Skip to content

refactor: Extract early config header and public file pipeline#983

Merged
james-elicx merged 1 commit intocloudflare:mainfrom
NathanDrake2406:nathan/config-header-public-early-pipeline
Apr 30, 2026
Merged

refactor: Extract early config header and public file pipeline#983
james-elicx merged 1 commit intocloudflare:mainfrom
NathanDrake2406:nathan/config-header-public-early-pipeline

Conversation

@NathanDrake2406
Copy link
Copy Markdown
Contributor

Summary

  • Move next.config.js header application into request-pipeline helpers for both Web Headers and early header records.
  • Move App Router public-file static response resolution into request-pipeline, leaving generated RSC entry code to describe app shape and route manifests.
  • Reuse the same config-header helper from the Pages production server and generated Pages Worker entry; export vinext/server/request-pipeline for generated worker code.
  • Add focused tests for original-request matcher context, middleware/config header precedence, multi-value header appends, and public-file routing policy.

Next.js references

Vinext should keep the route policy aligned with Next.js while keeping behavior out of generated templates:

Tests

  • vp test run tests/request-pipeline.test.ts
  • vp test run tests/app-router.test.ts -t "custom header handling|empty config arrays|rewrite handling code|config pattern"
  • vp test run tests/deploy.test.ts -t "next.config.js custom headers|next.config.js redirects|next.config.js rewrites|basePath stripping"
  • vp test run tests/request-pipeline.test.ts tests/deploy.test.ts
  • vp test run tests/app-router.test.ts -t "custom headers from next.config.js|serves public files from the build output|serves public files under basePath|App Router next.config.js features"
  • vp test run tests/entry-templates.test.ts
  • vp fmt --check packages/vinext/src/server/request-pipeline.ts packages/vinext/src/entries/app-rsc-entry.ts packages/vinext/src/server/prod-server.ts packages/vinext/src/deploy.ts tests/request-pipeline.test.ts tests/app-router.test.ts tests/deploy.test.ts packages/vinext/package.json
  • vp check
  • vp run vinext#build

Copilot AI review requested due to automatic review settings April 30, 2026 03:47
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 30, 2026

Open in StackBlitz

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

commit: 1bbf648

@NathanDrake2406 NathanDrake2406 changed the title Extract early config header and public file pipeline refactor: Extract early config header and public file pipeline Apr 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@james-elicx
Copy link
Copy Markdown
Collaborator

/bigbonk review

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean refactor that successfully extracts duplicated config-header and public-file logic from generated entries and server hot paths into testable helpers in request-pipeline.ts. All CI green.

What I verified:

  • applyConfigHeadersToResponse faithfully reproduces the old inline App Router entry behavior: append for vary/set-cookie, set only when !has().
  • applyConfigHeadersToHeaderRecord faithfully reproduces the old inline Pages Router prod-server and Worker entry behavior, with one inconsequential difference: for set-cookie with no pre-existing value, the old code stored [value] (always array) while the new appendHeaderRecord stores a plain value (string). This is safe because all downstream consumers (toWebHeaders, mergeHeaders, sendCompressed) handle both string and string[] correctly.
  • findHeaderRecordKey adds case-insensitive key lookup, which is a minor improvement over the old lk in middlewareHeaders (which happened to work because both sides were lowercased).
  • resolvePublicFileRoute exactly reproduces the old inline checks: method guard (GET/HEAD), .rsc exclusion on pathname, public-file lookup on cleanPathname, and createStaticFileSignal matches the old __createStaticFileSignal.
  • The new ./server/request-pipeline package.json export is correctly placed for the generated worker entry to consume.
  • Tests cover the important contracts: original-request matcher context, middleware precedence, multi-value header appends, and public-file routing policy.
  • Snapshot updates are mechanical and consistent across all fixture variants.

One small observation below, but nothing blocking.

function appendHeaderRecord(headers: HeaderRecord, lowerName: string, value: string): void {
const key = findHeaderRecordKey(headers, lowerName) ?? lowerName;
const existing = headers[key];
if (existing === undefined) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor observation: the old inline set-cookie code in prod-server.ts and deploy.ts always stored a fresh set-cookie as an array (middlewareHeaders[lk] = [h.value]), whereas appendHeaderRecord stores it as a plain string when there's no existing value. This is safe today because all downstream consumers (toWebHeaders, mergeHeaders) handle both string and string[], but worth noting in case a future consumer assumes set-cookie values are always arrays.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Apr 30, 2026

Review submitted. Approved with one minor observation.

Summary: This is a well-executed refactor that extracts duplicated config-header application and public-file routing logic from 3 places (generated App Router RSC entry, Pages Router prod-server, and generated Worker entry) into shared, tested helpers in request-pipeline.ts. The behavioral equivalence is verified across all code paths, all CI checks pass, and the new tests cover the key contracts. The one minor difference (set-cookie stored as string vs array for single values with no prior entry) is inconsequential since all downstream consumers handle both forms.

github run

@james-elicx james-elicx merged commit 9cae9cb into cloudflare:main Apr 30, 2026
28 of 29 checks passed
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.

3 participants