Skip to content

Commit 3e71235

Browse files
committed
Fix cache keys for dev warmup
1 parent dbf55a4 commit 3e71235

File tree

6 files changed

+34
-10
lines changed

6 files changed

+34
-10
lines changed

packages/next/src/client/components/app-router-headers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const NEXT_ROUTER_PREFETCH_HEADER = 'Next-Router-Prefetch' as const
1212
export const NEXT_ROUTER_SEGMENT_PREFETCH_HEADER =
1313
'Next-Router-Segment-Prefetch' as const
1414
export const NEXT_HMR_REFRESH_HEADER = 'Next-HMR-Refresh' as const
15+
export const NEXT_HMR_REFRESH_HASH_COOKIE = '__next_hmr_refresh_hash__' as const
1516
export const NEXT_URL = 'Next-Url' as const
1617
export const RSC_CONTENT_TYPE_HEADER = 'text/x-component' as const
1718

packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import type { GlobalErrorComponent } from '../../error-boundary'
4646
import type { DevIndicatorServerState } from '../../../../server/dev/dev-indicator-server-state'
4747
import reportHmrLatency from '../utils/report-hmr-latency'
4848
import { TurbopackHmr } from '../utils/turbopack-hot-reloader-common'
49+
import { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../app-router-headers'
4950

5051
export interface Dispatcher {
5152
onBuildOk(): void
@@ -412,7 +413,7 @@ function processMessage(
412413

413414
// Store the latest hash in a session cookie so that it's sent back to the
414415
// server with any subsequent requests.
415-
document.cookie = `__next_hmr_refresh_hash__=${obj.hash}`
416+
document.cookie = `${NEXT_HMR_REFRESH_HASH_COOKIE}=${obj.hash}`
416417

417418
if (RuntimeErrorHandler.hadRuntimeError) {
418419
if (reloading) return

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

+18
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import {
5353
NEXT_URL,
5454
RSC_HEADER,
5555
NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,
56+
NEXT_HMR_REFRESH_HASH_COOKIE,
5657
} from '../../client/components/app-router-headers'
5758
import {
5859
createTrackedMetadataContext,
@@ -725,6 +726,7 @@ async function warmupDevRender(
725726
stale: INFINITE_CACHE,
726727
tags: [],
727728
prerenderResumeDataCache,
729+
hmrRefreshHash: req.cookies[NEXT_HMR_REFRESH_HASH_COOKIE],
728730
}
729731

730732
const rscPayload = await workUnitAsyncStorage.run(
@@ -2221,6 +2223,10 @@ async function spawnDynamicValidationInDev(
22212223
ctx.getDynamicParamFromSegment
22222224
)
22232225

2226+
const hmrRefreshHash = requestStore.cookies.get(
2227+
NEXT_HMR_REFRESH_HASH_COOKIE
2228+
)?.value
2229+
22242230
// Prerender controller represents the lifetime of the prerender.
22252231
// It will be aborted when a Task is complete or a synchronously aborting
22262232
// API is called. Notably during cache-filling renders this does not actually
@@ -2248,6 +2254,7 @@ async function spawnDynamicValidationInDev(
22482254
stale: INFINITE_CACHE,
22492255
tags: [],
22502256
prerenderResumeDataCache,
2257+
hmrRefreshHash,
22512258
}
22522259

22532260
const initialClientController = new AbortController()
@@ -2265,6 +2272,7 @@ async function spawnDynamicValidationInDev(
22652272
stale: INFINITE_CACHE,
22662273
tags: [],
22672274
prerenderResumeDataCache,
2275+
hmrRefreshHash,
22682276
}
22692277

22702278
// We're not going to use the result of this render because the only time it could be used
@@ -2412,6 +2420,7 @@ async function spawnDynamicValidationInDev(
24122420
stale: INFINITE_CACHE,
24132421
tags: [],
24142422
prerenderResumeDataCache,
2423+
hmrRefreshHash,
24152424
}
24162425

24172426
const finalClientController = new AbortController()
@@ -2433,6 +2442,7 @@ async function spawnDynamicValidationInDev(
24332442
stale: INFINITE_CACHE,
24342443
tags: [],
24352444
prerenderResumeDataCache,
2445+
hmrRefreshHash,
24362446
}
24372447

24382448
const finalServerPayload = await workUnitAsyncStorage.run(
@@ -2759,6 +2769,7 @@ async function prerenderToStream(
27592769
stale: INFINITE_CACHE,
27602770
tags: [...implicitTags.tags],
27612771
prerenderResumeDataCache,
2772+
hmrRefreshHash: undefined,
27622773
})
27632774

27642775
// We're not going to use the result of this render because the only time it could be used
@@ -2853,6 +2864,7 @@ async function prerenderToStream(
28532864
stale: INFINITE_CACHE,
28542865
tags: [...implicitTags.tags],
28552866
prerenderResumeDataCache,
2867+
hmrRefreshHash: undefined,
28562868
}
28572869

28582870
const prerender = require('react-dom/static.edge')
@@ -2939,6 +2951,7 @@ async function prerenderToStream(
29392951
stale: INFINITE_CACHE,
29402952
tags: [...implicitTags.tags],
29412953
prerenderResumeDataCache,
2954+
hmrRefreshHash: undefined,
29422955
})
29432956

29442957
const finalAttemptRSCPayload = await workUnitAsyncStorage.run(
@@ -3008,6 +3021,7 @@ async function prerenderToStream(
30083021
stale: INFINITE_CACHE,
30093022
tags: [...implicitTags.tags],
30103023
prerenderResumeDataCache,
3024+
hmrRefreshHash: undefined,
30113025
}
30123026

30133027
let clientIsDynamic = false
@@ -3242,6 +3256,7 @@ async function prerenderToStream(
32423256
stale: INFINITE_CACHE,
32433257
tags: [...implicitTags.tags],
32443258
prerenderResumeDataCache,
3259+
hmrRefreshHash: undefined,
32453260
})
32463261

32473262
const initialClientController = new AbortController()
@@ -3259,6 +3274,7 @@ async function prerenderToStream(
32593274
stale: INFINITE_CACHE,
32603275
tags: [...implicitTags.tags],
32613276
prerenderResumeDataCache,
3277+
hmrRefreshHash: undefined,
32623278
})
32633279

32643280
// We're not going to use the result of this render because the only time it could be used
@@ -3412,6 +3428,7 @@ async function prerenderToStream(
34123428
stale: INFINITE_CACHE,
34133429
tags: [...implicitTags.tags],
34143430
prerenderResumeDataCache,
3431+
hmrRefreshHash: undefined,
34153432
})
34163433

34173434
let clientIsDynamic = false
@@ -3436,6 +3453,7 @@ async function prerenderToStream(
34363453
stale: INFINITE_CACHE,
34373454
tags: [...implicitTags.tags],
34383455
prerenderResumeDataCache,
3456+
hmrRefreshHash: undefined,
34393457
})
34403458

34413459
const finalServerPayload = await workUnitAsyncStorage.run(

packages/next/src/server/app-render/work-unit-async-storage.external.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
import type { Params } from '../request/params'
1717
import type { ImplicitTags } from '../lib/implicit-tags'
1818
import type { WorkStore } from './work-async-storage.external'
19+
import { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../client/components/app-router-headers'
1920

2021
export type WorkUnitPhase = 'action' | 'render' | 'after'
2122

@@ -121,6 +122,13 @@ export interface PrerenderStoreModern extends CommonWorkUnitStore {
121122
// not part of the primary render path and are just prerendering to produce
122123
// validation results
123124
validating?: boolean
125+
126+
/**
127+
* The HMR refresh hash is only provided in dev mode. It is needed for the dev
128+
* warmup render to ensure that the cache keys will be identical for the
129+
* subsequent dynamic render.
130+
*/
131+
readonly hmrRefreshHash: string | undefined
124132
}
125133

126134
export interface PrerenderStorePPR extends CommonWorkUnitStore {
@@ -276,10 +284,10 @@ export function getHmrRefreshHash(
276284
return undefined
277285
}
278286

279-
return workUnitStore.type === 'cache'
287+
return workUnitStore.type === 'cache' || workUnitStore.type === 'prerender'
280288
? workUnitStore.hmrRefreshHash
281289
: workUnitStore.type === 'request'
282-
? workUnitStore.cookies.get('__next_hmr_refresh_hash__')?.value
290+
? workUnitStore.cookies.get(NEXT_HMR_REFRESH_HASH_COOKIE)?.value
283291
: undefined
284292
}
285293

packages/next/src/server/route-modules/app-route/module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ export class AppRouteRouteModule extends RouteModule<
393393
stale: INFINITE_CACHE,
394394
tags: [...implicitTags.tags],
395395
prerenderResumeDataCache: null,
396+
hmrRefreshHash: undefined,
396397
})
397398

398399
let prospectiveResult
@@ -478,6 +479,7 @@ export class AppRouteRouteModule extends RouteModule<
478479
stale: INFINITE_CACHE,
479480
tags: [...implicitTags.tags],
480481
prerenderResumeDataCache: null,
482+
hmrRefreshHash: undefined,
481483
})
482484

483485
let responseHandled = false

test/development/app-dir/dynamic-io-dev-warmup/dynamic-io.dev-warmup.test.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,7 @@ describe('dynamic-io-dev-warmup', () => {
2020
}
2121

2222
it('logs with Prerender or Server environment depending based on whether the timing of when the log runs relative to this environment boundary', async () => {
23-
let browser = await next.browser('/')
24-
// At the moment this second render is required for the logs to resolves in the expected environment
25-
// This doesn't reproduce locally but I suspect some kind of lazy initialization during dev that leads the initial render
26-
// to not resolve in a microtask on the first render.
27-
await browser.close()
28-
browser = await next.browser('/')
29-
23+
const browser = await next.browser('/')
3024
const logs = await browser.log()
3125

3226
assertLog(logs, 'after layout cache read', 'Prerender')

0 commit comments

Comments
 (0)