Files
Hendrik LiebauandGitHub e59eb73bbc Compute dev fallback params from the most-specific prerendered route (#95066)
When Cache Components is enabled, the development server threads a
`fallbackParams` request meta for dynamic app routes so the staged
render knows which params are not statically known and must be deferred
to a later stage. The previous computation walked the prerendered routes
from `getStaticPaths` and kept the one with the fewest fallback params,
without checking that the route actually matched the requested URL.
Consider `/mixed/[lang]/[id]` where `generateStaticParams` covers `lang:
'en'` but not `id`: the prerendered routes are the base
`/mixed/[lang]/[id]`, which defers `[lang, id]`, and the covered
`/mixed/en/[id]`, which defers only `[id]`. For the request
`/mixed/fr/123` the fewest-fallback route is `/mixed/en/[id]`, but `en`
does not match `fr`, so applying its `[id]` set left `lang` out of the
fallback set and `fr` was treated as a statically known value.

Because this meta decides which stage each param resolves in, and the
stage decides the environment a replayed `console.log` is attributed to,
treating `fr` as static resolved it in the prerender stage instead of
deferring it to the runtime stage. The computation now matches the
requested URL against each prerendered route with the canonical
`getRouteRegex` and, among the routes that match, picks the
most-specific one, the one with the fewest fallback params. For
`/mixed/fr/123` only the base route matches, so its `[lang, id]` set is
used and both params defer, while for `/mixed/en/123` the covered
`/mixed/en/[id]` still matches and wins, so `lang` resolves statically
and only `id` defers. This mirrors what a production build writes to the
prerender manifest, where the server matches the URL to the
most-specific prerendered route at request time. The change is
development-only, gated on the route module being in dev mode, and
production continues to read the manifest. A later change in this stack
reads the same `fallbackParams` meta for the Instant Navigation testing
API's on-demand shell render, so that path defers the identical per-URL
set a production prefetch would.
2026-06-23 23:55:51 +02:00

44 lines
1.2 KiB
TypeScript

import {
CachedInnerTraceManualSpan,
InnerTraceManualSpan,
CachedTracedComponentManualSpan,
TracedComponentManualSpan,
CachedInnerTraceActiveSpan,
InnerTraceActiveSpan,
CachedTracedComponentActiveSpan,
TracedComponentActiveSpan,
} from '../../traced-work'
// A navigation to an uncovered slug reads a deferred `params`, which is a
// blocking navigation. This suite exercises span creation during cache
// component validation, not Instant Navigation, so opt the route out of that
// validation: otherwise its blocking-route insight masks the `startActiveSpan`
// console error these tests assert.
export const instant = false
export function generateStaticParams() {
return [{ slug: 'prerendered' }]
}
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
'use cache'
return (
<>
<h1>{(await params).slug}</h1>
<div>We are inside a "use cache" scope</div>
<CachedInnerTraceManualSpan />
<InnerTraceManualSpan />
<CachedTracedComponentManualSpan />
<TracedComponentManualSpan />
<CachedInnerTraceActiveSpan />
<InnerTraceActiveSpan />
<CachedTracedComponentActiveSpan />
<TracedComponentActiveSpan />
</>
)
}