Skip to content

fix(form): soft-navigate Pages Router submissions - #2029

Merged
james-elicx merged 1 commit into
mainfrom
codex/fix-pages-form-soft-navigation-20260615
Jun 15, 2026
Merged

fix(form): soft-navigate Pages Router submissions#2029
james-elicx merged 1 commit into
mainfrom
codex/fix-pages-form-soft-navigation-20260615

Conversation

@james-elicx

Copy link
Copy Markdown
Member

Summary

  • integrate next/form submissions with Pages Router soft navigation
  • preserve submitter formAction, client actions, replace, redirects, rewrites, basePath, history, and scroll behavior
  • keep native method/target/external cases on browser form semantics
  • add a hybrid Pages Form fixture and focused data-routing coverage

Next.js parity

Fixes the failing Pages Router matrix in test/e2e/next-form/default/pages-dir.test.ts.

Validation

  • pinned Next.js v16.2.6 exact suite: 10/10 passed
  • targeted form/link/pages/core tests: 565/565 passed
  • vinext-owned Playwright fixture: 5/5 passed
  • scoped checks and diff validation passed
  • independent review: no actionable findings

Cache Components, PPR, and resume behavior are explicitly out of scope.

@pkg-pr-new

pkg-pr-new Bot commented Jun 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2029
npm i https://pkg.pr.new/vinext@2029

commit: 12dba6a

@github-actions

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
workers-cache preview production
web preview production

@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

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.

Review: fix(form): soft-navigate Pages Router submissions

I reviewed the diff against main, traced the request lifecycle through app-rsc-handler.tsapp-pages-bridge.tspages-page-handler.ts, checked dev/prod parity, and ran the targeted unit + production-server suites. Everything passes and the change is well-scoped and well-tested. No blocking issues found.

Verified behavior

  • Pre-middleware normalization is correct. /_next/data/<buildId>/<page>.json is detected and normalized before middleware runs; middleware sees the basePath-prefixed page path (/docs/form-search), and cf is preserved across the request clones. Covered by the new "normalizes hybrid Pages data requests before middleware" test.
  • x-nextjs-rewrite parity. The emitted rewrite target is the basePath-stripped resolvedUrl, matching the existing pure Pages Router pipeline (pages-request-pipeline.ts refreshDataRewriteHeader). The client's resolvePagesDataNavigationTarget runs stripBasePath on it, so the values line up. Comparing against originalResolvedUrl (captured before any rewrite) correctly covers both middleware and config rewrites.
  • x-nextjs-redirect soft-redirect protocol is emitted for config redirects (with basePath, e.g. /docs/about) and middleware redirects (threaded via isDataRequest into applyAppMiddleware). Both paths are tested.
  • Stale buildId → JSON 404 before middleware, app-route-owned data URL → JSON 404, and out-of-basePath data URLs left untouched — all covered.
  • App-only apps (no pages dir) are unaffectedpagesDataNormalization is gated on options.renderPagesFallback, so the new branch never fires and isDataRequest falls back to the x-nextjs-data header as before.
  • cloneRequestWithHeaders refactor in the bridge is behavior-preserving and additionally restores cf/redirect/signal metadata that the old hand-rolled RequestInit dropped.
  • buildId wiringprocess.env.__VINEXT_BUILD_ID is a Vite define applied in both dev and prod (index.ts:1376), so buildId: process.env.__VINEXT_BUILD_ID ?? null resolves to the real id in the generated entry.

Non-blocking observations

  1. Latent double-consume of the request body (not currently reachable). In createAppRscHandler, when pagesDataNormalization.isDataReq is true, pagesDataCandidate is used as the clone source for both appRequest (cloneRequestWithUrl, app-rsc-handler.ts:1118) and pagesDataRequest (cloneRequestWithHeaders, :1122). On undici/Workers, new Request(src, ...) locks/transfers the source body stream, so a body-carrying request would leave the second clone with a disturbed body. This is harmless today because _next/data navigations are always GET (the next/form POST case intentionally stays a native browser submit), but it's a sharp edge if _next/data ever carries a body. Cloning both from rawRequest (or teeing) would make it robust.

  2. Style nit — duplicated renderPage call. In app-pages-bridge.ts:161-176 the isDataRequest ternary duplicates the entire five-argument renderPage(...) call just to append the 6th { isDataReq: true } arg. Could collapse to a single call with a conditional final argument (e.g. renderPage(renderRequest, pagesUrl, {}, undefined, headers, isDataRequest ? { isDataReq: true } : undefined)) for readability.

Neither observation blocks merge. Nice work on the parity coverage and the Next.js-sourced e2e port.

@ask-bonk

ask-bonk Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review posted to PR #2029.

Summary

I reviewed PR #2029 (fix(form): soft-navigate Pages Router submissions) by tracing the full request lifecycle through app-rsc-handler.tsapp-pages-bridge.tspages-page-handler.ts, checking dev/prod parity, comparing against the existing pure Pages Router pipeline, and running the targeted unit + production-server test suites (all green: 96 + 293 + 57 + 54 passing).

Verdict: No blocking issues. The change is well-scoped and well-tested.

Key things I verified:

  • Pre-middleware _next/data normalization (middleware sees the basePath-prefixed page path; cf preserved)
  • x-nextjs-rewrite value matches the existing Pages Router pipeline (basePath-stripped, compared against originalResolvedUrl)
  • x-nextjs-redirect soft-redirect protocol for both config and middleware redirects
  • Stale-buildId/app-owned/out-of-basePath edge cases all 404 or pass-through correctly
  • App-only apps unaffected (new branch gated on renderPagesFallback)
  • cloneRequestWithHeaders refactor is behavior-preserving and restores cf/redirect/signal metadata
  • buildId define resolves in both dev and prod

Two non-blocking observations flagged in the review:

  1. A latent double-consume of the request body (both appRequest and pagesDataRequest clone from the same pagesDataCandidate) — harmless today since _next/data navigations are GET, but a sharp edge if they ever carry a body.
  2. A style nit: the duplicated renderPage call in the isDataRequest ternary could collapse to one call.

github run

@james-elicx
james-elicx marked this pull request as ready for review June 15, 2026 10:31
@james-elicx
james-elicx merged commit 9958567 into main Jun 15, 2026
55 checks passed
@james-elicx
james-elicx deleted the codex/fix-pages-form-soft-navigation-20260615 branch June 15, 2026 21:37
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