Commit Graph

6 Commits

Author SHA1 Message Date
Josh Story e0966df114 test: migrate caching deploy exclusions to force gates (#98154)
## Summary

- migrate Cache Components, PPR, prefetching, prerendering,
revalidation, and SSG deployment exclusions to `@force-gate`
- remove the corresponding `skipDeployment` options and `skipped`
control flow while preserving each suite's rationale

This keeps caching-related exclusions together so their deployed
semantics can be reviewed by the same owners.

## Verification

- verified on the combined top-of-stack tree with `pnpm typescript`
- compared ordinary-mode collection before and after: all 4,670 existing
test names matched
- collected all 510 affected files in deploy mode: 4,578 skipped tests,
zero failures

<!-- NEXT_JS_LLM -->
2026-09-09 08:25:36 -07:00
Janka Uryga d352f1740a [PPF] Only track runtime accesses when the promise is used (#97165)
Improves how we track accesses of runtime data in static prerenders
(which affects whether a page will use static or runtime shells).
Now, Instead of tracking it when the hanging promise is created, we'll
track it when `then/catch/finally` is called on the promise (which we
use as a signal for being used).

The promise tracking required some novel work, because:

- Using a proxy seems to cause `Promise.then` to show up in call stacks
(we've had issues with proxies throwing off React's IO tracking before,
i believe this is a similar problem)
- patching `then/catch/finally` on the promise directly doesn't work,
because `then` doesn't get called for native `await`

The only way of doing this that i've found is a custom `Promise`
subclass that tracks the access in its `then` implementation. This is
what `TrackedPromise` does.

To improve the debuggability, i've added some debug logs enabled by
`NEXT_PRIVATE_DEBUG_RUNTIME_DATA=1` to detect when a page is deopted to
runtime and what expression caused it.

---

This fixes a false deopt caused by `createServerPathnameForMetadata` -
when called on a route with fallback params, it would always track a
fallback params access even if no icons/og images that actually use it
exist. This meant that we'd never statically optimize any routes that
had fallback params. After this PR, we only track a runtime data access
if a metadata route that uses that params actually exists, in which case
the `pathname` promise gets awaited.
(as a future optimization, we should do the equivalent of vary params
tracking on metadata routes to know if the params are used at all. also,
the logic in `pathname.ts` is generally in need of cleanup)
2026-08-26 18:05:44 +02:00
Zack Tanner 85c3d20a91 [cache components]: move flag out of experimental (#85035)
This moves `experimental.cacheComponents` to a top level config. As part
of this, I disabled some tests in `build-output-prerender` that assert
on `cacheComponents` appearing in the experimental list. In a separate
PR, I'm going to show that Cache Components is enabled next to the
bundler info.

This also updates some docs pages to remove "experimental" language.
2025-10-18 14:13:44 -07:00
Josh Story c5dab31407 Ignore unhandledRejection events for promises that reject after a React render aborts (#83590)
Currently we only abort React renders that are prerendered so this
change in practice only affects prerendering. The intent is to not
report unhandledRejections that are downstream of an abort because the
signal these errors provide is very limited. If you do have unrelated
unhandled rejections they'll usually show up before aborting or in a
dynamic page render so even if they are incidentally supressed in the
prerender context you should still be able to observe them.

Arguably we should go further and never report unhandled rejections
because there are still valid patterns where you initiate work
prospectively and then abandon it by choosing a fork or by returning
early (i.e. notFound()). This change doesn't attempt to cover every
possible case.

The implementation is a bit intense. We need the ability to stop
propagating the event which is not natively supported with Node's
EventEmitter interface. Instead we patch the listener methods to
delegate the filtering to an inner listener queue. If you add/remove or
otherwise manipulate the listener list we always ensure our listener is
first and can opt to omit propagating the event. If you want to
uninstall the this patch you just need to unregister this listener
specifically which can be accessing used
`process.listeners('unhandledRejection')[0]`

This patch only exists for the node environment because we do not do any
prerendering in edge runtimes. In the future if we add aborting to
environments like edge runtime we may need an alternative solution to
this problem
2025-09-09 20:46:31 -07:00
Josh Story ed5d085fb1 [Cache Components] Error for Sync IO in Server Components during Static Prerender (#82500)
Currently we error if you cannot produce a shell unless you have a
Suspense boundary above the root. This is fine for normal IO but sync IO
like Math.random() and new Date() have much more significant bad
consequences for prerendering. Instead of treating these errors as
another flavor of "must have a shell" validation we should instead treat
them like they must be guarded behind something else dynamic like `await
connection()`.

In addition to unconditionally erroring for Sync IO in Server Components
when prerendering this change also removes the Sync IO warning for
runtime prefetches. This is because at the moment there is no way to
debug these errors in dev. In the future we will add validation for
prefetches and need to add back in some ability to warn for these cases
but until then we will leave this case as a silent deopt.
2025-08-20 15:23:31 +00:00
Wyatt Johnson 8abbb3dc2e refactor: rename experimental.dynamicIO to experimental.cacheComponents (#81562)
## What?

Rename `experimental.dynamicIO` to `experimental.cacheComponents` across
the Next.js codebase.

## Why?

We're going to be merging the functionality of the `ppr`, `dynamicIO`
and `useCache` experimental flags into the singular `cacheComponents`
flag to reduce complexity of the codebase and simplify adoption for
users wanting to experiment with experimental features.

## How?

- Renamed the configuration option from `experimental.dynamicIO` to
`experimental.cacheComponents`
- Added deprecation handling with automatic migration for the old option
name
- Updated all documentation, tests, and internal references
- Updated Rust code in SWC transforms and Turbopack
- Maintained backward compatibility with deprecation warnings

NAR-158
2025-07-17 19:30:28 -06:00