Files
Josh StoryandGitHub d49f449f94 [Cache Components] Reset PrerenderStore after generating RSC payload (#82286)
The RSC payload ideally would be constructed during the prerender.
However it is not currently sync and RSC doesn't provide a top level way
to produce an object child from a function at the root so we generate
the component tree before starting the render.

However we use the workUnitStore type to govern certain behaviors within
the RSC payload generation for instance preparing things like
searchParams and params props for layouts and pages.

So at the moment we scope the RSC generation inside the same
workUnitStore instance that will also scope the prerender. This is fine
except there are certain things that apply in the prerender context that
do not apply in the component tree generation. Namely we do not want to
track Sync IO as need to abort the prerender. This would lead to the
entire prerender being aborted before it even begins.

There are a few options. We could create a new workUnitStore type. This
isn't great b/c we have so many places where we need to exhaustively
check this.

We could use a new phase to similarly track whether we're before render
or not however this has the same problem of all places where phase is
considered needing to be aware of this additional possible phase.

Instead I think we ought to leave the logic of the code that determines
what to do simple and continue to track the sync IO but we just reset
the dynamic tracking and abort controllers so that the render starts
afresh with these.
2025-08-01 20:43:37 -07:00

39 lines
1.4 KiB
TypeScript

/**
* This is a rather contrived test. The trick is to construct a scenario where
* Math.random is called during the create-component-tree phase but not during the render.
* To do this we patch Symbol.for. When the `react.client.reference` symbol is checked
* we know that this is happening in the create-component-tree function. Given the simple
* setup of the test page this symbol is not checked during the actual prerender itself.
*
* This test may flake in the future. It should be replaced ideally with a test that uses
* our OTel implementation to ensure that the built-in trace in create-component-tree does not
* early abort the prerender. The problem is that we are about to make these functions avoid the
* workUnitStore scope so it will not express the regression for other reasons.
*/
function patchSymbolFor() {
const isPatched = globalThis[Symbol.for('__SYMBOL_FOR_PATCHED__')]
if (!isPatched) {
console.log('patching')
globalThis[Symbol.for('__SYMBOL_FOR_PATCHED__')] = true
const originalSymbolFor = Symbol.for
Symbol.for = (...args) => {
if (args[0] === 'react.client.reference') {
Math.random()
}
return originalSymbolFor.apply(Symbol, args)
}
}
}
patchSymbolFor()
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}