Commit Graph

1201 Commits

Author SHA1 Message Date
James Anderson ed0e343d05 feat(init): mark CDN warmup flag experimental (#2533)
* feat(init): mark CDN warmup flag experimental

* chore(init): tweak experimental prewarm prompt

* chore(init): default experimental prewarm to no
2026-07-04 16:50:59 +00:00
James Anderson 201f423677 fix(init): use built Wrangler config for deploy script (#2532) 2026-07-04 17:40:33 +01:00
James Anderson eba70463d4 feat(cloudflare): warm prerendered paths before deploy (#2481)
* feat(cloudflare): warm prerendered paths before deploy

* fix(cloudflare): warm production CDN for uploaded versions

* fix(cloudflare): resolve Worker names for CDN warmup

* fix(cloudflare): harden CDN warmup diagnostics

* fix(cloudflare): harden CDN warmup deploy flow

* fix(cloudflare): clarify CDN warmup trigger failures

* feat(cloudflare): warm cdn from build path manifest

* fix(cloudflare): emit warm paths for skip-build deploys

* fix(cloudflare): avoid stale skip-build path manifests

* test(cloudflare): lock skip-build prerender manifest gate

* fix(cloudflare): warm fallback deploy URL from triggers

* fix(cloudflare): clarify CDN warmup deploy logs

* feat(init): offer CDN warmup deploy script

* update wrangler configs

* fix(init): default CDN warmup to yes

* fix(cloudflare): explain first warm deploy failure

* fix(cloudflare): keep deploy errors concise

* fix(init): make generated home page cacheable
2026-07-04 16:09:55 +00:00
James Anderson 454dfbdf6b fix(cloudflare): populate kv cache from prerendered routes (#2509)
* fix(cloudflare): populate kv cache from prerendered routes

* fix(cloudflare): harden prerender kv population

* fix(cloudflare): match runtime app cache keys

* fix(cloudflare): clean prerender kv checks

* fix(cloudflare): align zero revalidate kv entries

* fix(cloudflare): tighten prerender kv deploy seeding

* fix(cloudflare): align toml env deploy parsing

* fix(cloudflare): cover toml deploy domain parsing

* fix(cloudflare): accept indented toml deploy fields

* fix(cloudflare): align json env domain precedence

* fix(cloudflare): upload prerender cache through wrangler

* fix(cloudflare): scope prerender kv upload to deploy
2026-07-04 15:52:01 +01:00
James Anderson 078073d75c fix(cloudflare): stream deploy logs (#2528) 2026-07-04 15:39:42 +01:00
James Anderson f22c962af8 refactor(cloudflare)!: remove vinext package coupling (#2527)
* refactor(cloudflare)!: remove vinext package coupling

* Review: PR #2527 breaks a test

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>

* test(cache): remove CDN auto-detection expectations

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
2026-07-04 15:29:45 +01:00
James Anderson 282698a77f fix(app-router): stop varying RSC responses by Accept (#2526) 2026-07-04 14:14:10 +00:00
James Anderson 5825c6807f fix(app-router): preserve client state during action revalidation (#2517)
* fix(app-router): preserve client state during action revalidation

* test(app-router): pin loading boundary to slot entry

* test(app-router): deploy action revalidation repro
2026-07-04 11:08:54 +01:00
Steve Faulkner 54497d42e7 fix: dev-server polish batch — HTML charset, client global polyfill, trailingSlash image endpoint (#2512)
* fix(pages): send charset=utf-8 on HTML Content-Type

Next.js serves every HTML response (SSR and prerendered) with
`Content-Type: text/html; charset=utf-8`, but vinext's Pages Router
paths sent a bare `text/html`. Without the header charset — and without
an early <meta charset> in the page — Chromium falls back to
windows-1252, so non-ASCII content renders as mojibake (e.g. nbsp as
'Â ') and the resulting DOM diverges from the hydrated tree, triggering
the full-screen hydration error overlay in dev. Reproduced against
nextjs-notion-starter-kit; baseline `next dev`/`next start` both send
the charset.

Append `; charset=utf-8` on every Pages Router HTML producer (the App
Router paths already send it):

- pages-page-response.ts — page render response headers + gSSP header
  merge
- dev-server.ts — streaming SSR, ISR HIT/STALE, and static-HTML dev
  responses
- pages-page-data.ts — ISR cache HIT/STALE responses in prod
- pages-request-pipeline.ts — the `defaultContentType` a buffering
  adapter applies when a render response carries no Content-Type
- static-file-cache.ts — `.html` static files (prerendered pages),
  matching Next.js static serving

Compression negotiation is unaffected: COMPRESSIBLE_TYPES matching
splits the media type on ";" before lookup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(client): polyfill `global` in browser bundles

Next.js exposes the Node-style `global` alias to client code: webpack
via its `node.global` runtime shim, Turbopack by compile-time rewriting
the free `global` identifier to its globalThis shortcut and folding
`typeof global` to "object" (turbopack-ecmascript references). vinext
provided nothing, so any client dependency that reads `global` (e.g.
use-dark-mode via nextjs-notion-starter-kit) threw
`ReferenceError: global is not defined` after hydration.

Add a `vinext:client-global-define` plugin that scopes
`define: { global: "globalThis" }` to the client environment:

- builds statically rewrite free `global` references (Turbopack-style)
- dev injects `"global": globalThis` into the client runtime defines
  (/@vite/env), assigning `globalThis.global` before user code runs
  (webpack-style)
- the same define is layered into the client dep optimizer
  (rolldownOptions.transform.define / esbuildOptions.define) because
  pre-bundled deps bypass the plugin transform pipeline

`typeof global` evaluates to "object" in the browser either way,
matching Next.js. Server environments are untouched — `global` remains
the real Node global — and a user-configured `compiler.define.global`
takes precedence, mirroring Turbopack's or_insert free-var semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(images): accept /_next/image/ with trailingSlash: true

With `trailingSlash: true`, the App Router dev handler 308-redirects
`/_next/image?url=...` to `/_next/image/?url=...` (the trailing-slash
normalizer runs before the image-endpoint check), but the image endpoint
only matched the exact `/_next/image` pathname — so the redirected
request 404'd and every dev-mode next/image request broke. Reproduced
on tailwind-nextjs-starter-blog, which ships trailingSlash: true.

Baseline Next 16.2.10 behaves the same way up to the redirect (dev with
trailingSlash: true also 308s `/_next/image` to `/_next/image/`) but
then SERVES the slashed form: its route matching strips a trailing
slash before matching internal paths (getItem in
packages/next/src/server/lib/router-utils/filesystem.ts), so image
requests never fail.

Match that: isImageOptimizationPath() now strips a single trailing
slash before comparing, which covers every caller — App Router
dev/prod (app-rsc-handler), Pages Router dev middleware, the Node prod
server, and the Cloudflare worker entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: align existing assertions with charset and trailing-slash fixes

Three assertions added on main after these fixes were authored still
asserted the old behavior: bare text/html Content-Type in
static-file-cache and the pages pipeline defaultContentType, and
isImageOptimizationPath rejecting the trailing-slash form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 00:46:29 +01:00
James Anderson e4aa03ac5c feat(create): add create-vinext-app (#2483)
* feat(create): add create-vinext-app

* fix(ci): support create package checks

* fix(create): address creator review findings

* fix(create): document version flag

* fix(ci): keep create-next-app cloudflare coverage

* fix(create): update init option test for cdn cache

* fix(create): bundle creator helper deps

* fix(ci): allow local vinext dlx deploy test

* fix(ci): run create-vinext-app deploy test from local tarballs

* fix(create): keep creator package self-contained

* fix(ci): preview release create-vinext-app

* fix(init): install runtime deps as app dependencies

* fix(create-vinext-app): scope workers copy to cloudflare

* fix(create-vinext-app): use pnpm in template examples

* fix(init): start cloudflare apps with wrangler
2026-07-03 17:51:49 +01:00
James Anderson c84f5d476b fix(check): mark cache components partially supported (#2507)
* fix(check): mark cache components unsupported

* fix(check): classify cache components as partial
2026-07-03 15:27:02 +00:00
Steve Faulkner 160645c6d3 fix(config): tsconfig paths — longest-prefix matching and stylesheet-scoped aliases (#2504)
* fix(config): match overlapping tsconfig paths by longest prefix

TypeScript (and Next.js) match compilerOptions.paths patterns by longest
matched prefix regardless of declaration order, but vinext materialized
them into Vite resolve.alias entries in declaration order, where the
alias plugin picks the first match. With overlapping patterns like
`"@/*": ["./src/*"]` + `"@/public/*": ["./public/*"]` (the
ixartz/Next-js-Boilerplate shape), `@/public/...` imports resolved into
src/public/ and every page 500'd.

Sort materialized aliases longest-prefix-first in both the plugin's
resolve.alias materialization and the next.config.ts loader's
runnerImport aliases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(config): keep tsconfig path aliases out of stylesheet resolution

TypeScript compilerOptions.paths never apply to CSS in Next.js —
@import specifiers in stylesheets use standard bundler resolution,
including package.json exports maps. vinext's materialized
resolve.alias entries also ran inside Vite's internal CSS resolver
(which only consults the alias plugin plus Vite's own resolver), so a
monorepo alias like `"@scope/ui/*": ["../../packages/ui/src/*"]`
rewrote `@import "@scope/ui/globals.css"` away from its
exports-mapped target and every route failed with a postcss ENOENT in
dev, and builds failed while analyzing client references
(create-better-t-stack scaffolds).

Emit the merged alias map as alias entries and attach a customResolver
to tsconfig-derived ones that bails out for stylesheet importers
(stylesheet file paths and the synthetic <basedir>/* importer that
postcss-import/less use), letting Vite resolve the original specifier
normally. JS/TS importers keep full alias behavior — including
`import "@/styles/globals.css"` from a layout and alias-based
import.meta.glob / dynamic-import patterns, which require blind prefix
replacement. Vite 8 reports alias customResolver as deprecated during
config resolution; the replacement it suggests (a resolveId plugin)
never runs inside the CSS resolver container, so the warning is
filtered while this remains the only importer-aware hook available.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:25:51 +01:00
James Anderson b5897d0595 feat(build): require Vite 8 (#2486)
* feat(build)!: require Vite 8

* fix(build): remove unused Vite version export

* test(link): harden prefetch timing assertions
2026-07-03 15:20:33 +01:00
James Anderson 9eed252701 fix(init): default to Workers Cache on Cloudflare (#2482)
* fix(init): default to Workers Cache on Cloudflare

* fix(init): prompt for Cloudflare CDN cache

* fix(init): prompt for missing CDN cache choice

* fix(init): add Cloudflare deploy script
2026-07-03 11:15:52 +01:00
Steve Faulkner b7455c3fa6 fix: fully elide inline type-only import specifiers (#2498)
Vite 8's OXC transform (and Vite 7's esbuild transform) honour
`"verbatimModuleSyntax": true` from the app's tsconfig, so
`import { type Metadata } from "next"` leaves a side-effect
`import "next"` behind when every specifier is type-only. Next.js
(SWC) — and esbuild/tsc without verbatimModuleSyntax — elide the whole
statement. create-t3-app and other scaffolds emit both the tsconfig
option and the inline-type import form stock, so on vinext the real
Next.js server runtime was pulled into the RSC graph (dev 500
"require is not defined", build failures via styled-jsx/client-only)
and server-only modules were pulled into the browser bundle when a
"use client" file imported only types from them (t3's tRPC router
shipped to clients and crashed hydration).

Force `typescript.onlyRemoveTypeImports: false` in the oxc transform
options (and `verbatimModuleSyntax: false` in the Vite 7 esbuild
tsconfigRaw) so type-import elision matches Next.js regardless of the
app's tsconfig.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 10:35:59 +01:00
James Anderson 5915c87116 fix(app-router): limit mounted slot cache variants (#2497) 2026-07-03 00:05:47 +01:00
James Anderson 336450ae47 fix(config): escape destination query params (#2494) 2026-07-03 00:00:45 +01:00
James Anderson e0db846716 fix(cloudflare): respect TPR cache opt-outs (#2493) 2026-07-02 23:38:48 +01:00
Nathan Nguyen a9a30a5c85 fix(app-router): omit pending RSC cache state for query renders (#2488)
Co-authored-by: James Anderson <james@eli.cx>
2026-07-02 22:46:53 +01:00
James Anderson 6c7b71eb12 fix(app-router): isolate global not-found css (#2444)
* fix(app-router): isolate global not-found css

* fix(app-router): cover global not-found css review gaps
2026-07-02 21:35:52 +01:00
James Anderson 8b122744ef fix(pages): align middleware data prefetch caching (#2451)
* fix(pages): align middleware data prefetch caching

* fix(pages): guard middleware prefetch data kind

* fix(dev): lazily classify pages data kind

* fix(pages): preserve legacy prefetch fallback

* fix(pages): reject unknown prefetch data kind
2026-07-02 21:33:32 +01:00
James Anderson 6bd1ee0153 fix(app-router): expose app rewrites to pages data clients (#2468) 2026-07-02 21:03:05 +01:00
James Anderson 5a90172a6b fix(pages): honor basePath false rewrites (#2442) 2026-07-02 21:01:24 +01:00
James Anderson e453928dda fix(app-router): publish committed no-prefetch navigations (#2469)
* fix(app-router): publish committed no-prefetch navigations

* fix(app-router): remove unreachable visited-cache fallback

* fix(app-router): replay committed no-prefetch cache payloads

* fix(app-router): remove dead committed cache guard
2026-07-02 20:58:48 +01:00
James Anderson 5343a3ff32 fix(app-router): cache segment prefetches by rendered search params (#2477)
* fix(app-router): cache segment prefetches by rendered search params

* fix(app-router): protect rendered prefetch alias header

* fix(app-router): repair segment prefetch merge
2026-07-02 19:42:46 +00:00
James Anderson 04a7ed3a10 fix(app-router): skip readiness waits for speculative prerenders (#2457)
* fix(app-router): skip readiness waits for speculative prerenders

* test(request-pipeline): assert speculative header stripping

* fix(app-router): keep speculative prerender shell errors throwable

* fix(app-router): capture speculative prerender cache metadata
2026-07-02 20:25:31 +01:00
James Anderson 5f8048f660 fix(app-router): align app static ISR lifecycle (#2472)
* fix(app-router): align app static ISR lifecycle

* fix(fetch-cache): honor shorter revalidate on hits

* fix(cache): honor read-time revalidate in KV cache
2026-07-02 20:19:02 +01:00
James Anderson 9e1866abb9 fix(pages): normalize data routes for trailing slash middleware (#2470)
* fix(pages): normalize data routes for trailing slash middleware

* fix(pages): gate data trailing slash normalization on middleware
2026-07-02 20:04:25 +01:00
James Anderson 1500fe61d7 fix(pages): align prerender functional parity (#2471)
* fix(pages): align prerender functional parity

* fix(pages): harden preview bypass comparison
2026-07-02 19:57:40 +01:00
James Anderson 239595e69e fix(app-router): reuse metadata rewrite prefetches (#2455)
* fix(app-router): reuse metadata rewrite prefetches

* fix(app-router): normalize rsc reference validation ids

* Revert "fix(app-router): normalize rsc reference validation ids"

This reverts commit bbff1eb13a.

* chore: format link shim
2026-07-01 17:02:35 +00:00
James Anderson ebf8e59289 fix(app-router): avoid runtime route-tree prefetch sizing (#2467)
* fix(app-router): start optimistic prefetches immediately

* fix(app-router): support route tree prefetch inlining

* fix(app-router): dedupe max prefetch inlining requests

* fix(app-router): cap route-tree prefetch size reads

* fix(app-router): avoid runtime route-tree prefetch sizing

* Fixed CI type error, flagged parity gap

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>

* fix(app-router): preserve negative prefetch inlining thresholds

* fix(app-router): normalize rsc reference validation ids

* Revert "fix(app-router): normalize rsc reference validation ids"

This reverts commit 68b96b596c.

* fix(app-router): keep route-tree prefetch metadata scoped

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
2026-07-01 17:47:08 +01:00
James Anderson 03f02177ec fix(app-router): start optimistic prefetches immediately (#2440)
* fix(app-router): start optimistic prefetches immediately

* fix(app-router): normalize rsc reference validation ids

* Revert "fix(app-router): normalize rsc reference validation ids"

This reverts commit 34a37658c2.
2026-07-01 16:45:35 +00:00
James Anderson 2256fdd53b fix(app-router): normalize rsc reference validation ids (#2480)
* fix(app-router): normalize rsc reference validation ids

* fix(app-router): scope rsc validation normalizer to dev
2026-07-01 14:30:22 +01:00
James Anderson 81e925eb66 fix(ci): harden perf publisher tree validation (#2478) 2026-07-01 13:39:20 +01:00
James Anderson 9ec793244e fix(app-router): send deployment id on RSC responses (#2452)
* fix(app-router): send deployment id on RSC responses

* test(app-router): isolate deployment id integration coverage
2026-07-01 11:27:22 +01:00
James Anderson 97cd5c3fb4 fix(app-router): separate header-only full-route rsc requests (#2445)
* fix(app-router): separate header-only full-route rsc requests

* test(app-router): assert header RSC redirect
2026-07-01 11:17:10 +01:00
James Anderson b0367f1448 fix(link): avoid reusing dynamic app route prefetches (#2450)
* fix(link): avoid reusing dynamic app route prefetches

* fix(link): preserve static dynamic app prefetches

* test(e2e): scope segment cache client params to prod
2026-07-01 11:14:11 +01:00
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 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