Introduce prerenderAsyncStorage and refactor app-render (#68637)
In preparation for a number of new features and rendering modes this PR
dramatically refactors app-render and related files to make future
contributions easier to land.
Historically we have used AsyncLocalStorage to scope state that is
contextual for an entire page export (RSC > SSR > error handling etc...)
however it can be useful and is generally a good practice to push the
ALS scoping deeper into the render when possible. One case is for
tracking dynamic access. in this PR we introduce prerenderAsyncStorage
which is wrapped around individual render calls into React. If there is
a store during a render then we can infer we are in an App Router
prerender.
Longer term we should consider combinging the requestStorage and
staticGenerationStorage since these are scoped at the same level and the
name of staticGenerationStorage is misleading because it is in scope
even when there is no static generation happening.
In addition to storage changes the code paths for app-render are
reorganized to use fewer closures and to consolidate argument passing.
Additionally we now treat render (dynamic request handling) and
prerender (build and revalidate handling) in separate code paths. This
allows for clearer login within each pathway and fewer repeated
conditionals.
There are still a number of things to further clean up like how we track
metadata. One idea is to have the render/prerender functions simply
return a RenderResult. Another area is error handling. There is
currently a bug where ssr only errors won't fail a build the same way an
RSC error would. To keep this PR clean I've reproduced this behavior
even if it is buggy so we can land a fix stacked on top