mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #938] [MERGED] fix(app-router): scope layout params and layout error boundaries #965
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#965
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/938
Author: @NathanDrake2406
Created: 4/28/2026
Status: ✅ Merged
Merged: 4/29/2026
Merged by: @james-elicx
Base:
main← Head:nathan/app-layout-boundaries-params📝 Commits (3)
bf053b9fix(app-router): scope layout params and propagate layout head errors9d9e98etest(app-router): cover layout viewport error boundariesbc6ae85chore(app-router): address head review nits📊 Changes
29 files changed (+1045 additions, -813 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+65 -107)📝
packages/vinext/src/routing/app-router.ts(+10 -0)📝
packages/vinext/src/server/app-page-boundary-render.ts(+7 -62)📝
packages/vinext/src/server/app-page-boundary.ts(+42 -3)➕
packages/vinext/src/server/app-page-head.ts(+141 -0)➕
packages/vinext/src/server/app-page-params.ts(+53 -0)📝
packages/vinext/src/server/app-page-route-wiring.tsx(+8 -2)📝
packages/vinext/src/shims/metadata.tsx(+1 -1)📝
tests/__snapshots__/entry-templates.test.ts.snap(+324 -636)📝
tests/app-page-boundary.test.ts(+25 -2)➕
tests/app-page-head.test.ts(+76 -0)➕
tests/app-page-params.test.ts(+47 -0)📝
tests/app-page-route-wiring.test.ts(+39 -0)📝
tests/app-router.test.ts(+20 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-forbidden-boundary/layout.tsx(+9 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-forbidden-boundary/page.tsx(+3 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-metadata-error-with-boundary/error.tsx(+9 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-metadata-error-with-boundary/layout.tsx(+11 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-metadata-error-with-boundary/page.tsx(+3 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/layout-metadata-error-without-boundary/layout.tsx(+11 -0)...and 9 more files
📄 Description
What this changes
App Router layouts now receive only the params that apply at their segment depth during both page tree wiring and layout probing. Layout metadata and viewport resolution use the same segment-scoped params, while page metadata still receives full route params and searchParams.
Layout
generateMetadata()andgenerateViewport()failures now propagate to the normal App Router error boundary path instead of being swallowed. Layout-thrownforbidden()andunauthorized()now select the matching parent HTTP access boundary instead of falling through the not-found-only path.The generated RSC entry stays thin: it serializes route imports and delegates param slicing, head resolution, search param collection, and parent access-boundary selection to typed server helpers.
Why
Next.js scopes layout params by walking accumulated parent params per segment, not by passing the full route params object to every layout. Relevant references:
Next.js also routes metadata and HTTP access fallback failures through the relevant error/access boundary paths:
Approach
Add small functional helpers under
server/for segment param slicing, search param collection, head resolution, and parent access-boundary selection. The RSC entry now imports those helpers and keeps the route-specific imperative work in place.The scanner now keeps forbidden and unauthorized boundary arrays aligned with layout levels, matching the existing not-found array shape.
Validation
vp test run tests/app-page-params.test.ts tests/app-page-head.test.ts tests/app-page-boundary.test.ts tests/app-page-route-wiring.test.ts tests/entry-templates.test.ts tests/routing.test.tsvp test run tests/nextjs-compat/global-error.test.tsvp test run tests/app-router.test.ts -t "thrown from a layout uses|layout generateMetadata\(\) does not receive searchParams"vp check tests/app-page-params.test.ts tests/app-page-head.test.ts tests/app-page-boundary.test.ts tests/app-page-route-wiring.test.ts tests/entry-templates.test.ts tests/routing.test.ts tests/nextjs-compat/global-error.test.ts tests/app-router.test.tsvp check tests/nextjs-compat/global-error.test.tsgit diff --checkRisks / follow-ups
Checked open PRs before publishing. Closest adjacent work is #891, #735, and #822; this PR should not overlap their behavior directly.
This PR intentionally does not address remaining App Router opportunities like unknown Server Action IDs, non-action method handling, route-handler
NextResponse.next()validation, or route-handler cookie precedence.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.