Skip to content

Commit 57a8d69

Browse files
committed
refactor types for dev-only RequestStore properties
1 parent 758a91a commit 57a8d69

File tree

3 files changed

+64
-26
lines changed

3 files changed

+64
-26
lines changed

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

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
type WorkStore,
1717
} from '../app-render/work-async-storage.external'
1818
import type {
19+
DevStoreModernPartial,
1920
PrerenderStoreModernRuntime,
2021
RequestStore,
2122
} from '../app-render/work-unit-async-storage.external'
@@ -2826,18 +2827,20 @@ async function renderWithRestartOnCacheMissInDev(
28262827
initialHangingPromiseController.signal
28272828
)
28282829

2829-
requestStore.prerenderResumeDataCache = prerenderResumeDataCache
28302830
// `getRenderResumeDataCache` will fall back to using `prerenderResumeDataCache` as `renderResumeDataCache`,
28312831
// so not having a resume data cache won't break any expectations in case we don't need to restart.
28322832
requestStore.renderResumeDataCache = null
2833-
requestStore.stagedRendering = initialStageController
2834-
requestStore.asyncApiPromises = createAsyncApiPromisesInDev(
2835-
initialStageController,
2836-
requestStore.cookies,
2837-
requestStore.mutableCookies,
2838-
requestStore.headers
2839-
)
2840-
requestStore.cacheSignal = cacheSignal
2833+
Object.assign(requestStore, {
2834+
stagedRendering: initialStageController,
2835+
asyncApiPromises: createAsyncApiPromisesInDev(
2836+
initialStageController,
2837+
requestStore.cookies,
2838+
requestStore.mutableCookies,
2839+
requestStore.headers
2840+
),
2841+
prerenderResumeDataCache,
2842+
cacheSignal,
2843+
} satisfies DevStoreModernPartial)
28412844

28422845
let debugChannel = setReactDebugChannel && createDebugChannel()
28432846

@@ -2938,18 +2941,20 @@ async function renderWithRestartOnCacheMissInDev(
29382941

29392942
// We've filled the caches, so now we can render as usual,
29402943
// without any cache-filling mechanics.
2941-
requestStore.prerenderResumeDataCache = null
29422944
requestStore.renderResumeDataCache = createRenderResumeDataCache(
29432945
prerenderResumeDataCache
29442946
)
2945-
requestStore.stagedRendering = finalStageController
2946-
requestStore.cacheSignal = null
2947-
requestStore.asyncApiPromises = createAsyncApiPromisesInDev(
2948-
finalStageController,
2949-
requestStore.cookies,
2950-
requestStore.mutableCookies,
2951-
requestStore.headers
2952-
)
2947+
Object.assign(requestStore, {
2948+
stagedRendering: finalStageController,
2949+
asyncApiPromises: createAsyncApiPromisesInDev(
2950+
finalStageController,
2951+
requestStore.cookies,
2952+
requestStore.mutableCookies,
2953+
requestStore.headers
2954+
),
2955+
prerenderResumeDataCache: null,
2956+
cacheSignal: null,
2957+
} satisfies DevStoreModernPartial)
29532958

29542959
// The initial render already wrote to its debug channel.
29552960
// We're not using it, so we need to create a new one.

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

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface CommonWorkUnitStore {
2929
readonly implicitTags: ImplicitTags
3030
}
3131

32-
export interface RequestStore extends CommonWorkUnitStore {
32+
interface BaseRequestStore extends CommonWorkUnitStore {
3333
readonly type: 'request'
3434

3535
/**
@@ -65,14 +65,46 @@ export interface RequestStore extends CommonWorkUnitStore {
6565
* The resume data cache for this request. This will be a immutable cache.
6666
*/
6767
renderResumeDataCache: RenderResumeDataCache | null
68+
}
69+
70+
export type RequestStore = ProdRequestStore | DevRequestStore
71+
72+
export type ProdRequestStore = BaseRequestStore & AllMissing<DevStore>
73+
export type DevRequestStore = BaseRequestStore & DevStore
6874

69-
// DEV-only
75+
// If `cacheComponents` is enabled, we add multiple extra properties on the store.
76+
// We either want all of them to be present, or all of them to be undefined.
77+
// Note that we don't want to remove the properties altogether, as in `{ a: A } | { a: A, b: B }`,
78+
// because then typescript wouldn prevent us from doing `if (requestStore.someProp) { ... }` --
79+
// we'd need to check `if ('someProp' in requestStore && requestStore.someProp) { ... }` instead,
80+
// which is annoying to write everywhere.
81+
type DevStore = DevStoreLegacy | DevStoreModern
82+
type DevStoreLegacy = DevStoreCommon & AllMissing<DevStoreModernPartial>
83+
type DevStoreModern = DevStoreCommon & DevStoreModernPartial
84+
85+
type DevStoreCommon = {
7086
usedDynamic?: boolean
7187
devFallbackParams?: OpaqueFallbackRouteParams | null
72-
stagedRendering?: StagedRenderingController | null
73-
asyncApiPromises?: DevAsyncApiPromises
74-
cacheSignal?: CacheSignal | null
75-
prerenderResumeDataCache?: PrerenderResumeDataCache | null
88+
}
89+
90+
export type DevStoreModernPartial = {
91+
readonly stagedRendering: StagedRenderingController
92+
readonly asyncApiPromises: DevAsyncApiPromises
93+
} & (
94+
| {
95+
// In the initial render, we track and fill caches
96+
readonly cacheSignal: CacheSignal
97+
readonly prerenderResumeDataCache: PrerenderResumeDataCache
98+
}
99+
| {
100+
// In the final (restarted) render, we do not track or fill caches
101+
readonly cacheSignal: null
102+
readonly prerenderResumeDataCache: null
103+
}
104+
)
105+
106+
type AllMissing<TObj extends Record<string, any>> = {
107+
[key in keyof TObj]?: undefined
76108
}
77109

78110
type DevAsyncApiPromises = {

packages/next/src/server/use-cache/use-cache-wrapper.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { prerender } from 'react-server-dom-webpack/static'
1717
import type { WorkStore } from '../app-render/work-async-storage.external'
1818
import { workAsyncStorage } from '../app-render/work-async-storage.external'
1919
import type {
20+
DevRequestStore,
2021
PrerenderStoreModernClient,
2122
PrerenderStoreModernRuntime,
2223
PrivateUseCacheStore,
@@ -1848,7 +1849,7 @@ function isRecentlyRevalidatedTag(tag: string, workStore: WorkStore): boolean {
18481849

18491850
async function delayBeforeCacheReadStartInDev(
18501851
stage: NonStaticRenderStage,
1851-
requestStore: RequestStore
1852+
requestStore: DevRequestStore
18521853
): Promise<void> {
18531854
const { stagedRendering } = requestStore
18541855
if (stagedRendering && stagedRendering.currentStage < stage) {
@@ -1859,7 +1860,7 @@ async function delayBeforeCacheReadStartInDev(
18591860
/** Note: Only call this after a `cacheSignal.beginRead()`. */
18601861
async function delayOrHangStartedCacheReadInDev(
18611862
stage: NonStaticRenderStage,
1862-
requestStore: RequestStore,
1863+
requestStore: DevRequestStore,
18631864
cacheSignal: CacheSignal | null,
18641865
route: string,
18651866
expression: string

0 commit comments

Comments
 (0)