Skip to content

Commit

Permalink
[dynamicIO] track Prerender environment name during dev
Browse files Browse the repository at this point in the history
When rendering in dev we track environment name to pass along server logs to the browser. Today the environment name is the default "Server" however when `dynamicIO` is enabled we want to have logs in the first Task where rendering starts be tagged with the environment "Prerender". This will help us understand what work is happening in the "Prerender" phase and what is happening in the dynamic "Server" phase while developing in dev mode.v
  • Loading branch information
gnoff committed Oct 11, 2024
1 parent ceebc67 commit 3357685
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
31 changes: 31 additions & 0 deletions packages/next/src/server/app-render/app-render-render-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { InvariantError } from '../../shared/lib/invariant-error'

/**
* This is a utility function to make scheduling sequential tasks that run back to back easier.
* We schedule on the same queue (setImmediate) at the same time to ensure no other events can sneak in between.
*/
export function scheduleInSequentialTasks<R>(
render: () => R | Promise<R>,
followup: () => void
): Promise<R> {
if (process.env.NEXT_RUNTIME === 'edge') {
throw new InvariantError(
'`scheduleInSequentialTasks` should not be called in edge runtime.'
)
} else {
return new Promise((resolve, reject) => {
let pendingResult: R | Promise<R>
setImmediate(() => {
try {
pendingResult = render()
} catch (err) {
reject(err)
}
})
setImmediate(() => {
followup()
resolve(pendingResult)
})
})
}
}
56 changes: 45 additions & 11 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ import {
createReactServerPrerenderResult,
createReactServerPrerenderResultFromRender,
prerenderAndAbortInSequentialTasks,
} from '../app-render/app-render-prerender-utils'
} from './app-render-prerender-utils'
import { scheduleInSequentialTasks } from './app-render-render-utils'
import { waitAtLeastOneReactRenderTask } from '../../lib/scheduler'
import {
workUnitAsyncStorage,
Expand Down Expand Up @@ -1445,17 +1446,50 @@ async function renderToStream(
ctx,
res.statusCode === 404
)
reactServerResult = new ReactServerResult(
workUnitAsyncStorage.run(
requestStore,
ComponentMod.renderToReadableStream,
RSCPayload,
clientReferenceManifest.clientModules,
{
onError: serverComponentsErrorHandler,
}

if (
// We only want this behavior when running `next dev`
renderOpts.dev &&
// We only want this behavior when we have React's dev builds available
process.env.NODE_ENV === 'development' &&
// Edge routes never prerender so we don't have a Prerender environment for anything in edge runtime
process.env.NEXT_RUNTIME !== 'edge' &&
// We only have a Prerender environment for projects opted into dynamicIO
renderOpts.experimental.dynamicIO
) {
let environmentName = 'Prerender'
reactServerResult = new ReactServerResult(
await workUnitAsyncStorage.run(
requestStore,
scheduleInSequentialTasks,
() => {
return ComponentMod.renderToReadableStream(
RSCPayload,
clientReferenceManifest.clientModules,
{
onError: serverComponentsErrorHandler,
environmentName: () => environmentName,
}
)
},
() => {
environmentName = 'Server'
}
)
)
)
} else {
reactServerResult = new ReactServerResult(
workUnitAsyncStorage.run(
requestStore,
ComponentMod.renderToReadableStream,
RSCPayload,
clientReferenceManifest.clientModules,
{
onError: serverComponentsErrorHandler,
}
)
)
}

// React doesn't start rendering synchronously but we want the RSC render to have a chance to start
// before we begin SSR rendering because we want to capture any available preload headers so we tick
Expand Down
2 changes: 1 addition & 1 deletion packages/next/types/$$compiled.internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ declare module 'react-server-dom-webpack/server.edge' {
},
options?: {
temporaryReferences?: string
environmentName?: string
environmentName?: string | (() => string)
filterStackFrame?: (url: string, functionName: string) => boolean
onError?: (error: unknown) => void
onPostpone?: (reason: string) => void
Expand Down

0 comments on commit 3357685

Please # to comment.