## 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 -->
## Summary
`experimental.ppr` is deprecated, and Cache Components is now the only
internal path that enables partial prerendering. This makes the legacy
PPR renderer and its `prerender-ppr` work unit unreachable.
This removes that rendering path, the associated work-unit branches,
Next.js’s remaining integration with React’s deprecated
`unstable_postpone` API, the dead `__NEXT_PPR` client flag, and obsolete
legacy PPR tests.
Cache Components’ postponed-state and resume behavior remain unchanged.
<!-- NEXT_JS_LLM -->
This reverts commit a85d888a77.
PR #88243 introduced deploy test regressions in the following test
suites:
-
`test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts`
- `test/e2e/app-dir/segment-cache/client-params/client-params.test.ts`
### What?
Removes the `experimental.ppr` configuration flag and consolidates
Partial Prerendering (PPR) functionality into the `cacheComponents`
architecture.
### Why?
Having two separate systems (PPR flag and cacheComponents) created dual
code paths and complexity. PPR is now implicitly enabled when
cacheComponents is enabled, simplifying the codebase.
### How?
- Deleted `postpone.ts` and `ppr.ts` utility files
- Removed `PrerenderStorePPR` work unit type and all PPR-specific work
unit cases
- Removed React.unstable_postpone-based dynamic rendering logic
- Deprecated `experimental.ppr` config (kept for backwards
compatibility)
- Simplified build system to check only `cacheComponents` flag
- Updated tests to remove PPR-specific behavior expectations
This removes ~986 lines of code across 48 files.
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.
This hard deprecates the `experimental.ppr` configuration, requiring
users to opt-in instead via `experimental.cacheComponents`. This does
mean that the previous `experimental.ppr = "incremental"` will no longer
be supported.
NAR-433
This work introduces the new concept of **Partial Fallback Prerendering
(PFPR)**.
Traditionally, when a dynamic page needed to be routed to that wasn't
pregenerated, it required a render to generate even the first few bytes
of the static page itself. This resulted in slow page loads for pages
not frequently visited and a reduced Time to First Byte (TTFB) score on
Core Web Vitals (CWV).
PFPR takes advantage of the new systems of Partial Prerendering (PPR)
that allows the application to suspend at different points mid-render,
and resume it later. We mark any unknown parameter access as dynamic
access, and suspend the rendering up to the next suspense boundaries at
those points. Under ideal conditions (correctly placed `<Suspense />`
boundaries or `loading.jsx` files) this generates a static shell that
can be served to users as soon as the request hits Next.js, right out of
the static cache. This minimizes the TTFB for all requests, dynamic or
not for those pages that enable PPR. For example, the following page
would create a usable shell:
```jsx
// /app/users/[userID]/page.jsx
import { Suspense } from 'react'
function Profile({ params }) {
const { userID } = params
return <div>Hello {userID}!</div>
}
export default function ProfilePage({ params }) {
return (
<div>
<h1>User Profile</h1>
<Suspense fallback="Loading...">
<Profile params={params} />
</Suspense>
</div>
)
}
```
Due to the way that suspense works within React components, access of
params within the root page component would cause the whole page to
suspend. Thankfully, that's where the `loading.jsx` comes in handy.
Adding a `loading.jsx` at a segment will automatically wrap the
`page.jsx` with a suspense boundary, setting the contents of the root
`loading.jsx` as the fallback component to use for it. This lets you
maintain your existing style of accessing parameters at the root of the
components while also taking advantage of PFPR.
To enable this feature, you first need to enable both PPR and PFPR:
```js
module.exports = {
experimental: {
ppr: true,
pprFallbacks: true,
}
}
```
Once PFPR has stabilized with hosting providers, the experimental flag
will go away and it will become the default with the PPR flag.
Users that experiment with PPR and might have seen #61798, or #62703, or
most recently #65483, may try the `__nextppronly=1` query param to debug
the static shell. This will lead to the following uncaught error and
blank page:
<img width="1045" alt="static shell debugging hydration error"
src="https://github.com/vercel/next.js/assets/761683/ed382d97-82ae-4a23-9930-bb4d4419e88e">
It might not be immediately obvious that javascript must be disabled to
see the static shell. To improve the DX in this scenario we can omit the
bootstrap script to skip hydration, and thus prevent the error. Then
debugging the static shell works even without disabling javascript in
the devtools.
<img width="1045" alt="static shell debugging without hydration"
src="https://github.com/vercel/next.js/assets/761683/57f6cb88-f5b4-473f-963f-7fda8c8e7f00">
In addition, we should add the closing body and html tags to the shell
so that a valid HTML document is returned.
This disables tests that should not be run in a deployed environment,
because they use incompatible APIs or there's no reason to test them
outside of `next start`. Specifically disables for things like:
- Using `next.patchFile`, `next.renameFile`, etc.
- Attempting to use `next.cliOutput` to query runtime logs. When
deployed, these are only build-time logs.
[Latest Run](https://github.com/vercel/next.js/actions/runs/9483807368)
To assist with the development and testing of the new partial
prerendering (PPR) paradigm, this introduces a stop-gap solution to let
us verify issues with pages in preview and production environments if
enabled. When a Next.js app is built and ran with the
`__NEXT_EXPERIMENTAL_STATIC_SHELL_DEBUGGING=1` environment variable,
pages that have PPR enabled in production and preview environments can
have only their static shell served when accessed with a
`?__nextppronly=1` query parameter.
If your project is not using PPR, it will not change anything. If a page
is accessed in production or development with the query parameter but
PPR is not enabled, it will not change anything. Tests have been added
to validate that going forward.