Skip to content

Commit d643bf4

Browse files
committed
Fix dev warmup after revalidation
1 parent 3100ce3 commit d643bf4

File tree

6 files changed

+119
-59
lines changed

6 files changed

+119
-59
lines changed

packages/next/src/server/app-render/app-render.tsx

+71-50
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ export type AppRenderContext = {
227227
isNotFoundPath: boolean
228228
nonce: string | undefined
229229
res: BaseNextResponse
230+
/**
231+
* For now, the implicit tags are common for the whole route. If we ever start
232+
* rendering/revalidating segments independently, they need to move to the
233+
* work unit store.
234+
*/
235+
implicitTags: ImplicitTags
230236
}
231237

232238
interface ParseRequestHeadersOptions {
@@ -680,16 +686,24 @@ async function warmupDevRender(
680686
req: BaseNextRequest,
681687
ctx: AppRenderContext
682688
): Promise<RenderResult> {
683-
const renderOpts = ctx.renderOpts
689+
const {
690+
clientReferenceManifest,
691+
componentMod,
692+
getDynamicParamFromSegment,
693+
implicitTags,
694+
renderOpts,
695+
workStore,
696+
} = ctx
697+
684698
if (!renderOpts.dev) {
685699
throw new InvariantError(
686700
'generateDynamicFlightRenderResult should never be called in `next start` mode.'
687701
)
688702
}
689703

690704
const rootParams = getRootParams(
691-
ctx.componentMod.tree,
692-
ctx.getDynamicParamFromSegment
705+
componentMod.tree,
706+
getDynamicParamFromSegment
693707
)
694708

695709
function onFlightDataRenderError(err: DigestedError) {
@@ -716,7 +730,7 @@ async function warmupDevRender(
716730
type: 'prerender',
717731
phase: 'render',
718732
rootParams,
719-
implicitTags: undefined,
733+
implicitTags,
720734
renderSignal: renderController.signal,
721735
controller: prerenderController,
722736
cacheSignal,
@@ -739,9 +753,9 @@ async function warmupDevRender(
739753
// which contains the subset React.
740754
workUnitAsyncStorage.run(
741755
prerenderStore,
742-
ctx.componentMod.renderToReadableStream,
756+
componentMod.renderToReadableStream,
743757
rscPayload,
744-
ctx.clientReferenceManifest.clientModules,
758+
clientReferenceManifest.clientModules,
745759
{
746760
onError,
747761
signal: renderController.signal,
@@ -759,7 +773,7 @@ async function warmupDevRender(
759773
// that calls into renderToHTML... expects a result. We should refactor this to
760774
// lift the warmup pathway outside of renderToHTML... but for now this suffices
761775
return new FlightRenderResult('', {
762-
fetchMetrics: ctx.workStore.fetchMetrics,
776+
fetchMetrics: workStore.fetchMetrics,
763777
devRenderResumeDataCache: createRenderResumeDataCache(
764778
prerenderResumeDataCache
765779
),
@@ -1343,6 +1357,12 @@ async function renderToHTMLOrFlightImpl(
13431357

13441358
const isActionRequest = getServerActionRequestMetadata(req).isServerAction
13451359

1360+
const implicitTags = await getImplicitTags(
1361+
workStore.page,
1362+
url,
1363+
fallbackRouteParams
1364+
)
1365+
13461366
const ctx: AppRenderContext = {
13471367
componentMod: ComponentMod,
13481368
url,
@@ -1364,16 +1384,11 @@ async function renderToHTMLOrFlightImpl(
13641384
nonce,
13651385
res,
13661386
sharedContext,
1387+
implicitTags,
13671388
}
13681389

13691390
getTracer().setRootSpanAttribute('next.route', pagePath)
13701391

1371-
const implicitTags = await getImplicitTags(
1372-
workStore.page,
1373-
url,
1374-
fallbackRouteParams
1375-
)
1376-
13771392
if (isStaticGeneration) {
13781393
// We're either building or revalidating. In either case we need to
13791394
// prerender our page rather than render it.
@@ -1394,8 +1409,7 @@ async function renderToHTMLOrFlightImpl(
13941409
ctx,
13951410
metadata,
13961411
workStore,
1397-
loaderTree,
1398-
implicitTags
1412+
loaderTree
13991413
)
14001414

14011415
// If we're debugging partial prerendering, print all the dynamic API accesses
@@ -2217,7 +2231,7 @@ async function spawnDynamicValidationInDev(
22172231
route: string,
22182232
requestStore: RequestStore
22192233
): Promise<void> {
2220-
const { componentMod: ComponentMod } = ctx
2234+
const { componentMod: ComponentMod, implicitTags } = ctx
22212235
const rootParams = getRootParams(
22222236
ComponentMod.tree,
22232237
ctx.getDynamicParamFromSegment
@@ -2244,7 +2258,7 @@ async function spawnDynamicValidationInDev(
22442258
type: 'prerender',
22452259
phase: 'render',
22462260
rootParams,
2247-
implicitTags: undefined,
2261+
implicitTags,
22482262
renderSignal: initialServerRenderController.signal,
22492263
controller: initialServerPrerenderController,
22502264
cacheSignal,
@@ -2262,7 +2276,7 @@ async function spawnDynamicValidationInDev(
22622276
type: 'prerender',
22632277
phase: 'render',
22642278
rootParams,
2265-
implicitTags: undefined,
2279+
implicitTags,
22662280
renderSignal: initialClientController.signal,
22672281
controller: initialClientController,
22682282
cacheSignal,
@@ -2409,7 +2423,7 @@ async function spawnDynamicValidationInDev(
24092423
type: 'prerender',
24102424
phase: 'render',
24112425
rootParams,
2412-
implicitTags: undefined,
2426+
implicitTags,
24132427
renderSignal: finalServerController.signal,
24142428
controller: finalServerController,
24152429
// During the final prerender we don't need to track cache access so we omit the signal
@@ -2431,7 +2445,7 @@ async function spawnDynamicValidationInDev(
24312445
type: 'prerender',
24322446
phase: 'render',
24332447
rootParams,
2434-
implicitTags: undefined,
2448+
implicitTags,
24352449
renderSignal: finalClientController.signal,
24362450
controller: finalClientController,
24372451
// During the final prerender we don't need to track cache access so we omit the signal
@@ -2602,16 +2616,23 @@ async function prerenderToStream(
26022616
ctx: AppRenderContext,
26032617
metadata: AppPageRenderResultMetadata,
26042618
workStore: WorkStore,
2605-
tree: LoaderTree,
2606-
implicitTags: ImplicitTags
2619+
tree: LoaderTree
26072620
): Promise<PrerenderToStreamResult> {
26082621
// When prerendering formState is always null. We still include it
26092622
// because some shared APIs expect a formState value and this is slightly
26102623
// more explicit than making it an optional function argument
26112624
const formState = null
2612-
const rootParams = getRootParams(tree, ctx.getDynamicParamFromSegment)
26132625

2614-
const renderOpts = ctx.renderOpts
2626+
const {
2627+
assetPrefix,
2628+
getDynamicParamFromSegment,
2629+
implicitTags,
2630+
nonce,
2631+
pagePath,
2632+
renderOpts,
2633+
} = ctx
2634+
2635+
const rootParams = getRootParams(tree, getDynamicParamFromSegment)
26152636
const ComponentMod = renderOpts.ComponentMod
26162637
// TODO: fix this typescript
26172638
const clientReferenceManifest = renderOpts.clientReferenceManifest!
@@ -2620,7 +2641,7 @@ async function prerenderToStream(
26202641
const { ServerInsertedHTMLProvider, renderServerInsertedHTML } =
26212642
createServerInsertedHTML()
26222643
const { ServerInsertedMetadataProvider, getServerInsertedMetadata } =
2623-
createServerInsertedMetadata(ctx.nonce)
2644+
createServerInsertedMetadata(nonce)
26242645

26252646
const tracingMetadata = getTracedMetadata(
26262647
getTracer().getTracePropagationData(),
@@ -2634,25 +2655,25 @@ async function prerenderToStream(
26342655
polyfill.endsWith('.js') && !polyfill.endsWith('.module.js')
26352656
)
26362657
.map((polyfill) => ({
2637-
src: `${ctx.assetPrefix}/_next/${polyfill}${getAssetQueryString(
2658+
src: `${assetPrefix}/_next/${polyfill}${getAssetQueryString(
26382659
ctx,
26392660
false
26402661
)}`,
26412662
integrity: renderOpts.subresourceIntegrityManifest?.[polyfill],
26422663
crossOrigin: renderOpts.crossOrigin,
26432664
noModule: true,
2644-
nonce: ctx.nonce,
2665+
nonce: nonce,
26452666
}))
26462667

26472668
const [preinitScripts, bootstrapScript] = getRequiredScripts(
26482669
renderOpts.buildManifest,
26492670
// Why is assetPrefix optional on renderOpts?
26502671
// @TODO make it default empty string on renderOpts and get rid of it from ctx
2651-
ctx.assetPrefix,
2672+
assetPrefix,
26522673
renderOpts.crossOrigin,
26532674
renderOpts.subresourceIntegrityManifest,
26542675
getAssetQueryString(ctx, true),
2655-
ctx.nonce,
2676+
nonce,
26562677
renderOpts.page
26572678
)
26582679

@@ -2882,7 +2903,7 @@ async function prerenderToStream(
28822903
ServerInsertedMetadataProvider={
28832904
ServerInsertedMetadataProvider
28842905
}
2885-
nonce={ctx.nonce}
2906+
nonce={nonce}
28862907
/>,
28872908
{
28882909
signal: initialClientController.signal,
@@ -3040,7 +3061,7 @@ async function prerenderToStream(
30403061
clientReferenceManifest={clientReferenceManifest}
30413062
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
30423063
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3043-
nonce={ctx.nonce}
3064+
nonce={nonce}
30443065
/>,
30453066
{
30463067
signal: finalClientController.signal,
@@ -3165,13 +3186,13 @@ async function prerenderToStream(
31653186
clientReferenceManifest={clientReferenceManifest}
31663187
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
31673188
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3168-
nonce={ctx.nonce}
3189+
nonce={nonce}
31693190
/>,
31703191
JSON.parse(JSON.stringify(postponed)),
31713192
{
31723193
signal: createPostponedAbortSignal('static prerender resume'),
31733194
onError: htmlRendererErrorHandler,
3174-
nonce: ctx.nonce,
3195+
nonce,
31753196
}
31763197
)
31773198

@@ -3185,7 +3206,7 @@ async function prerenderToStream(
31853206
stream: await continueStaticPrerender(htmlStream, {
31863207
inlinedDataStream: createInlinedDataReadableStream(
31873208
reactServerResult.consumeAsStream(),
3188-
ctx.nonce,
3209+
nonce,
31893210
formState
31903211
),
31913212
getServerInsertedHTML,
@@ -3356,7 +3377,7 @@ async function prerenderToStream(
33563377
clientReferenceManifest={clientReferenceManifest}
33573378
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
33583379
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3359-
nonce={ctx.nonce}
3380+
nonce={nonce}
33603381
/>,
33613382
{
33623383
signal: initialClientController.signal,
@@ -3511,7 +3532,7 @@ async function prerenderToStream(
35113532
ServerInsertedMetadataProvider={
35123533
ServerInsertedMetadataProvider
35133534
}
3514-
nonce={ctx.nonce}
3535+
nonce={nonce}
35153536
/>,
35163537
{
35173538
signal: finalClientController.signal,
@@ -3608,7 +3629,7 @@ async function prerenderToStream(
36083629
stream: await continueFizzStream(htmlStream!, {
36093630
inlinedDataStream: createInlinedDataReadableStream(
36103631
serverPrerenderStreamResult.asStream(),
3611-
ctx.nonce,
3632+
nonce,
36123633
formState
36133634
),
36143635
isStaticGeneration: true,
@@ -3690,7 +3711,7 @@ async function prerenderToStream(
36903711
clientReferenceManifest={clientReferenceManifest}
36913712
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
36923713
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3693-
nonce={ctx.nonce}
3714+
nonce={nonce}
36943715
/>,
36953716
{
36963717
onError: htmlRendererErrorHandler,
@@ -3822,13 +3843,13 @@ async function prerenderToStream(
38223843
clientReferenceManifest={clientReferenceManifest}
38233844
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
38243845
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3825-
nonce={ctx.nonce}
3846+
nonce={nonce}
38263847
/>,
38273848
JSON.parse(JSON.stringify(postponed)),
38283849
{
38293850
signal: createPostponedAbortSignal('static prerender resume'),
38303851
onError: htmlRendererErrorHandler,
3831-
nonce: ctx.nonce,
3852+
nonce,
38323853
}
38333854
)
38343855

@@ -3842,7 +3863,7 @@ async function prerenderToStream(
38423863
stream: await continueStaticPrerender(htmlStream, {
38433864
inlinedDataStream: createInlinedDataReadableStream(
38443865
reactServerResult.consumeAsStream(),
3845-
ctx.nonce,
3866+
nonce,
38463867
formState
38473868
),
38483869
getServerInsertedHTML,
@@ -3901,11 +3922,11 @@ async function prerenderToStream(
39013922
clientReferenceManifest={clientReferenceManifest}
39023923
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
39033924
ServerInsertedMetadataProvider={ServerInsertedMetadataProvider}
3904-
nonce={ctx.nonce}
3925+
nonce={nonce}
39053926
/>,
39063927
{
39073928
onError: htmlRendererErrorHandler,
3908-
nonce: ctx.nonce,
3929+
nonce,
39093930
bootstrapScripts: [bootstrapScript],
39103931
}
39113932
)
@@ -3935,7 +3956,7 @@ async function prerenderToStream(
39353956
stream: await continueFizzStream(htmlStream, {
39363957
inlinedDataStream: createInlinedDataReadableStream(
39373958
reactServerResult.consumeAsStream(),
3938-
ctx.nonce,
3959+
nonce,
39393960
formState
39403961
),
39413962
isStaticGeneration: true,
@@ -3976,7 +3997,7 @@ async function prerenderToStream(
39763997
if (shouldBailoutToCSR) {
39773998
const stack = getStackWithoutErrorMessage(err)
39783999
error(
3979-
`${err.reason} should be wrapped in a suspense boundary at page "${ctx.pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`
4000+
`${err.reason} should be wrapped in a suspense boundary at page "${pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`
39804001
)
39814002

39824003
throw err
@@ -4009,11 +4030,11 @@ async function prerenderToStream(
40094030

40104031
const [errorPreinitScripts, errorBootstrapScript] = getRequiredScripts(
40114032
renderOpts.buildManifest,
4012-
ctx.assetPrefix,
4033+
assetPrefix,
40134034
renderOpts.crossOrigin,
40144035
renderOpts.subresourceIntegrityManifest,
40154036
getAssetQueryString(ctx, false),
4016-
ctx.nonce,
4037+
nonce,
40174038
'/_not-found/page'
40184039
)
40194040

@@ -4065,11 +4086,11 @@ async function prerenderToStream(
40654086
ServerInsertedHTMLProvider={ServerInsertedHTMLProvider}
40664087
preinitScripts={errorPreinitScripts}
40674088
clientReferenceManifest={clientReferenceManifest}
4068-
nonce={ctx.nonce}
4089+
nonce={nonce}
40694090
/>
40704091
),
40714092
streamOptions: {
4072-
nonce: ctx.nonce,
4093+
nonce,
40734094
// Include hydration scripts in the HTML
40744095
bootstrapScripts: [errorBootstrapScript],
40754096
formState,
@@ -4107,7 +4128,7 @@ async function prerenderToStream(
41074128
stream: await continueFizzStream(fizzStream, {
41084129
inlinedDataStream: createInlinedDataReadableStream(
41094130
flightStream,
4110-
ctx.nonce,
4131+
nonce,
41114132
formState
41124133
),
41134134
isStaticGeneration: true,

0 commit comments

Comments
 (0)