mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 00:09:23 +02:00
[PR #1016] [MERGED] refactor(app-router): extract app fallback renderer factory #1020
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#1020
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/1016
Author: @NathanDrake2406
Created: 5/2/2026
Status: ✅ Merged
Merged: 5/2/2026
Merged by: @james-elicx
Base:
main← Head:nathan/extract-fallback-renderer📝 Commits (1)
99bc7b6refactor(app-router): extract app fallback renderer factory to eliminate per-request closure reconstruction📊 Changes
6 files changed (+763 additions, -652 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+31 -93)➕
packages/vinext/src/server/app-fallback-renderer.ts(+212 -0)📝
packages/vinext/src/server/app-page-boundary-render.ts(+1 -1)📝
tests/__snapshots__/entry-templates.test.ts.snap(+174 -546)➕
tests/app-fallback-renderer.test.ts(+321 -0)📝
tests/app-router.test.ts(+24 -12)📄 Description
[Kimi 2.6]
What this changes
Replaces three generated wrapper functions (
renderHTTPAccessFallbackPage,renderNotFoundPage,renderErrorBoundaryPage) in the App Router RSC entry with a single factorycreateAppFallbackRenderer()that returns{ renderHttpAccessFallback, renderNotFound, renderErrorBoundary }.The generated entry constructs the factory once at module level and calls the returned methods many times. App-level dependencies (root boundaries, font providers, metadata routes, SSR loader, thenable-params helper, sanitizer, RSC renderer) are pre-bound at construction time. The per-request
Requestobject is passed at the call site and is no longer captured in any factory closure.Why
Previously each of the three wrappers reconstructed a large options object on every invocation, passing the same app-level constants over and over. The
requestparameter was also captured in each wrapper's closure, which inflated the dependency surface and made it hard to distinguish per-app from per-request state at a glance.This follows the codebase principle: codegen should describe the app shape; normal modules should implement behavior.
Approach
packages/vinext/src/server/app-fallback-renderer.tscreateAppFallbackRenderer(options)with a strongly-typed options bagrenderAppPageHttpAccessFallbackandrenderAppPageErrorBoundaryhelpers inapp-page-boundary-render.ts{ headers: null, status: null }) moves into the factory module so generated code no longer needs to define itpackages/vinext/src/entries/app-rsc-entry.tsconst __fallbackRenderer = __createAppFallbackRenderer({...})construction__dispatchAppPageand the not-found fallback path now call__fallbackRenderer.renderErrorBoundary(...),__fallbackRenderer.renderHttpAccessFallback(...), and__fallbackRenderer.renderNotFound(...)packages/vinext/src/server/app-page-boundary-render.tsAppPageBoundaryRoutetype so the factory can reference it without redeclaringValidation
tests/app-fallback-renderer.test.tswith focused unit tests for:renderNotFounddelegates torenderHttpAccessFallbackwith status 404createRscOnErrorHandlerreceives the request at call timetests/app-router.test.tsgenerated-code assertions to verify:createAppFallbackRenderer as __createAppFallbackRendereris importedconst __fallbackRenderer = __createAppFallbackRenderer({...})appears in generated codereturn __renderAppPageHttpAccessFallback({...})andreturn __renderAppPageErrorBoundary({...})are gone__dispatchAppPagecall__fallbackRenderer.renderErrorBoundaryand__fallbackRenderer.renderHttpAccessFallbacktests/app-router.test.ts(316 tests)tests/app-page-boundary-render.test.ts(12 tests)tests/app-page-dispatch.test.ts(4 tests)tests/app-fallback-renderer.test.ts(6 tests)Relevant Next.js source
This refactoring aligns vinext's App Router fallback/error-boundary rendering with the same architectural separation Next.js uses between its app-render pipeline and the underlying boundary components:
packages/next/src/server/app-render/app-render.tsx(seefindPrerenderHTTPErrorBoundaryTree,getErrorRSCPayload, and theerrorRSCPayload/errorServerStreampaths around L8400-L8480)packages/next/src/client/components/http-access-fallback/error-boundary.tsxpackages/next/src/server/app-render/app-render.tsx(seecreateMetadataComponentswitherrorType: 'not-found'around L2110-L2125)Risks / follow-ups
renderAppPageHttpAccessFallbackandrenderAppPageErrorBoundaryhelpers that were already in use.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.