Skip to content

Commit 4337bc2

Browse files
authored
fallback shell should not error when dynamic due to params access even with dynamic = "error" (#70534)
When producing a fallback shell params is dynamic. Normally anything dynamic shoudl be a build error when `export const dynamic = "error"` is used. however for fallback shells we'll never have fully static shells, nor should we since the whole point is to produce a PPR shell that server a wide range of paths. In the refactor for async dynamic APIs I introduced a bug where fallback param dynamic also errored if `export const dynamic = "error"` was used. This change corrects this behavior and adds a corresponding test
1 parent cd65c52 commit 4337bc2

File tree

4 files changed

+51
-17
lines changed

4 files changed

+51
-17
lines changed

packages/next/src/server/request/params.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ import {
1414
type PrerenderStore,
1515
} from '../app-render/prerender-async-storage.external'
1616
import { InvariantError } from '../../shared/lib/invariant-error'
17-
import {
18-
makeResolvedReactPromise,
19-
describeStringPropertyAccess,
20-
throwWithStaticGenerationBailoutErrorWithDynamicError,
21-
} from './utils'
17+
import { makeResolvedReactPromise, describeStringPropertyAccess } from './utils'
2218
import { makeHangingPromise } from '../dynamic-rendering-utils'
2319

2420
export type Params = Record<string, string | Array<string> | undefined>
@@ -259,12 +255,13 @@ function makeErroringExoticParams(
259255
Object.defineProperty(augmentedUnderlying, prop, {
260256
get() {
261257
const expression = describeStringPropertyAccess('params', prop)
262-
if (staticGenerationStore.dynamicShouldError) {
263-
throwWithStaticGenerationBailoutErrorWithDynamicError(
264-
staticGenerationStore.route,
265-
expression
266-
)
267-
} else if (prerenderStore) {
258+
// In most dynamic APIs we also throw if `dynamic = "error"` however
259+
// for params is only dynamic when we're generating a fallback shell
260+
// and even when `dynamic = "error"` we still support generating dynamic
261+
// fallback shells
262+
// TODO remove this comment when dynamicIO is the default since there
263+
// will be no `dynamic = "error"`
264+
if (prerenderStore) {
268265
postponeWithTracking(
269266
staticGenerationStore.route,
270267
expression,
@@ -282,12 +279,13 @@ function makeErroringExoticParams(
282279
Object.defineProperty(promise, prop, {
283280
get() {
284281
const expression = describeStringPropertyAccess('params', prop)
285-
if (staticGenerationStore.dynamicShouldError) {
286-
throwWithStaticGenerationBailoutErrorWithDynamicError(
287-
staticGenerationStore.route,
288-
expression
289-
)
290-
} else if (prerenderStore) {
282+
// In most dynamic APIs we also throw if `dynamic = "error"` however
283+
// for params is only dynamic when we're generating a fallback shell
284+
// and even when `dynamic = "error"` we still support generating dynamic
285+
// fallback shells
286+
// TODO remove this comment when dynamicIO is the default since there
287+
// will be no `dynamic = "error"`
288+
if (prerenderStore) {
291289
postponeWithTracking(
292290
staticGenerationStore.route,
293291
expression,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const dynamic = 'error'
2+
3+
export default function Layout({ children }) {
4+
return (
5+
<>
6+
<div data-layout={Math.random().toString(16).slice(2)} />
7+
{children}
8+
</>
9+
)
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { setTimeout } from 'timers/promises'
2+
3+
export default async function Page({ params }) {
4+
await setTimeout(1000)
5+
6+
const { slug } = params
7+
8+
return (
9+
<div>
10+
<div data-slug={slug}>{slug}</div>
11+
This page should be static
12+
</div>
13+
)
14+
}

test/e2e/app-dir/ppr-full/ppr-full.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,18 @@ describe('ppr-full', () => {
476476
expect(revalidatedDynamicID).not.toBe(fallbackID)
477477
})
478478
})
479+
480+
/**
481+
* This test is really here to just to force the the suite to have the expected route
482+
* as part of the build. If this failed we'd get a build error and all the tests would fail
483+
*/
484+
it('will allow dynamic fallback shells even when static is enforced', async () => {
485+
const random = Math.random().toString(16).slice(2)
486+
const pathname = `/fallback/dynamic/params/revalidate-${random}`
487+
488+
let $ = await next.render$(pathname)
489+
expect($('[data-slug]').text()).toBe(`revalidate-${random}`)
490+
})
479491
})
480492

481493
it('should allow client layouts without postponing fallback if params are not accessed', async () => {

0 commit comments

Comments
 (0)