Skip to content

feat(app-router): filter skipped layouts from RSC responses and cached reads [3/6]#840

Draft
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
NathanDrake2406:feat/pr-768-3-skip-filter-server
Draft

feat(app-router): filter skipped layouts from RSC responses and cached reads [3/6]#840
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
NathanDrake2406:feat/pr-768-3-skip-filter-server

Conversation

@NathanDrake2406
Copy link
Copy Markdown
Contributor

Summary

PR 3 of 6 — restack of #768. Stacked on #839.

Introduces `app-page-skip-filter.ts` with the canonical-bytes guarantee: the render path always produces the full RSC payload and writes it to the cache; the egress branch applies a byte-level filter that omits layouts the client asked to skip, but only if the server independently classified them as static (`computeSkipDecision`).

Wires the filter into `renderAppPageLifecycle` and `buildAppPageCachedResponse` so both fresh renders and cache hits honor the skip header. Parses the incoming `X-Vinext-Router-Skip` header at the handler scope and threads the resulting set through render and ISR.

Dormant until canonical-stream is validated: gated behind `supportsFilteredRscStream: false` in the generated entry so this PR lands inert at runtime. Tests exercise the filter directly by injecting the skip set into `renderAppPageLifecycle` options.

Canonical-bytes invariant

  1. `rscStream` is rendered from the canonical element (never mutated).
  2. `teeAppPageRscStreamForCapture` splits into `capturedRscDataPromise` (→ cache) and `responseStream` (→ client).
  3. The filter only applies to `responseStream` when `isRscRequest && supportsFilteredRscStream !== false && skipIds.size > 0`.
  4. The cache therefore always sees full bytes regardless of client skip state.

Stack

  1. [1/6] refactor(app-rsc-entry): centralize request-derived page inputs [1/6] #838 — centralize request-derived page inputs
  2. [2/6] feat(app-router): emit per-layout flags in the RSC payload [2/6] #839 — emit per-layout flags in the RSC payload
  3. [3/6] this PR — filter skipped layouts from RSC responses and cached reads
  4. [4/6] send X-Vinext-Router-Skip on navigation requests
  5. [5/6] wire build-time layout classification
  6. [6/6] classification reasons sidecar

Test plan

  • `tests/app-page-skip-filter.test.ts` (44 tests)
  • `tests/app-page-cache.test.ts` (17 tests)
  • `tests/app-page-render.test.ts` (21 tests, includes skip-filter section)
  • Verified tests pass WITHOUT client header wiring from PR 4

Reshape buildPageElements to accept a single pageRequest object bundling
opts, searchParams, isRscRequest, request, and mountedSlotsHeader. Lift
the mounted-slots header read to the handler scope so every call site
shares one source of truth and a future refactor cannot silently drift
one read path out of the other.
Wire runtime layout classification through renderAppPageLifecycle and
attach the resulting flags as __layoutFlags in the outgoing RSC payload
via buildOutgoingAppPayload. Payload-shape helpers (withLayoutFlags,
isAppElementsRecord, buildOutgoingAppPayload, AppOutgoingElements) live
alongside the existing readAppElementsMetadata so the write and read
boundaries sit next to each other.
…d reads

Introduce app-page-skip-filter.ts with the canonical-bytes guarantee:
the render path always produces the full RSC payload and writes it to
the cache; the egress branch applies a byte-level filter that omits
layouts the client asked to skip, but only if the server independently
classified them as static (computeSkipDecision).

Wire the filter into renderAppPageLifecycle and buildAppPageCachedResponse
so both fresh renders and cache hits honor the skip header. Parse the
incoming X-Vinext-Router-Skip header at the handler scope and thread
the resulting set through render and ISR.

Gate the filter behind supportsFilteredRscStream: false in the generated
entry so this PR is dormant at runtime until the canonical-stream story
is validated. Tests exercise the filter directly by injecting the skip
set into renderAppPageLifecycle options.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 14, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@840

commit: 7d04612

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant