Commit Graph

1635 Commits

Author SHA1 Message Date
James Anderson fd8dd3de09 fix(app-router): preserve app rewrite filtering (#2441) 2026-07-01 11:08:31 +01:00
James Anderson de733ce4aa fix(app-router): revalidate dynamic intercepted actions (#2443) 2026-07-01 11:02:53 +01:00
James Anderson bc1dfce00f fix(app-router): evict segment prefetches under memory pressure (#2466)
* fix(app-router): evict segment prefetches under memory pressure

* fix(app-router): hold prefetch queue slots until body read
2026-07-01 10:54:47 +01:00
Nathan Nguyen 4dd64dd87f fix(build): handle dynamic requests in JS files with JSX (#1736)
* fix(build): parse dynamic request JS files as JSX

* fix(build): parse mjs cjs dynamic requests as JSX

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 23:25:47 +01:00
Yunfei He fae1a4f949 fix(dev): treat .js as JSX in the optimizeDeps scanner (#2434)
* fix(dev): treat .js as JSX in the optimizeDeps scanner

The dep optimizer (scanner + pre-bundler) runs its own Rolldown/esbuild
pipeline that does not go through the `vinext:jsx-in-js` transform plugin,
so JSX in plain `.js`/`.mjs` source files made the dependency scan fail with
"Unexpected JSX expression" and aborted pre-bundling.

Configure the dep optimizer to treat `.js`/`.mjs` as JSX
(`optimizeDeps.rolldownOptions.moduleTypes` on Vite 8,
`optimizeDeps.esbuildOptions.loader` on Vite 7), mirroring how the main
transform treats `.js`/`.mjs` (its `/\.m?js$/` filter). Applied to the
top-level optimizeDeps and the per-environment (rsc/ssr/client) blocks via
getDepOptimizeNodeEnvOptions.

The motivating real-world symptom is that, once the scan aborts,
pre-bundling is skipped and UMD/CJS deps can fail to interop under SSR
("window is not defined"). That downstream cascade runs through a different
optimizer path and is not what this change is verified to fix — the added
tests assert only that the dependency scan no longer aborts on
JSX-in-`.js`/`.mjs`.

* test(dev): cover pages jsx optimizer scan

* test(dev): strengthen jsx optimizer scan coverage

* fix(dev): apply jsx optimizer config to pages build clients

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 23:07:30 +01:00
Yunfei He feb78add12 feat(pages): enforce reactStrictMode by wrapping client root in <StrictMode> (#2433)
* feat(pages): enforce reactStrictMode by wrapping client root in <StrictMode>

`reactStrictMode: true` was recognized but not enforced — the app root was
never wrapped in <React.StrictMode>, so dev-time strict checks (double-invoked
effects/render, deprecation warnings) were silently lost.

Resolve `reactStrictMode` from next.config (preserved as `boolean | null` so
each router applies its own default) and, for the Pages Router, wrap the
client tree in <React.StrictMode> when the value is `true`. The default
matches Next.js: `null`/unset is OFF for the Pages Router
(`reactStrictMode === null ? false` in define-env.ts).

The wrap lives in `wrapWithRouterContext` (next/router) — the single seam every
render path funnels through: the initial hydration entry (production AND the
dev server's inline hydration script) and every client-side navigation
`root.render()` in shims/router.ts. This mirrors Next.js, whose `doRender`
closure wraps in <React.StrictMode> for both the initial hydrate and subsequent
`reactRoot.render()` calls (client/index.tsx). Wrapping only the production
client entry would have been inert — StrictMode does nothing in production, and
the dev server hydrates via a separate template — so the flag is also threaded
into createSSRHandler and the dev hydration script. The wrap is gated on a
client-only `window.__VINEXT_REACT_STRICT_MODE__` flag so the server-rendered
tree is never wrapped (Next.js wraps client-side only); StrictMode renders no
DOM, so SSR markup and hydration are unaffected. The CommitBoundary stays
outside StrictMode so its commit effect is not double-invoked (Next.js keeps
`<Root>` outside <StrictMode> too).

`vinext check` reports reactStrictMode as "partial": enforced for the Pages
Router, but the App Router is not yet wrapped (its root is mounted by the RSC
client runtime, not vinext-owned code, and Next.js defaults App Router strict
mode on).

* test(pages): cover strict mode navigation renders

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 23:06:25 +01:00
Yunfei He 13d36378f8 perf(build): parallelize prerender across a pool of render processes (#2437)
* perf(build): parallelize prerender across a pool of render processes

Build-time prerender rendered every static route by fetching it from a
single in-process production server driven by a promise pool. React
SSR/RSC rendering is CPU-bound JS, so the pool only overlaps I/O — every
render serialized on one core, and raising --prerender-concurrency did
nothing. Next.js forks a worker pool and saturates every core.

Fork a pool of production-server child processes (one per core, capped)
and round-robin the per-route render fetch across them, keeping route
scanning, getStaticPaths/static-params resolution, file writing and the
manifest on the main process. Pool size scales by cores AND routes, so
small apps, low-memory machines, and --prerender-concurrency 1 keep the
single in-process server (no fork, no regression); running from source
(no built .js worker entry) also falls back to single-process.

child_process, not worker_threads: worker threads contend for CPU on this
workload (measured ~2x slower per route and non-scaling), which is also
why Next.js uses processes.

react.dev (809 routes, cold cache, same machine): 29.9s -> 15.1s, now
faster than its own Next.js build (~19.3s). An 801-route static fixture:
~22s -> ~2-6s. Prerender output is byte-identical to the single-process
path on deterministic renders; workers install the same NoOp cache
handler the in-process path uses. A worker that exits unexpectedly fails
the build loudly instead of shipping partial output.

* fix(build): harden prerender worker pool

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 23:04:02 +01:00
Yunfei He 6e9fa0b0b1 fix(config): resolve and bundle extensionless .cjs config imports (#2435)
* fix(config): resolve and bundle extensionless .cjs config imports

`vinext init` renames CJS config files (tailwind.config.js,
postcss.config.js) to .cjs when it adds "type": "module", and app code
imports them extensionlessly (import cfg from "../tailwind.config").

Two problems blocked this on the app module graph:

1. vinext overrides resolve.extensions for every Vite environment with a
   list that, like Vite's default, omits .cjs/.cts, so the extensionless
   import failed with [UNRESOLVED_IMPORT]. Append .cjs/.cts (lowest
   priority) to buildViteResolveExtensions' default list.

2. Once resolved, vite-plugin-commonjs rewrote the .cjs module.exports to
   ESM export {}, but rolldown infers moduleType: cjs from the extension
   and re-parsed the output as CommonJS, failing with "Cannot use export
   statement outside a module". Return false from the commonjs() filter for
   project-local .cjs/.cts so vite-plugin-commonjs skips them and rolldown's
   own CJS interop bundles them. Everything else returns undefined, which
   preserves the plugin's defaults, including its existing skip of
   node_modules .cjs files.

Fixes cloudflare/vinext#13.

* fix(config): harden local cjs commonjs filter

* docs(config): fix cjs regression references

* test(config): cover extensionless cts config imports

* docs(config): clarify cjs resolve extension defaults

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 23:00:55 +01:00
James Anderson 2da8287e89 fix(app-router): honor basePath false rewrites (#2370)
* fix(app-router): honor basePath false rewrites

* fix(app-router): preserve basePath routing boundaries

* test(app-router): cover basePath handler boundaries

* fix(app-router): track basePath rewrite claims

* chore(app-router): remove stale basePath note

* fix(app-router): allow late rewrite route posts

* fix(app-router): short-circuit unclaimed basePath misses

* fix(app-router): preserve out-of-basePath 404 semantics

* fix(app-router): validate late basePath rewrites

* docs(app-router): clarify late action rewrites

* fix(app-router): resolve progressive action rewrites
2026-06-30 21:16:27 +01:00
James Anderson e0cb913922 fix(app-router): preserve rewritten route identity (#2358)
* fix(app-router): preserve rewritten route identity

* test(app-router): isolate rewrite prefetch regression

* test(app-router): cover rewritten element keys

* test(app-router): remove orphaned rewrite fixture

* fix(prerender): avoid reloading RSC entry after path injection
2026-06-30 21:14:04 +01:00
James Anderson d7e8bc5f53 chore: add script for targetted e2e (#2439) 2026-06-30 19:56:06 +00:00
James Anderson 328f01b09d fix(app-router): support styled-jsx from next (#2341)
* fix(app-router): support styled-jsx from next

* fix(app-router): preserve styled jsx refresh

* test(app-router): exercise styled jsx compiler

* fix(app-router): keep styled jsx refresh server-safe

* fix(app-router): keep styled jsx refresh server-safe

* test(app-router): cover server-safe styled jsx dev

* fix(app-router): detect styled jsx syntax variants

* fix(app-router): scope styled jsx detection

* fix(app-router): parse styled jsx attributes

* fix(app-router): delegate styled jsx detection

* fix(app-router): preserve vinext-only style builds

* fix(app-router): detect styled jsx with AST

* fix(app-router): prefer Next styled jsx runtime

* fix(app-router): skip styled-jsx transforms in dependencies
2026-06-30 20:54:17 +01:00
James Anderson 8df2344e77 fix(css): preserve Sass partial asset URLs (#2338)
* fix(css): preserve Sass partial asset URLs

* fix(css): preserve Sass use namespaces

* fix(css): match Sass namespace derivation
2026-06-30 20:31:49 +01:00
James Anderson 49945a9e05 fix(link): reuse full prefetch loading shells (#2332)
* fix(link): reuse full prefetch loading shells

* fix(link): share loading shell prefetch ownership
2026-06-30 19:34:50 +01:00
Yunfei He c1672a1acb test(routing): cover optional catch-all root with empty params (#2436)
* test(routing): cover optional catch-all root with empty params

Add a regression test for a ROOT-level optional catch-all page
pages/[[...markdownPath]].js whose getStaticPaths emits the empty-params
entry { markdownPath: [] } (the react.dev shape). Verifies the dev server
serves the root / HTML, the /_next/data/<id>/index.json endpoint, a
non-root concrete path, and a 404 for unlisted paths under fallback:false.

The existing optional catch-all test only covers a non-root subpath; this
guards the empty-params-at-root case, which routes through the trie's
0-segment optional catch-all match (route-trie.ts) and the empty-array
path normalization (route-pattern.ts / pages-page-data.ts).

* test(routing): tighten optional catch-all root coverage

---------

Co-authored-by: James <james@eli.cx>
2026-06-30 18:31:56 +01:00
James Anderson 6a787de547 feat(benchmarks): add local profile tooling (#2432) 2026-06-30 16:06:13 +00:00
James Anderson 427e0ef154 fix(dev): seed Cloudflare Pages Router worker deps (#2430)
* fix(dev): seed Cloudflare Pages Router worker deps

* fix(dev): include external store selector dep

* fix(dev): guard optional worker optimizer dep

* Revert "fix(dev): guard optional worker optimizer dep"

This reverts commit 65530f1d0c.

* fix(dev): suppress optional worker optimizer warning

* fix(dev): harden optional optimizer warning filter
2026-06-30 12:26:16 +01:00
James Anderson b0de1af028 fix(cloudflare): support Sentry request errors on Workers (#2425)
* fix(cloudflare): support sentry request errors on workers

* fix(cloudflare): avoid worker conditions in node pages builds

* test(cloudflare): run sentry worker e2es in ci

* test(cloudflare): cover sentry render errors

* test(cloudflare): mirror sentry next setup in fixtures

* update lockfile

* update lockfile

* test(cloudflare): cover sentry client instrumentation
2026-06-30 10:58:04 +01:00
James Anderson f4a96c993b fix(pages): preload initial dev stylesheets (#2423)
* fix(pages): preload initial dev stylesheets

* fix(pages): keep dev module path encoder internal

* fix(pages): harden dev stylesheet parity

* fix(pages): preserve hybrid app HMR

* fix(pages): preserve CSS resource query imports
2026-06-30 10:10:16 +01:00
James Anderson b5aded498a fix(cloudflare): allow pages deploy without custom worker (#2429) 2026-06-30 08:21:47 +00:00
James Anderson c02f30484b fix(pages): route dotted dynamic paths in dev (#2424)
* fix(pages): route dotted dynamic paths in dev

* fix(pages): preserve i18n dotted dynamic routes

* chore(pages): clarify dotted route preflight

* chore(pages): share dev hostname parsing

* chore(pages): reuse dev request origin
2026-06-30 09:19:27 +01:00
Arnold K 53da079f86 fix: use normalizePathSeparators in formatAppFilePath for Windows compatibility (#2426) 2026-06-30 07:53:52 +00:00
Jerry Zhao c54614f2ed refactor(app-router): build discoverSiblingInterceptingRoutes paths with path.posix (#2306) 2026-06-30 08:49:53 +01:00
Jerry Zhao 7de1edf79d refactor(app-router): descend collectInterceptingPages with path.posix.join (#2307) 2026-06-30 08:49:46 +01:00
Jerry Zhao 795d56873e fix(routing): use normalizePathSeparators(path.relative) instead of path.posix.relative (#2308) 2026-06-30 08:49:36 +01:00
Nathan Nguyen c8aef02dcd test(fonts): mock google font files in unit tests (#2412)
The font self-hosting unit tests depended on live Google Fonts CSS and font file requests. When the CSS fetch hit a recoverable network error, the plugin correctly skipped _vinext injection for offline fallback, but the test expected self-hosted output.

Mock both fonts.googleapis.com CSS and fonts.gstatic.com font binaries for the self-hosting assertions. The offline fallback behavior remains covered by the explicit network-error test.
2026-06-29 21:27:49 +01:00
Nathan Nguyen 2a26a309a0 fix(ci): skip create-next-app deploy on forks (#2414) 2026-06-29 21:27:37 +01:00
dependabot[bot] 31109c4b1b chore(deps): bump actions/cache/save from 6.0.0 to 6.1.0 (#2421)
Bumps [actions/cache/save](https://github.com/actions/cache) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: actions/cache/save
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 21:27:26 +01:00
dependabot[bot] fdd80b4263 chore(deps): bump actions/cache/restore from 6.0.0 to 6.1.0 (#2419)
Bumps [actions/cache/restore](https://github.com/actions/cache) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: actions/cache/restore
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 21:27:17 +01:00
dependabot[bot] f0338b7f59 chore(deps): bump actions/cache from 6.0.0 to 6.1.0 (#2420)
Bumps [actions/cache](https://github.com/actions/cache) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/2c8a9bd7457de244a408f35966fab2fb45fda9c8...55cc8345863c7cc4c66a329aec7e433d2d1c52a9)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 21:27:09 +01:00
James Anderson 91148ac05f ci: deploy CNA smoke with vinext cloudflare CLI (#2422) 2026-06-29 21:26:45 +01:00
James Anderson bf8ba93d4c fix(test): mark app trailing slash ISR fixture private (#2417) 2026-06-29 18:54:36 +00:00
github-actions[bot] a399fc55e2 chore: version packages (#2293)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@vinext/cloudflare@0.2.0 vinext@0.2.0
2026-06-29 19:46:44 +01:00
James Anderson bcd4e44d96 feat(build): support prerender vite config (#2415)
* feat(build): support prerender vite config

* feat(init): offer prerender config opt-in

* fix(cloudflare): export prerender deploy helper

* fix(cloudflare): avoid redundant prerender config load

* fix(build): quiet adapter fallback warnings
2026-06-29 19:16:08 +01:00
James Anderson a3910e7aa9 feat(cloudflare): add unified worker entry (#2416)
* feat(cloudflare): add default pages router worker entry

* feat(cloudflare): add unified worker entry

* chore(web): use unified worker entry

* chore(examples): use built-in workers-cache entry

* chore(examples): keep hackernews on app router entry

* chore(cloudflare): rename unified entry to fetch handler

* chore(cloudflare): keep pages entry source helper test-local
2026-06-29 17:33:51 +00:00
James Anderson 0a48f0f7fb feat(cloudflare): move deploy command to cloudflare package (#2405)
* feat(cloudflare): move deploy command to cloudflare package

* fix(cloudflare): expose deploy cli bin
2026-06-29 16:47:28 +00:00
Nathan Nguyen 25f3d09332 test(e2e): wait for hydration before dev overlay recovery click (#2410)
The dev overlay recovery spec armed its reload canary after only confirming that the navigation runtime existed. That was not enough to prove the app-router client tree had hydrated the Link handler, so CI could occasionally follow the anchor as a hard navigation before the soft-nav path was ready.

Reuse the shared app-router hydration helper before setting the canary and clicking the recovery link. The test still exercises the real browser click path, but no longer races client hydration.
2026-06-29 17:44:28 +01:00
Nathan Nguyen 8ad5e5be32 fix(ci): resolve setup-vp version from catalog (#2406)
* fix(ci): resolve setup-vp version from catalog

* ci: retry app-router e2e

* fix(ci): avoid heredoc in setup version resolver

* fix(ci): anchor setup resolver to workspace root

* chore: rerun ci

* chore: rerun ci
2026-06-29 17:44:05 +01:00
Nathan Nguyen 23ed801656 fix(e2e): stabilize nav regression suspense window (#2408)
* fix(e2e): stabilize nav regression suspense window

* test(e2e): strengthen nav regression flake guard
2026-06-29 16:57:29 +01:00
Boy Steven 94ea837cfc fix(init): only detect pnpm approve-builds failures from pnpm-specific output (#2404) 2026-06-29 15:41:24 +01:00
Boy Steven 0a9eb33a50 docs(nextjs-compat): refresh resolved OpenNext tracking (#2403) 2026-06-29 15:37:57 +01:00
James Anderson 31e87439df fix(pages-router): retain prefetched SSG data (#2366)
* fix(pages-router): retain prefetched SSG data

* fix(pages-router): align SSG export detection

* fix(pages-router): skip data prefetch for non-SSG routes

* fix(pages-router): align data navigation with Next.js

* chore: avoid exporting middleware matcher helper type

* fix(pages-router): preserve client navigation effects

* fix(pages-router): preserve query rewrite history timing

* fix(pages-router): keep data fetch startup synchronous

* fix(pages-router): keep superseded data fetches alive

* fix(pages-router): skip nonmatching redirect matcher awaits

* fix(pages-router): reuse middleware SSR prefetch data

* Fix pages data prefetch CI regressions

* fix(pages-router): evict middleware prefetch cache
2026-06-29 14:52:35 +01:00
James Anderson 4f5ab7b46b fix(pages): pass req res to document initial props (#2402) 2026-06-29 12:17:13 +01:00
James Anderson 69e0051cf7 fix(pages): expose parsed cookies on request objects (#2401) 2026-06-29 11:29:35 +01:00
James Anderson 6cbe7cdd18 fix(ci): handle npm-pinned deploy fixtures (#2400) 2026-06-29 11:12:05 +01:00
James Anderson 3de7c93dc3 ci: smoke test create-next-app Cloudflare deploy (#2398) 2026-06-29 10:35:02 +01:00
Nathan Nguyen 4a88a9c9e9 fix(ci): avoid loading commit diffs in benchmark validation (#2397)
The trusted benchmark publisher validates measuredAt by fetching commit metadata with gh api. Using the repository commit endpoint also returns commit diff files and stats, which can exceed Node's default child process output buffer for large merge commits.

Fetch the raw Git commit object instead, which still exposes committer.date without diff payloads. Update the validator tests to expect the lighter Git Database endpoint and response shape.
2026-06-29 09:55:55 +01:00
James Anderson b9322bc950 feat(web): use new cache (#2337) 2026-06-29 08:41:06 +00:00
James Anderson 011349b858 fix(app-router): match generated params case-insensitively (#2351)
* fix(app-router): match generated params case-insensitively

* test(app-router): preserve requested static param casing
2026-06-28 23:14:14 +00:00
James Anderson 56772ed310 fix(build): resolve framework-owned SWC helpers (#2357)
* fix(build): resolve framework-owned SWC helpers

* fix(test): preserve shared node_modules during deploy prepare
2026-06-29 00:11:42 +01:00