Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix idleTimeout error being thrown in route loader #22775

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions packages/next/client/route-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,29 @@ function appendScript(
})
}

function idleTimeout<T>(ms: number, err: Error): Promise<T> {
return new Promise((_resolve, reject) =>
requestIdleCallback(() => setTimeout(() => reject(err), ms))
)
// Resolve a promise that times out after given amount of milliseconds.
function resolvePromiseWithTimeout<T>(
p: Promise<T>,
ms: number,
err: Error
): Promise<T> {
return new Promise((resolve, reject) => {
let cancelled = false

p.then((r) => {
// Resolved, cancel the timeout
cancelled = true
resolve(r)
}).catch(reject)

requestIdleCallback(() =>
setTimeout(() => {
if (!cancelled) {
reject(err)
}
}, ms)
)
})
}

// TODO: stop exporting or cache the failure
Expand All @@ -176,13 +195,12 @@ export function getClientBuildManifest(): Promise<ClientBuildManifest> {
cb && cb()
}
})
return Promise.race([

return resolvePromiseWithTimeout<ClientBuildManifest>(
onBuildManifest,
idleTimeout<ClientBuildManifest>(
MS_MAX_IDLE_DELAY,
markAssetError(new Error('Failed to load client build manifest'))
),
])
MS_MAX_IDLE_DELAY,
markAssetError(new Error('Failed to load client build manifest'))
)
}

interface RouteFiles {
Expand Down Expand Up @@ -298,15 +316,14 @@ function createRouteLoader(assetPrefix: string): RouteLoader {
Promise.all(css.map(fetchStyleSheet)),
] as const)

const entrypoint: RouteEntrypoint = await Promise.race([
const entrypoint: RouteEntrypoint = await resolvePromiseWithTimeout(
this.whenEntrypoint(route),
idleTimeout<RouteLoaderEntry>(
MS_MAX_IDLE_DELAY,
markAssetError(
new Error(`Route did not complete loading: ${route}`)
)
),
])
MS_MAX_IDLE_DELAY,
markAssetError(
new Error(`Route did not complete loading: ${route}`)
)
)

const res: RouteLoaderEntry = Object.assign<
{ styles: RouteStyleSheet[] },
RouteEntrypoint
Expand Down