[PR #986] [MERGED] refactor(app-router): extract app page dispatch #1001

Closed
opened 2026-05-06 13:11:30 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/986
Author: @NathanDrake2406
Created: 4/30/2026
Status: Merged
Merged: 5/1/2026
Merged by: @james-elicx

Base: mainHead: nathan/extract-app-page-dispatch


📝 Commits (2)

  • 888ca29 refactor(app-router): extract app page dispatch
  • 6938714 chore: rerun ci

📊 Changes

8 files changed (+1264 additions, -3188 deletions)

View changed files

📝 knip.ts (+1 -0)
📝 packages/vinext/src/entries/app-rsc-entry.ts (+43 -438)
packages/vinext/src/server/app-page-dispatch.ts (+632 -0)
📝 packages/vinext/src/server/app-page-request.ts (+5 -5)
📝 tests/__snapshots__/entry-templates.test.ts.snap (+252 -2574)
tests/app-page-dispatch.test.ts (+278 -0)
📝 tests/app-router.test.ts (+39 -171)
📝 tests/entry-templates.test.ts (+14 -0)

📄 Description

What changed

This extracts App Router page request orchestration out of the generated RSC entry and into packages/vinext/src/server/app-page-dispatch.ts.

The generated entry now describes app shape and request wiring only: matched route, params, component tree builder, boundary render callbacks, middleware context, cache keys, and module loaders. The normal runtime module owns behavior: method policy, force-static/error setup, ISR cache read/regeneration, dynamic params validation, intercepting route responses, page element build error handling, lifecycle render delegation, and special-error fallback routing.

Why

This follows the principle that codegen should describe the app shape while normal modules implement behavior. The prior generated template mixed route-specific imports with a large page dispatch pipeline, which made orchestration harder to type, test, review, and evolve independently from route manifest generation.

Behavior tests

Added tests/app-page-dispatch.test.ts with response-level behavior coverage for the new dispatch module:

  • production page cache HIT serves cached HTML instead of revalidating params or rendering
  • unsupported page methods return the method policy response instead of rendering
  • dynamicParams = false returns 404 for paths outside generated params
  • intercepted RSC source-route payloads preserve middleware status and headers

These tests assert HTTP-visible outcomes: status, headers, and response body. They avoid asserting dispatch call counts or generated implementation details.

Next.js references

Next.js uses a similar separation between generated app-page shape and runtime page rendering modules:

Validation

  • vp check --fix knip.ts packages/vinext/src/entries/app-rsc-entry.ts packages/vinext/src/server/app-page-dispatch.ts packages/vinext/src/server/app-page-request.ts tests/app-page-dispatch.test.ts tests/app-router.test.ts tests/entry-templates.test.ts tests/__snapshots__/entry-templates.test.ts.snap
  • vp test run tests/app-page-dispatch.test.ts
  • vp test run tests/app-page-dispatch.test.ts tests/entry-templates.test.ts tests/app-router.test.ts tests/app-page-render.test.ts tests/app-page-request.test.ts tests/app-page-cache.test.ts
  • vp run knip --no-progress
  • Commit hook reran staged-file checks and Knip successfully.

Risk coverage

Covered the main behavioral risks through dedicated dispatch behavior tests plus the App Router integration suite: dev/prod App Router rendering, RSC/HTML responses, ISR cache reads and writes, route handler separation, middleware header propagation, dynamic params validation, intercepting routes, not-found/forbidden/unauthorized boundaries, and generated-entry delegation assertions.

The generated-code tests intentionally assert only the delegation contract now. Runtime dispatch behavior is covered by tests/app-page-dispatch.test.ts, existing helper tests, and the App Router integration suite.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/986 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 4/30/2026 **Status:** ✅ Merged **Merged:** 5/1/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `nathan/extract-app-page-dispatch` --- ### 📝 Commits (2) - [`888ca29`](https://github.com/cloudflare/vinext/commit/888ca29c0771db61c355949b2305d0c07a919d74) refactor(app-router): extract app page dispatch - [`6938714`](https://github.com/cloudflare/vinext/commit/6938714f44e57ab0d021009c927b321450ef6fda) chore: rerun ci ### 📊 Changes **8 files changed** (+1264 additions, -3188 deletions) <details> <summary>View changed files</summary> 📝 `knip.ts` (+1 -0) 📝 `packages/vinext/src/entries/app-rsc-entry.ts` (+43 -438) ➕ `packages/vinext/src/server/app-page-dispatch.ts` (+632 -0) 📝 `packages/vinext/src/server/app-page-request.ts` (+5 -5) 📝 `tests/__snapshots__/entry-templates.test.ts.snap` (+252 -2574) ➕ `tests/app-page-dispatch.test.ts` (+278 -0) 📝 `tests/app-router.test.ts` (+39 -171) 📝 `tests/entry-templates.test.ts` (+14 -0) </details> ### 📄 Description ## What changed This extracts App Router page request orchestration out of the generated RSC entry and into `packages/vinext/src/server/app-page-dispatch.ts`. The generated entry now describes app shape and request wiring only: matched route, params, component tree builder, boundary render callbacks, middleware context, cache keys, and module loaders. The normal runtime module owns behavior: method policy, force-static/error setup, ISR cache read/regeneration, dynamic params validation, intercepting route responses, page element build error handling, lifecycle render delegation, and special-error fallback routing. ## Why This follows the principle that codegen should describe the app shape while normal modules implement behavior. The prior generated template mixed route-specific imports with a large page dispatch pipeline, which made orchestration harder to type, test, review, and evolve independently from route manifest generation. ## Behavior tests Added `tests/app-page-dispatch.test.ts` with response-level behavior coverage for the new dispatch module: - production page cache HIT serves cached HTML instead of revalidating params or rendering - unsupported page methods return the method policy response instead of rendering - `dynamicParams = false` returns 404 for paths outside generated params - intercepted RSC source-route payloads preserve middleware status and headers These tests assert HTTP-visible outcomes: status, headers, and response body. They avoid asserting dispatch call counts or generated implementation details. ## Next.js references Next.js uses a similar separation between generated app-page shape and runtime page rendering modules: - [App page build template creates an `AppPageRouteModule`](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/build/templates/app-page.ts#L127) - [Generated app-page template delegates into a render closure rather than owning all renderer internals](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/build/templates/app-page.ts#L771) - [`AppPageRouteModule` is the runtime module boundary for app page rendering](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/server/route-modules/app-page/module.ts#L85) - [`AppPageRouteModule.render()` delegates to `renderToHTMLOrFlight`](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/server/route-modules/app-page/module.ts#L155) - [`renderToHTMLOrFlightImpl` owns the app render orchestration](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/server/app-render/app-render.tsx#L2568) - [`renderToHTMLOrFlight` exposes the stable runtime entrypoint](https://github.com/vercel/next.js/blob/ae61573e062e900050b8e6b24626e450accc4570/packages/next/src/server/app-render/app-render.tsx#L3077) ## Validation - `vp check --fix knip.ts packages/vinext/src/entries/app-rsc-entry.ts packages/vinext/src/server/app-page-dispatch.ts packages/vinext/src/server/app-page-request.ts tests/app-page-dispatch.test.ts tests/app-router.test.ts tests/entry-templates.test.ts tests/__snapshots__/entry-templates.test.ts.snap` - `vp test run tests/app-page-dispatch.test.ts` - `vp test run tests/app-page-dispatch.test.ts tests/entry-templates.test.ts tests/app-router.test.ts tests/app-page-render.test.ts tests/app-page-request.test.ts tests/app-page-cache.test.ts` - `vp run knip --no-progress` - Commit hook reran staged-file checks and Knip successfully. ## Risk coverage Covered the main behavioral risks through dedicated dispatch behavior tests plus the App Router integration suite: dev/prod App Router rendering, RSC/HTML responses, ISR cache reads and writes, route handler separation, middleware header propagation, dynamic params validation, intercepting routes, not-found/forbidden/unauthorized boundaries, and generated-entry delegation assertions. The generated-code tests intentionally assert only the delegation contract now. Runtime dispatch behavior is covered by `tests/app-page-dispatch.test.ts`, existing helper tests, and the App Router integration suite. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:30 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1001
No description provided.