Files
Janka UrygaandGitHub 576d3a3397 [PP] Instant validation - error for unguarded static params (#94595)
Follow-up to #95151, implementing support for validating awaits of
static params (i.e. when using `generateStaticParams`)

An app shell cannot contain any link data. This poses a challenge when
we're trying to re-use the dev render for instant validation, because we
have to make a choice:
1. either we resolve static params (from `generateStaticParams`) in the
`Static` stage, and get an accurate *static HTML shell* (used for the
initial navigation), but an incorrect app shell
2. or we resolve them in the `ShellRuntime` stage and we get an accurate
App Shell, but cannot validate a static HTML shell (which would contain
static params)

We'll use order 2 in the main render whenever client-navigating to a
page with `partialPrefetching` enabled. We still need a render with
order 1 for Static Shell Validation, so we perform a second, partial
render that aborts before the dynamic stage (because only instant
navigation needs the dynamic stage). As an optimization, we can skip the
secondary render if the page doesn't have static params, because in that
case the two orders are equivalent.

If we're performing an initial load, we'll use order 1 (to reflect the
HTML shell). in this case, we'll do a full secondary render with order
2. Same as above, we can skip the secondary render if there's no static
params.

---

Where params resolve (order 1 vs order 2) is controlled by
`requestStore.needsSessionShell`. We then end up with two sets of
"validation inputs" (mainly rendered chunks) that we can feed into
static and instant validation respectively.

Also note that this PR doesn't touch `environmentName`, because that
required changing too many tests. This will be addressed in a follow-up.
2026-07-01 04:59:43 +00:00

34 lines
1.0 KiB
TypeScript

import { Suspense } from 'react'
import { setTimeout } from 'timers/promises'
async function getCachedValue(slug: string) {
'use cache'
// A slow generation, so a warm reload that serves the cached entry is
// observably faster than a cold load that has to generate, and so a cold read
// is still pending at a staged-render boundary (which surfaces the cold cache
// indicator). The slug keys the entry; the value itself is just a timestamp.
await setTimeout(1000)
return new Date().toISOString()
}
async function CachedValue({ slug }: { slug: string }) {
const value = await getCachedValue(slug)
return <p id="value">{value}</p>
}
export async function PageForSlug({ slug }: { slug: string }) {
// NOTE: we're not using generateStaticParams because
// those resolve after the shell in `partialPrefetching`,
// and the test needs the cache to be part of the shell
return (
<main>
<Suspense fallback={<p id="loading">Loading...</p>}>
<CachedValue slug={slug} />
</Suspense>
</main>
)
}