Skip to content

Commit

Permalink
[dynamicIO] use new heuristic to track whether server render is dynam…
Browse files Browse the repository at this point in the history
…ic (#73751)

Instead of relying on onError just use the timing of the prerender
resolution to determine whether the server render completed before
aborting.

React is going to remove onError and onPostpone calls from `prerender`
in flight [31715](facebook/react#31715). This is
because semantically the error is going to be hidden from the prerender
and on resume it might not error. So rather than relying on whether the
error callback is called we simply infer whether we are done by checking
if the `prerender` resolved prior to our abort deadline. In our case it
is possible we also aborted earlier than the deadline because you can
call something like `Math.random()` which requires the `prerender` to
halt synchronously so we also check the signal status in our deadline
task.

We don't expect this to change any semantics so there are no altered
tests.

This is only currently implemented in the dynamicIO + PPR case because
that is the only case using experimental React with `prerender`. When
dynamicIO is on by itself we still use `renderToReadableStream` which
does not have halt semantics. We will switch to `prerender` when it is
available in React's stable channel
  • Loading branch information
gnoff authored Dec 10, 2024
1 parent e098755 commit f8b3174
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2716,11 +2716,12 @@ async function prerenderToStream(
ctx,
res.statusCode === 404
)
let prerenderIsPending = true
const reactServerResult = (reactServerPrerenderResult =
await createReactServerPrerenderResult(
prerenderAndAbortInSequentialTasks(
() =>
workUnitAsyncStorage.run(
async () => {
const prerenderResult = await workUnitAsyncStorage.run(
// The store to scope
finalRenderPrerenderStore,
// The function to run
Expand All @@ -2730,17 +2731,33 @@ async function prerenderToStream(
clientReferenceManifest.clientModules,
{
onError: (err: unknown) => {
// TODO we can remove this once https://github.com/facebook/react/pull/31715 lands
// because we won't have onError calls when halting the prerender
if (finalServerController.signal.aborted) {
serverIsDynamic = true
return
}

return serverComponentsErrorHandler(err)
},
signal: finalServerController.signal,
}
),
)
prerenderIsPending = false
return prerenderResult
},
() => {
if (finalServerController.signal.aborted) {
// If the server controller is already aborted we must have called something
// that required aborting the prerender synchronously such as with new Date()
serverIsDynamic = true
return
}

if (prerenderIsPending) {
// If prerenderIsPending then we have blocked for longer than a Task and we assume
// there is something unfinished.
serverIsDynamic = true
}
finalServerController.abort()
}
)
Expand Down

0 comments on commit f8b3174

Please sign in to comment.