Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
Prevent timeout when loading routes in development (vercel#25749)
Browse files Browse the repository at this point in the history
* Prevent timeout when loading routes in development

The new route loader (vercel#19006) will timeout
loading routes after 3.8s (MS_MAX_IDLE_DELAY), but this can easily happen when
running dev on a large app.

Fixes vercel#25675

* Delay route loading timeout in development

* refactor: Integrate onBuildCallback into resolvePromiseWithTimeout

* refactor: Tweak for better dead-code elimination

Co-authored-by: JJ Kasper <jj@jjsweb.site>
  • Loading branch information
stovmascript and ijjk authored Jul 12, 2021
1 parent 9dbc3b2 commit 8bdccdb
Showing 1 changed file with 62 additions and 7 deletions.
69 changes: 62 additions & 7 deletions packages/next/client/route-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,39 @@ function appendScript(
})
}

// We wait for pages to be built in dev before we start the route transition
// timeout to prevent an un-necessary hard navigation in development.
let devBuildPromise: Promise<void> | undefined
let devBuildResolve: (() => void) | undefined

if (process.env.NODE_ENV === 'development') {
const { addMessageListener } = require('./dev/error-overlay/eventsource')

addMessageListener((event: any) => {
// This is the heartbeat event
if (event.data === '\uD83D\uDC93') {
return
}

const obj =
typeof event === 'string' ? { action: event } : JSON.parse(event.data)

switch (obj.action) {
case 'built':
case 'sync':
if (devBuildResolve) {
devBuildResolve()
devBuildResolve = undefined
}

break

default:
break
}
})
}

// Resolve a promise that times out after given amount of milliseconds.
function resolvePromiseWithTimeout<T>(
p: Promise<T>,
Expand All @@ -164,13 +197,29 @@ function resolvePromiseWithTimeout<T>(
resolve(r)
}).catch(reject)

requestIdleCallback(() =>
setTimeout(() => {
if (!cancelled) {
reject(err)
}
}, ms)
)
// We wrap these checks separately for better dead-code elimination in
// production bundles.
if (process.env.NODE_ENV === 'development') {
;(devBuildPromise || Promise.resolve()).then(() => {
requestIdleCallback(() =>
setTimeout(() => {
if (!cancelled) {
reject(err)
}
}, ms)
)
})
}

if (process.env.NODE_ENV !== 'development') {
requestIdleCallback(() =>
setTimeout(() => {
if (!cancelled) {
reject(err)
}
}, ms)
)
}
})
}

Expand Down Expand Up @@ -307,6 +356,12 @@ function createRouteLoader(assetPrefix: string): RouteLoader {
},
loadRoute(route: string, prefetch?: boolean) {
return withFuture<RouteLoaderEntry>(route, routes, () => {
if (process.env.NODE_ENV === 'development') {
devBuildPromise = new Promise<void>((resolve) => {
devBuildResolve = resolve
})
}

return resolvePromiseWithTimeout(
getFilesForRoute(assetPrefix, route)
.then(({ scripts, css }) => {
Expand Down

0 comments on commit 8bdccdb

Please sign in to comment.