Skip to content

Commit 254fa07

Browse files
committed
[dynamicIO] use RSC dynamicness to control partial vs complete PPR result
Historically anything dynamic in a prerender would result in a partially static shell that resumes at runtime. With this change now partial shells are only possible when RSC is dynamic. If your client prerneder has any IO but your RSC tree was entirely prerenderable then Next.js will produce a complete static result and not perform a resume at runtime. This simplifies how you reason about what will and wil not make a static page. It also means that anything dynamic in the client layer will only render in browser.
1 parent 6492a52 commit 254fa07

File tree

1 file changed

+8
-4
lines changed

1 file changed

+8
-4
lines changed

packages/next/src/server/app-render/app-render.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3182,7 +3182,6 @@ async function prerenderToStream(
31823182
hmrRefreshHash: undefined,
31833183
}
31843184

3185-
let clientIsDynamic = false
31863185
let dynamicValidation = createDynamicValidationState()
31873186

31883187
const prerender = require('react-dom/static.edge')
@@ -3209,8 +3208,6 @@ async function prerenderToStream(
32093208
isPrerenderInterruptedError(err) ||
32103209
finalClientController.signal.aborted
32113210
) {
3212-
clientIsDynamic = true
3213-
32143211
const componentStack: string | undefined = (
32153212
errorInfo as any
32163213
).componentStack
@@ -3274,7 +3271,12 @@ async function prerenderToStream(
32743271
fallbackRouteParams
32753272
)
32763273

3277-
if (serverIsDynamic || clientIsDynamic) {
3274+
if (serverIsDynamic) {
3275+
// Dynamic case
3276+
// We will always need to perform a "resume" render of some kind when this route is accessed
3277+
// because the RSC data itself is dynamic. We determine if there are any HTML holes or not
3278+
// but generally this is a "partial" prerender in that there will be a per-request compute
3279+
// concatenated to the static shell.
32783280
if (postponed != null) {
32793281
// Dynamic HTML case
32803282
metadata.postponed = await getDynamicHTMLPostponedState(
@@ -3308,6 +3310,8 @@ async function prerenderToStream(
33083310
}
33093311
} else {
33103312
// Static case
3313+
// We will not perform resumption per request. The result can be served statically to the requestor
3314+
// and if there was anything dynamic it will be marked as
33113315
if (workStore.forceDynamic) {
33123316
throw new StaticGenBailoutError(
33133317
'Invariant: a Page with `dynamic = "force-dynamic"` did not trigger the dynamic pathway. This is a bug in Next.js'

0 commit comments

Comments
 (0)