Skip to content

Commit 7d880a3

Browse files
ztannerunstubbable
andauthored
Backport v15: Retry manifest file loading only in dev mode (#73900) (#74283)
Backports: - #73900 Co-authored-by: Hendrik Liebau <[email protected]>
1 parent df392a1 commit 7d880a3

File tree

5 files changed

+41
-8
lines changed

5 files changed

+41
-8
lines changed

packages/next/src/build/utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,7 @@ export async function isPageStatic({
16141614
distDir,
16151615
page: originalAppPath || page,
16161616
isAppPath: pageType === 'app',
1617+
isDev: false,
16171618
})
16181619
}
16191620
const Comp = componentsResult.Component as NextComponentType | undefined
@@ -1869,6 +1870,7 @@ export async function hasCustomGetInitialProps({
18691870
distDir,
18701871
page: page,
18711872
isAppPath: false,
1873+
isDev: false,
18721874
})
18731875
let mod = components.ComponentMod
18741876

@@ -1895,6 +1897,7 @@ export async function getDefinedNamedExports({
18951897
distDir,
18961898
page: page,
18971899
isAppPath: false,
1900+
isDev: false,
18981901
})
18991902

19001903
return Object.keys(components.ComponentMod).filter((key) => {

packages/next/src/export/worker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ async function exportPageImpl(
233233
distDir,
234234
page,
235235
isAppPath: isAppDir,
236+
isDev: false,
236237
})
237238

238239
// Handle App Routes.

packages/next/src/server/dev/static-paths-worker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export async function loadStaticPaths({
8383
// In `pages/`, the page is the same as the pathname.
8484
page: page || pathname,
8585
isAppPath,
86+
isDev: true,
8687
})
8788

8889
if (isAppPath) {

packages/next/src/server/load-components.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,13 @@ export async function evalManifestWithRetries<T extends object>(
118118

119119
async function loadClientReferenceManifest(
120120
manifestPath: string,
121-
entryName: string
121+
entryName: string,
122+
attempts?: number
122123
) {
123124
try {
124125
const context = await evalManifestWithRetries<{
125126
__RSC_MANIFEST: { [key: string]: ClientReferenceManifest }
126-
}>(manifestPath)
127+
}>(manifestPath, attempts)
127128
return context.__RSC_MANIFEST[entryName]
128129
} catch (err) {
129130
return undefined
@@ -134,10 +135,12 @@ async function loadComponentsImpl<N = any>({
134135
distDir,
135136
page,
136137
isAppPath,
138+
isDev,
137139
}: {
138140
distDir: string
139141
page: string
140142
isAppPath: boolean
143+
isDev: boolean
141144
}): Promise<LoadComponentsReturnType<N>> {
142145
let DocumentMod = {}
143146
let AppMod = {}
@@ -151,6 +154,12 @@ async function loadComponentsImpl<N = any>({
151154
// Make sure to avoid loading the manifest for metadata route handlers.
152155
const hasClientManifest = isAppPath && !isMetadataRoute(page)
153156

157+
// In dev mode we retry loading a manifest file to handle a race condition
158+
// that can occur while app and pages are compiling at the same time, and the
159+
// build-manifest is still being written to disk while an app path is
160+
// attempting to load.
161+
const manifestLoadAttempts = isDev ? 3 : 1
162+
154163
// Load the manifest files first
155164
const [
156165
buildManifest,
@@ -159,15 +168,20 @@ async function loadComponentsImpl<N = any>({
159168
clientReferenceManifest,
160169
serverActionsManifest,
161170
] = await Promise.all([
162-
loadManifestWithRetries<BuildManifest>(join(distDir, BUILD_MANIFEST)),
171+
loadManifestWithRetries<BuildManifest>(
172+
join(distDir, BUILD_MANIFEST),
173+
manifestLoadAttempts
174+
),
163175
loadManifestWithRetries<ReactLoadableManifest>(
164-
join(distDir, REACT_LOADABLE_MANIFEST)
176+
join(distDir, REACT_LOADABLE_MANIFEST),
177+
manifestLoadAttempts
165178
),
166179
// This manifest will only exist in Pages dir && Production && Webpack.
167180
isAppPath || process.env.TURBOPACK
168181
? undefined
169182
: loadManifestWithRetries<DynamicCssManifest>(
170-
join(distDir, `${DYNAMIC_CSS_MANIFEST}.json`)
183+
join(distDir, `${DYNAMIC_CSS_MANIFEST}.json`),
184+
manifestLoadAttempts
171185
).catch(() => undefined),
172186
hasClientManifest
173187
? loadClientReferenceManifest(
@@ -177,12 +191,14 @@ async function loadComponentsImpl<N = any>({
177191
'app',
178192
page.replace(/%5F/g, '_') + '_' + CLIENT_REFERENCE_MANIFEST + '.js'
179193
),
180-
page.replace(/%5F/g, '_')
194+
page.replace(/%5F/g, '_'),
195+
manifestLoadAttempts
181196
)
182197
: undefined,
183198
isAppPath
184199
? loadManifestWithRetries<ActionManifest>(
185-
join(distDir, 'server', SERVER_REFERENCE_MANIFEST + '.json')
200+
join(distDir, 'server', SERVER_REFERENCE_MANIFEST + '.json'),
201+
manifestLoadAttempts
186202
).catch(() => null)
187203
: null,
188204
])

packages/next/src/server/next-server.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,14 @@ export default class NextNodeServer extends BaseServer<
177177

178178
protected cleanupListeners = new AsyncCallbackSet()
179179
protected internalWaitUntil: WaitUntil | undefined
180+
private isDev: boolean
180181

181182
constructor(options: Options) {
182183
// Initialize super class
183184
super(options)
184185

186+
this.isDev = options.dev ?? false
187+
185188
/**
186189
* This sets environment variable to be used at the time of SSR by head.tsx.
187190
* Using this from process.env allows targeting SSR by calling
@@ -213,11 +216,13 @@ export default class NextNodeServer extends BaseServer<
213216
distDir: this.distDir,
214217
page: '/_document',
215218
isAppPath: false,
219+
isDev: this.isDev,
216220
}).catch(() => {})
217221
loadComponents({
218222
distDir: this.distDir,
219223
page: '/_app',
220224
isAppPath: false,
225+
isDev: this.isDev,
221226
}).catch(() => {})
222227
}
223228

@@ -278,11 +283,17 @@ export default class NextNodeServer extends BaseServer<
278283
distDir: this.distDir,
279284
page,
280285
isAppPath: false,
286+
isDev: this.isDev,
281287
}).catch(() => {})
282288
}
283289

284290
for (const page of Object.keys(appPathsManifest || {})) {
285-
await loadComponents({ distDir: this.distDir, page, isAppPath: true })
291+
await loadComponents({
292+
distDir: this.distDir,
293+
page,
294+
isAppPath: true,
295+
isDev: this.isDev,
296+
})
286297
.then(async ({ ComponentMod }) => {
287298
// we need to ensure fetch is patched before we require the page,
288299
// otherwise if the fetch is patched by user code, we will be patching it
@@ -789,6 +800,7 @@ export default class NextNodeServer extends BaseServer<
789800
distDir: this.distDir,
790801
page: pagePath,
791802
isAppPath,
803+
isDev: this.isDev,
792804
})
793805

794806
if (

0 commit comments

Comments
 (0)