mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
576d3a3397
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.
37 lines
1.2 KiB
TypeScript
37 lines
1.2 KiB
TypeScript
import { Suspense } from 'react'
|
|
import { setTimeout } from 'timers/promises'
|
|
|
|
async function getCachedValue(slug: string) {
|
|
'use cache'
|
|
|
|
// A slow generation, so the cold read is clearly pending at a staged-render
|
|
// boundary (which surfaces the cold cache indicator on the first load), and a
|
|
// warm reload served from the front is observably different. 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>
|
|
}
|
|
|
|
// We use a distinct slug per test, so each test exercises its own cache entry and no
|
|
// cache hits are shared across tests (the first request for a slug is a genuine
|
|
// cold miss).
|
|
// 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.
|
|
export async function PageForSlug({ slug }: { slug: string }) {
|
|
return (
|
|
<main>
|
|
<Suspense fallback={<p id="loading">Loading...</p>}>
|
|
<CachedValue slug={slug} />
|
|
</Suspense>
|
|
</main>
|
|
)
|
|
}
|