vinext 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +13 -10
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/output-root-externals.d.ts +21 -0
  13. package/dist/build/output-root-externals.js +40 -0
  14. package/dist/build/pages-client-assets-module.js +1 -1
  15. package/dist/build/prerender-paths.js +6 -3
  16. package/dist/build/prerender.js +1 -1
  17. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  18. package/dist/build/server-actions-encryption-key.js +101 -0
  19. package/dist/build/ssr-manifest.d.ts +3 -0
  20. package/dist/build/ssr-manifest.js +10 -1
  21. package/dist/check.js +5 -6
  22. package/dist/cli-dev-config.js +3 -3
  23. package/dist/cli.js +1 -1
  24. package/dist/client/client-rewrite-params.d.ts +9 -0
  25. package/dist/client/client-rewrite-params.js +20 -0
  26. package/dist/client/dev-error-overlay.js +2 -1
  27. package/dist/client/navigation-runtime.d.ts +25 -2
  28. package/dist/client/navigation-runtime.js +42 -11
  29. package/dist/client/vinext-next-data.d.ts +0 -1
  30. package/dist/config/config-matchers.d.ts +15 -40
  31. package/dist/config/config-matchers.js +195 -262
  32. package/dist/config/config-source.d.ts +34 -0
  33. package/dist/config/config-source.js +141 -0
  34. package/dist/config/header-params.d.ts +29 -0
  35. package/dist/config/header-params.js +106 -0
  36. package/dist/config/next-config.d.ts +7 -5
  37. package/dist/config/next-config.js +120 -7
  38. package/dist/entries/app-browser-entry.d.ts +14 -1
  39. package/dist/entries/app-browser-entry.js +26 -36
  40. package/dist/entries/app-rsc-entry.d.ts +2 -0
  41. package/dist/entries/app-rsc-entry.js +92 -57
  42. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  43. package/dist/entries/app-rsc-manifest.js +20 -1
  44. package/dist/entries/app-ssr-entry.d.ts +4 -1
  45. package/dist/entries/app-ssr-entry.js +9 -2
  46. package/dist/entries/pages-client-entry.d.ts +1 -0
  47. package/dist/entries/pages-client-entry.js +6 -6
  48. package/dist/entries/pages-server-entry.js +17 -14
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.js +350 -175
  51. package/dist/init.d.ts +1 -1
  52. package/dist/init.js +103 -6
  53. package/dist/plugins/ast-utils.d.ts +53 -2
  54. package/dist/plugins/ast-utils.js +90 -2
  55. package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
  56. package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
  57. package/dist/plugins/commonjs-esm-facade.js +2 -2
  58. package/dist/plugins/css-module-imports.js +13 -20
  59. package/dist/plugins/dynamic-preload-metadata.js +2 -3
  60. package/dist/plugins/extensionless-dynamic-import.js +2 -3
  61. package/dist/plugins/fonts.d.ts +1 -1
  62. package/dist/plugins/fonts.js +3 -3
  63. package/dist/plugins/ignore-dynamic-requests.js +2 -3
  64. package/dist/plugins/import-meta-url.js +3 -4
  65. package/dist/plugins/instrumentation-client.js +3 -2
  66. package/dist/plugins/middleware-export-validation.js +2 -3
  67. package/dist/plugins/og-harfbuzz.js +2 -3
  68. package/dist/plugins/optimize-imports.d.ts +25 -2
  69. package/dist/plugins/optimize-imports.js +109 -24
  70. package/dist/plugins/pages-node-externals.js +2 -3
  71. package/dist/plugins/remove-console.js +2 -18
  72. package/dist/plugins/require-condition-resolution.js +3 -3
  73. package/dist/plugins/require-context.js +2 -3
  74. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  75. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  76. package/dist/plugins/strip-server-exports.js +3 -4
  77. package/dist/plugins/styled-jsx.js +2 -3
  78. package/dist/plugins/use-cache-callable.d.ts +26 -2
  79. package/dist/plugins/use-cache-callable.js +101 -36
  80. package/dist/plugins/worker-image-imports.d.ts +1 -0
  81. package/dist/plugins/worker-image-imports.js +31 -34
  82. package/dist/plugins/worker-use-server.js +38 -14
  83. package/dist/routing/app-route-graph.d.ts +1 -1
  84. package/dist/routing/browser-route-manifest.d.ts +43 -0
  85. package/dist/routing/browser-route-manifest.js +195 -0
  86. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  87. package/dist/routing/hashed-route-patterns.js +22 -0
  88. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  89. package/dist/routing/optimistic-route-trie.js +102 -0
  90. package/dist/routing/route-validation.d.ts +6 -1
  91. package/dist/routing/route-validation.js +26 -10
  92. package/dist/server/api-handler.js +1 -1
  93. package/dist/server/app-action-forwarding.d.ts +8 -0
  94. package/dist/server/app-action-forwarding.js +17 -3
  95. package/dist/server/app-browser-entry.js +149 -62
  96. package/dist/server/app-browser-error.d.ts +3 -1
  97. package/dist/server/app-browser-error.js +7 -2
  98. package/dist/server/app-browser-interception-context.d.ts +2 -2
  99. package/dist/server/app-browser-interception-context.js +1 -1
  100. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  101. package/dist/server/app-browser-mpa-navigation.js +6 -5
  102. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  103. package/dist/server/app-browser-navigation-controller.js +88 -26
  104. package/dist/server/app-browser-prefetch-response.js +2 -2
  105. package/dist/server/app-browser-state.d.ts +2 -2
  106. package/dist/server/app-browser-state.js +1 -1
  107. package/dist/server/app-browser-supplemental-refresh.js +1 -1
  108. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  109. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  110. package/dist/server/app-client-reference-preloader.js +30 -7
  111. package/dist/server/app-fallback-renderer.js +2 -1
  112. package/dist/server/app-middleware.d.ts +6 -0
  113. package/dist/server/app-middleware.js +8 -10
  114. package/dist/server/app-optimistic-routing.d.ts +8 -10
  115. package/dist/server/app-optimistic-routing.js +4 -95
  116. package/dist/server/app-page-boundary-render.js +8 -1
  117. package/dist/server/app-page-cache-render.js +1 -0
  118. package/dist/server/app-page-dispatch.js +3 -1
  119. package/dist/server/app-page-render.js +4 -2
  120. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  121. package/dist/server/app-page-rsc-render-status.js +1 -0
  122. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  123. package/dist/server/app-page-search-params-observation.js +8 -10
  124. package/dist/server/app-page-stream.d.ts +7 -0
  125. package/dist/server/app-page-stream.js +1 -0
  126. package/dist/server/app-pages-bridge.d.ts +2 -1
  127. package/dist/server/app-pages-bridge.js +12 -8
  128. package/dist/server/app-prerender-endpoints.js +1 -1
  129. package/dist/server/app-prerender-static-params.js +3 -2
  130. package/dist/server/app-render-abort-error.d.ts +19 -0
  131. package/dist/server/app-render-abort-error.js +31 -1
  132. package/dist/server/app-render-dependency.js +42 -2
  133. package/dist/server/app-request-stage-independent-entry.js +7 -7
  134. package/dist/server/app-response-stage-entry.js +5 -5
  135. package/dist/server/app-route-handler-dispatch.js +3 -1
  136. package/dist/server/app-route-handler-execution.d.ts +2 -0
  137. package/dist/server/app-route-handler-execution.js +9 -2
  138. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  139. package/dist/server/app-route-handler-middleware-context.js +3 -3
  140. package/dist/server/app-route-handler-response.d.ts +2 -1
  141. package/dist/server/app-route-handler-response.js +2 -2
  142. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  143. package/dist/server/app-route-handler-runtime.js +21 -4
  144. package/dist/server/app-route-module-loader.js +7 -6
  145. package/dist/server/app-route-tree.d.ts +20 -0
  146. package/dist/server/app-route-tree.js +18 -0
  147. package/dist/server/app-router-entry.js +7 -7
  148. package/dist/server/app-rsc-cache-busting.d.ts +16 -0
  149. package/dist/server/app-rsc-cache-busting.js +29 -12
  150. package/dist/server/app-rsc-combined-handler.js +8 -1
  151. package/dist/server/app-rsc-errors.d.ts +7 -0
  152. package/dist/server/app-rsc-errors.js +9 -2
  153. package/dist/server/app-rsc-handler.d.ts +4 -1
  154. package/dist/server/app-rsc-handler.js +151 -135
  155. package/dist/server/app-rsc-request-normalization.js +3 -3
  156. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  157. package/dist/server/app-rsc-response-finalizer.js +4 -1
  158. package/dist/server/app-rsc-response-stage.js +5 -3
  159. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  160. package/dist/server/app-rsc-route-matching.js +1 -1
  161. package/dist/server/app-server-action-execution.d.ts +23 -6
  162. package/dist/server/app-server-action-execution.js +51 -57
  163. package/dist/server/app-ssr-entry.d.ts +6 -0
  164. package/dist/server/app-ssr-entry.js +21 -11
  165. package/dist/server/app-ssr-stream.d.ts +7 -0
  166. package/dist/server/app-ssr-stream.js +13 -1
  167. package/dist/server/app-visited-response-cache.js +2 -2
  168. package/dist/server/config-headers.js +13 -4
  169. package/dist/server/defer-until-stream-consumed.d.ts +2 -1
  170. package/dist/server/defer-until-stream-consumed.js +3 -1
  171. package/dist/server/dev-server.js +1 -1
  172. package/dist/server/image-optimization.js +1 -0
  173. package/dist/server/isolate-shared-promise.d.ts +10 -0
  174. package/dist/server/isolate-shared-promise.js +33 -0
  175. package/dist/server/isr-cache.js +3 -2
  176. package/dist/server/metadata-route-response.js +2 -2
  177. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  178. package/dist/server/middleware-matcher-pattern.js +11 -140
  179. package/dist/server/middleware-matcher.js +5 -6
  180. package/dist/server/middleware-response-headers.d.ts +31 -0
  181. package/dist/server/middleware-response-headers.js +57 -1
  182. package/dist/server/middleware-runtime.js +30 -17
  183. package/dist/server/navigation-planner.d.ts +2 -2
  184. package/dist/server/navigation-planner.js +1 -1
  185. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  186. package/dist/server/nitro-public-files-plugin.js +106 -0
  187. package/dist/server/nitro-public-files.d.ts +21 -0
  188. package/dist/server/nitro-public-files.js +39 -0
  189. package/dist/server/open-redirect.d.ts +11 -4
  190. package/dist/server/open-redirect.js +11 -4
  191. package/dist/server/pages-api-route.js +2 -2
  192. package/dist/server/pages-asset-tags.d.ts +5 -0
  193. package/dist/server/pages-asset-tags.js +9 -2
  194. package/dist/server/pages-client-assets.d.ts +4 -1
  195. package/dist/server/pages-data-route.js +2 -1
  196. package/dist/server/pages-i18n.d.ts +18 -0
  197. package/dist/server/pages-i18n.js +18 -2
  198. package/dist/server/pages-node-compat.d.ts +5 -3
  199. package/dist/server/pages-node-compat.js +35 -16
  200. package/dist/server/pages-page-data.js +1 -1
  201. package/dist/server/pages-page-handler.js +1 -1
  202. package/dist/server/pages-page-response.js +1 -1
  203. package/dist/server/pages-request-pipeline.d.ts +6 -1
  204. package/dist/server/pages-request-pipeline.js +35 -39
  205. package/dist/server/pages-request-stage-entry.js +20 -10
  206. package/dist/server/pages-response-stage-entry.js +1 -1
  207. package/dist/server/pages-revalidate.js +3 -2
  208. package/dist/server/pages-router-entry.js +2 -2
  209. package/dist/server/prod-server.d.ts +2 -2
  210. package/dist/server/prod-server.js +74 -36
  211. package/dist/server/proxy-trust.d.ts +6 -0
  212. package/dist/server/proxy-trust.js +12 -6
  213. package/dist/server/request-pipeline.d.ts +5 -0
  214. package/dist/server/request-pipeline.js +12 -1
  215. package/dist/server/rsc-stream-hints.d.ts +1 -1
  216. package/dist/server/rsc-stream-hints.js +21 -3
  217. package/dist/server/server-reference-loader.js +10 -1
  218. package/dist/server/static-file-cache.js +15 -3
  219. package/dist/server/worker-image-optimization.js +19 -6
  220. package/dist/server/worker-utils.js +1 -1
  221. package/dist/shims/cache-handler.js +3 -2
  222. package/dist/shims/cache-request-state.d.ts +40 -3
  223. package/dist/shims/cache-request-state.js +70 -5
  224. package/dist/shims/cache-runtime.js +47 -19
  225. package/dist/shims/cache.d.ts +2 -2
  226. package/dist/shims/cache.js +17 -8
  227. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  228. package/dist/shims/cdn-purge-routes.js +77 -0
  229. package/dist/shims/dynamic.js +17 -4
  230. package/dist/shims/form.js +8 -3
  231. package/dist/shims/head.js +1 -1
  232. package/dist/shims/headers.js +2 -2
  233. package/dist/shims/image-props.d.ts +93 -0
  234. package/dist/shims/image-props.js +323 -0
  235. package/dist/shims/image.d.ts +4 -18
  236. package/dist/shims/image.js +4 -319
  237. package/dist/shims/internal/headers-state.d.ts +7 -0
  238. package/dist/shims/internal/headers-state.js +14 -2
  239. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  240. package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
  241. package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
  242. package/dist/shims/link-prefetch.js +5 -4
  243. package/dist/shims/link.js +7 -5
  244. package/dist/shims/navigation.d.ts +1 -1
  245. package/dist/shims/navigation.js +21 -10
  246. package/dist/shims/og.js +35 -10
  247. package/dist/shims/request-context.d.ts +13 -0
  248. package/dist/shims/router.js +28 -52
  249. package/dist/shims/server.d.ts +42 -8
  250. package/dist/shims/server.js +99 -15
  251. package/dist/shims/thenable-params.d.ts +6 -1
  252. package/dist/shims/thenable-params.js +11 -2
  253. package/dist/shims/unified-request-context.d.ts +5 -0
  254. package/dist/shims/unified-request-context.js +2 -0
  255. package/dist/shims/url-utils.d.ts +7 -0
  256. package/dist/shims/url-utils.js +12 -3
  257. package/dist/utils/asset-prefix.d.ts +7 -0
  258. package/dist/utils/asset-prefix.js +10 -1
  259. package/dist/utils/client-build-manifest.js +12 -5
  260. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  261. package/dist/utils/client-runtime-metadata.js +15 -2
  262. package/dist/utils/domain-locale.js +1 -1
  263. package/dist/utils/lazy-chunks.d.ts +4 -0
  264. package/dist/utils/manifest-paths.d.ts +14 -0
  265. package/dist/utils/manifest-paths.js +22 -1
  266. package/dist/utils/path-to-regexp.d.ts +21 -0
  267. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  268. package/dist/utils/plugin-react-version.d.ts +15 -0
  269. package/dist/utils/plugin-react-version.js +64 -0
  270. package/dist/utils/plugin-rsc-version.d.ts +2 -0
  271. package/dist/utils/plugin-rsc-version.js +28 -2
  272. package/dist/utils/public-routes.d.ts +2 -0
  273. package/dist/utils/public-routes.js +18 -7
  274. package/dist/utils/react-version.d.ts +7 -0
  275. package/dist/utils/react-version.js +39 -16
  276. package/package.json +6 -6
  277. package/dist/build/nitro-route-rules.d.ts +0 -47
  278. package/dist/build/nitro-route-rules.js +0 -79
  279. package/dist/plugins/cache-flight-codec.d.ts +0 -19
  280. package/dist/plugins/cache-flight-codec.js +0 -68
  281. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  282. package/dist/utils/regex-safety.d.ts +0 -17
  283. package/dist/utils/regex-safety.js +0 -789
package/README.md CHANGED
@@ -232,6 +232,8 @@ The migration is non-destructive -- your existing Next.js setup continues to wor
232
232
 
233
233
  vinext targets Vite 8, which defaults to Rolldown, Oxc, Lightning CSS, and a newer browser baseline. If you bring custom Vite config or plugins from an older setup, prefer `oxc`, `optimizeDeps.rolldownOptions`, and `build.rolldownOptions` over older `esbuild` and `build.rollupOptions` knobs, and override `build.target` if you still need older browsers. If a dependency breaks because of stricter CommonJS default import handling, fix the import or use `legacy.inconsistentCjsInterop: true` as a temporary escape hatch. See the [Vite 8 migration guide](https://vite.dev/guide/migration).
234
234
 
235
+ Production client JS, Web Worker and CSS files use hash-only file names (by default `_next/static/chunks/[hash].js`, `_next/static/workers/<module-id>-[hash].js` and `_next/static/css/[hash].css`) so component and source file names don't appear in public asset URLs. Web Worker file names are fixed. To use different client JS and CSS names, set `entryFileNames`, `chunkFileNames` or `assetFileNames` in `build.rolldownOptions.output` (or `environments.client.build.rolldownOptions.output`), keeping them under the client assets directory: `_next/static/` by default, or `<prefix>/_next/static/` with a path-based `assetPrefix` such as `/cdn` (e.g. `chunkFileNames: "cdn/_next/static/chunks/[name]-[hash].js"`).
236
+
235
237
  ```bash
236
238
  npm run dev:vinext # Start the vinext dev server (port 3001)
237
239
  npm run build:vinext # Build production output with vinext
@@ -677,15 +679,16 @@ Every `next/*` import is shimmed to a Vite-compatible implementation.
677
679
 
678
680
  ### Configuration
679
681
 
680
- | Feature | | Notes |
681
- | ------------------------------------------------ | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
682
- | `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
683
- | `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation |
684
- | Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
685
- | `images` config | 🟡 | Parsed but not used for optimization |
686
- | `experimental.optimizePackageImports` | ✅ | Rewrites barrel imports to direct sub-module imports in RSC/SSR environments. A default set (lucide-react, date-fns, radix-ui, antd, MUI, and others) are always optimized. Add package names here to extend the list. |
687
- | `vinext({ nextConfig })` | ✅ | Inline Next-style config from `vite.config.*`. Supports object-form and function-form config. When provided, this overrides root `next.config.*`. |
688
- | `vinext({ react: { compiler: true } })` | ✅ | React Compiler auto memoization. Needs `@vitejs/plugin-react` 6.1+ and the optional `oxc-transform-react` package. |
682
+ | Feature | | Notes |
683
+ | ------------------------------------------------ | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
684
+ | `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
685
+ | `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation. A source Next.js rejects fails config loading, as it fails the Next.js build: missing, not starting with `/`, over the 4,096-character built-regex limit, or rejected by path-to-regexp, such as a header glob `/api/*` |
686
+ | Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
687
+ | `images` config | 🟡 | Parsed but not used for optimization |
688
+ | `experimental.optimizePackageImports` | ✅ | Rewrites barrel imports to direct sub-module imports in RSC/SSR environments. A default set (lucide-react, date-fns, radix-ui, antd, MUI, and others) are always optimized. Add package names here to extend the list. |
689
+ | `vinext({ nextConfig })` | ✅ | Inline Next-style config from `vite.config.*`. Supports object-form and function-form config. When provided, this overrides root `next.config.*`. |
690
+ | `vinext({ react: { compiler: true } })` | ✅ | React Compiler auto memoization. Needs `@vitejs/plugin-react` 6.1+ and the optional `oxc-transform-react` package. |
691
+ | `vinext({ disableNextLikeChunking: true })` | ✅ | Loads each client component from its own chunk, instead of one chunk per route group (Next.js-like; App Router production builds). Grouping also turns off on its own when the client build has other chunk groups. |
689
692
 
690
693
  ### React Compiler
691
694
 
@@ -1048,7 +1051,7 @@ Or add it to your `package.json` as a file dependency:
1048
1051
  }
1049
1052
  ```
1050
1053
 
1051
- vinext has peer dependencies on `react ^19.2.6`, `react-dom ^19.2.6`, `react-server-dom-webpack ^19.2.6`, and `vite ^8.0.0`. Then replace `next` with `vinext` in your scripts and run as normal.
1054
+ vinext has peer dependencies on `react ^19.3.1`, `react-dom ^19.3.1`, `react-server-dom-webpack ^19.3.1`, and `vite ^8.0.0`. Then replace `next` with `vinext` in your scripts and run as normal.
1052
1055
 
1053
1056
  ## Contributing
1054
1057
 
@@ -39,10 +39,62 @@ export declare function createClientAssetFileNames(assetsDir: string): (assetInf
39
39
  * and route-specific code stays in route chunks.
40
40
  */
41
41
  export declare function createClientManualChunks(shimsDir: string, preserveRouteBoundaries?: boolean): (id: string) => string | undefined;
42
- export declare function createClientFileNameConfig(assetsDir: string): {
43
- entryFileNames: string;
44
- chunkFileNames: string;
42
+ /**
43
+ * Web Worker output names. Workers are hash-only like client chunks, so their
44
+ * URLs don't publish source file names. Vite bundles each worker separately
45
+ * and stores the outputs by file name, so two workers' entries or chunks with
46
+ * identical code would share `[hash].js` and one's source map would overwrite
47
+ * the other's. Each name therefore also carries an opaque id derived from the
48
+ * chunk's module ids (root-relative for files).
49
+ */
50
+ export declare function createWorkerFileNames(assetsDir: string, root: string): {
51
+ entryFileNames: (chunk: {
52
+ facadeModuleId: string | null;
53
+ moduleIds?: readonly string[];
54
+ }) => string;
55
+ chunkFileNames: (chunk: {
56
+ facadeModuleId: string | null;
57
+ moduleIds?: readonly string[];
58
+ }) => string;
45
59
  };
60
+ /**
61
+ * vinext's client output file names, limited to the ones the incoming client
62
+ * environment config leaves unset. Vite merges `config` hook results over the
63
+ * user's config, so vinext applies these from `configEnvironment` instead: by
64
+ * then the user's top-level `build` and `environments.client.build` are merged
65
+ * into the client environment, and a user-provided pattern wins.
66
+ *
67
+ * Returns null for array-shaped output, which cannot be augmented without Vite
68
+ * concatenating a second output entry. Array-shaped client output is advanced
69
+ * config vinext doesn't support: Vite also appends vinext's own client output
70
+ * object (code splitting) to the user's array, producing an extra bundle.
71
+ */
72
+ export declare function createClientOutputFileNameDefaults(output: VinextBuildBundlerOptions["output"], assetsDir: string): {
73
+ entryFileNames?: string | undefined;
74
+ chunkFileNames?: string | undefined;
75
+ assetFileNames?: ((assetInfo: ClientAssetFileNameInfo) => string) | undefined;
76
+ } | null;
77
+ /** Entry, chunk and asset file names from a (non-array) bundler output config. */
78
+ export declare function getOutputFileNames(output: VinextBuildBundlerOptions["output"]): Pick<VinextBuildOutput, "entryFileNames" | "chunkFileNames" | "assetFileNames">;
79
+ /**
80
+ * User-provided client file name patterns vinext cannot serve correctly:
81
+ * - outside `assetsDir`: built-asset URLs, immutable caching and
82
+ * precompression all assume client output lives there;
83
+ * - without `[hash]`: everything under `assetsDir` is served
84
+ * `immutable`, so an unhashed URL would pin stale code for a year;
85
+ * - JS not ending in `.js`: client metadata and Pages Router script
86
+ * tags only recognize `.js` chunks;
87
+ * - assets not ending in `[extname]` (or `.[ext]`): CSS without its real
88
+ * extension is served as `application/octet-stream` and rejected by browsers.
89
+ * - asset basenames not starting with `[name].` or `[name]-`: restoring CSS
90
+ * `url()` assets deduplicated across builds swaps the source stem at the
91
+ * start of the emitted basename (see css-url-assets.ts), so any other
92
+ * placement or delimiter drops the hash from the restored sibling.
93
+ * This is a guard against common mistakes, not full validation: function
94
+ * patterns and array-shaped output are advanced config left to the user to
95
+ * keep within these rules.
96
+ */
97
+ export declare function findUnsupportedClientOutputFileNames(output: VinextBuildBundlerOptions["output"], assetsDir: string): string[];
46
98
  export declare function createClientCodeSplittingConfig(clientManualChunks: (id: string) => string | undefined): {
47
99
  minSize: number;
48
100
  groups: {
@@ -126,4 +178,13 @@ export declare function assertClientOutDirIsSeparate(root: string, dirs: {
126
178
  rscOutDir?: string;
127
179
  ssrOutDir?: string;
128
180
  }): void;
181
+ /**
182
+ * Whether client output options have chunk groups (`codeSplitting.groups`,
183
+ * `advancedChunks.groups` or `manualChunks`) other than vinext's own
184
+ * `ownGroups`, whether they came from the user or another plugin. vinext's
185
+ * client-reference route grouping is disabled in that case: a manual group can
186
+ * move modules out of a route group's chunk, and that combination has been
187
+ * seen to evaluate modules out of order and break hydration.
188
+ */
189
+ export declare function hasUserClientChunkGroups(output: unknown, ownGroups: ReadonlySet<unknown>): boolean;
129
190
  //#endregion
@@ -1,4 +1,7 @@
1
1
  import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
+ import { stripViteModuleQuery } from "../utils/path.js";
3
+ import { WORKER_IMAGE_METADATA_PREFIX } from "../plugins/worker-image-imports.js";
4
+ import { createHash } from "node:crypto";
2
5
  //#region src/build/client-build-config.ts
3
6
  const ROUTE_OWNED_CLIENT_SHIMS = /* @__PURE__ */ new Set([
4
7
  "app-router-tree-context",
@@ -7,6 +10,7 @@ const ROUTE_OWNED_CLIENT_SHIMS = /* @__PURE__ */ new Set([
7
10
  "dynamic-preload-chunks",
8
11
  "form",
9
12
  "image",
13
+ "image-props",
10
14
  "internal/hybrid-client-route-owner",
11
15
  "layout-segment-context",
12
16
  "legacy-image",
@@ -16,7 +20,7 @@ const ROUTE_OWNED_CLIENT_SHIMS = /* @__PURE__ */ new Set([
16
20
  "script",
17
21
  "web-vitals"
18
22
  ]);
19
- const NEXT_CLIENT_CSS_ASSET_FILE_NAMES = "css/[name].[hash:8][extname]";
23
+ const NEXT_CLIENT_CSS_ASSET_FILE_NAMES = "css/[hash][extname]";
20
24
  const NEXT_CLIENT_STATIC_MEDIA_FILE_NAMES = "media/[name].[hash:8][extname]";
21
25
  function joinAssetFileNamePattern(assetsDir, pattern) {
22
26
  let end = assetsDir.length;
@@ -110,13 +114,119 @@ function createClientManualChunks(shimsDir, preserveRouteBoundaries = false) {
110
114
  }
111
115
  };
112
116
  }
117
+ /**
118
+ * Client JS is emitted as hash-only `<assetsDir>/chunks/[hash].js`. Rolldown
119
+ * names a chunk after its first module, so `[name]` would publish component
120
+ * and source file names in public asset URLs. Next.js doesn't put component
121
+ * names in production chunk URLs either: webpack names split chunks by
122
+ * deterministic numeric id. Users can opt back into `[name]` through their own
123
+ * Vite config; see createClientOutputFileNameDefaults.
124
+ */
113
125
  function createClientFileNameConfig(assetsDir) {
114
126
  const chunksDir = `${assetsDir}/chunks`;
115
127
  return {
116
- entryFileNames: `${chunksDir}/[name]-[hash].js`,
117
- chunkFileNames: `${chunksDir}/[name]-[hash].js`
128
+ entryFileNames: `${chunksDir}/[hash].js`,
129
+ chunkFileNames: `${chunksDir}/[hash].js`
118
130
  };
119
131
  }
132
+ /**
133
+ * Web Worker output names. Workers are hash-only like client chunks, so their
134
+ * URLs don't publish source file names. Vite bundles each worker separately
135
+ * and stores the outputs by file name, so two workers' entries or chunks with
136
+ * identical code would share `[hash].js` and one's source map would overwrite
137
+ * the other's. Each name therefore also carries an opaque id derived from the
138
+ * chunk's module ids (root-relative for files).
139
+ */
140
+ function createWorkerFileNames(assetsDir, root) {
141
+ const workersDir = `${assetsDir}/workers`;
142
+ const fileName = (chunk) => {
143
+ const ids = chunk.facadeModuleId ? [chunk.facadeModuleId] : chunk.moduleIds ?? [];
144
+ const chunkId = JSON.stringify(ids.map((id) => {
145
+ const file = stripViteModuleQuery(id);
146
+ if (path.isAbsolute(file)) return ["file", toSlash(path.relative(root, file)) + id.slice(file.length)];
147
+ const imagePath = id.startsWith("\0vinext-worker-image-meta:") ? id.slice(WORKER_IMAGE_METADATA_PREFIX.length) : void 0;
148
+ if (imagePath !== void 0 && path.isAbsolute(imagePath)) return ["image-meta", toSlash(path.relative(root, imagePath))];
149
+ return ["id", id];
150
+ }));
151
+ const idHash = createHash("sha256").update(chunkId).digest("hex").slice(0, 8);
152
+ return `${workersDir}/${idHash}-[hash].js`;
153
+ };
154
+ return {
155
+ entryFileNames: fileName,
156
+ chunkFileNames: fileName
157
+ };
158
+ }
159
+ /**
160
+ * vinext's client output file names, limited to the ones the incoming client
161
+ * environment config leaves unset. Vite merges `config` hook results over the
162
+ * user's config, so vinext applies these from `configEnvironment` instead: by
163
+ * then the user's top-level `build` and `environments.client.build` are merged
164
+ * into the client environment, and a user-provided pattern wins.
165
+ *
166
+ * Returns null for array-shaped output, which cannot be augmented without Vite
167
+ * concatenating a second output entry. Array-shaped client output is advanced
168
+ * config vinext doesn't support: Vite also appends vinext's own client output
169
+ * object (code splitting) to the user's array, producing an extra bundle.
170
+ */
171
+ function createClientOutputFileNameDefaults(output, assetsDir) {
172
+ if (Array.isArray(output)) return null;
173
+ const configured = output ?? {};
174
+ const { entryFileNames, chunkFileNames } = createClientFileNameConfig(assetsDir);
175
+ return {
176
+ ...configured.entryFileNames === void 0 ? { entryFileNames } : {},
177
+ ...configured.chunkFileNames === void 0 ? { chunkFileNames } : {},
178
+ ...configured.assetFileNames === void 0 ? { assetFileNames: createClientAssetFileNames(assetsDir) } : {}
179
+ };
180
+ }
181
+ /** Entry, chunk and asset file names from a (non-array) bundler output config. */
182
+ function getOutputFileNames(output) {
183
+ if (!output || Array.isArray(output)) return {};
184
+ const { entryFileNames, chunkFileNames, assetFileNames } = output;
185
+ return {
186
+ entryFileNames,
187
+ chunkFileNames,
188
+ assetFileNames
189
+ };
190
+ }
191
+ /**
192
+ * User-provided client file name patterns vinext cannot serve correctly:
193
+ * - outside `assetsDir`: built-asset URLs, immutable caching and
194
+ * precompression all assume client output lives there;
195
+ * - without `[hash]`: everything under `assetsDir` is served
196
+ * `immutable`, so an unhashed URL would pin stale code for a year;
197
+ * - JS not ending in `.js`: client metadata and Pages Router script
198
+ * tags only recognize `.js` chunks;
199
+ * - assets not ending in `[extname]` (or `.[ext]`): CSS without its real
200
+ * extension is served as `application/octet-stream` and rejected by browsers.
201
+ * - asset basenames not starting with `[name].` or `[name]-`: restoring CSS
202
+ * `url()` assets deduplicated across builds swaps the source stem at the
203
+ * start of the emitted basename (see css-url-assets.ts), so any other
204
+ * placement or delimiter drops the hash from the restored sibling.
205
+ * This is a guard against common mistakes, not full validation: function
206
+ * patterns and array-shaped output are advanced config left to the user to
207
+ * keep within these rules.
208
+ */
209
+ function findUnsupportedClientOutputFileNames(output, assetsDir) {
210
+ if (!output || Array.isArray(output)) return [];
211
+ const unsupported = [];
212
+ for (const key of [
213
+ "entryFileNames",
214
+ "chunkFileNames",
215
+ "assetFileNames"
216
+ ]) {
217
+ const value = output[key];
218
+ if (typeof value !== "string") continue;
219
+ const problems = [
220
+ !value.startsWith(`${assetsDir}/`) && `outside "${assetsDir}/"`,
221
+ !value.includes("[hash") && "no [hash]",
222
+ key !== "assetFileNames" && !value.endsWith(".js") && "not \".js\"",
223
+ key === "assetFileNames" && !value.endsWith("[extname]") && !value.endsWith(".[ext]") && "not ending in [extname]",
224
+ key === "assetFileNames" && !/^\[name\][.-]/.test(value.slice(value.lastIndexOf("/") + 1)) && "basename not starting with \"[name].\" or \"[name]-\""
225
+ ].filter(Boolean);
226
+ if (problems.length > 0) unsupported.push(`${key}: ${JSON.stringify(value)} (${problems.join(", ")})`);
227
+ }
228
+ return unsupported;
229
+ }
120
230
  function createClientCodeSplittingConfig(clientManualChunks) {
121
231
  return {
122
232
  minSize: 1e4,
@@ -282,5 +392,22 @@ function assertClientOutDirIsSeparate(root, dirs) {
282
392
  throw new Error(`[vinext] clientOutDir "${dirs.clientOutDir}" contains ${name} "${dir}". The client build runs last and empties its output directory, which would delete the server build. Use separate output directories.`);
283
393
  }
284
394
  }
395
+ function hasChunkGroups(output, ownGroups) {
396
+ if (!output || typeof output !== "object") return false;
397
+ const { advancedChunks, codeSplitting, manualChunks } = output;
398
+ if (manualChunks !== void 0) return true;
399
+ return [...advancedChunks?.groups ?? [], ...(codeSplitting && typeof codeSplitting === "object" ? codeSplitting.groups : void 0) ?? []].some((group) => !ownGroups.has(group));
400
+ }
401
+ /**
402
+ * Whether client output options have chunk groups (`codeSplitting.groups`,
403
+ * `advancedChunks.groups` or `manualChunks`) other than vinext's own
404
+ * `ownGroups`, whether they came from the user or another plugin. vinext's
405
+ * client-reference route grouping is disabled in that case: a manual group can
406
+ * move modules out of a route group's chunk, and that combination has been
407
+ * seen to evaluate modules out of order and break hydration.
408
+ */
409
+ function hasUserClientChunkGroups(output, ownGroups) {
410
+ return Array.isArray(output) ? output.some((entry) => hasChunkGroups(entry, ownGroups)) : hasChunkGroups(output, ownGroups);
411
+ }
285
412
  //#endregion
286
- export { RSC_FRAMEWORK_CHUNK_TEST, assertClientOutDirIsSeparate, createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createMultiStageChunkFileNames, createMultiStageCodeSplittingConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfig, isRscFrameworkModule, sanitizeRscChunkFileName, withBuildBundlerOptions };
413
+ export { RSC_FRAMEWORK_CHUNK_TEST, assertClientOutDirIsSeparate, createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputFileNameDefaults, createMultiStageChunkFileNames, createMultiStageCodeSplittingConfig, createRscFrameworkChunkOutputConfig, createWorkerFileNames, findUnsupportedClientOutputFileNames, getBuildBundlerOptions, getClientTreeshakeConfig, getOutputFileNames, hasUserClientChunkGroups, isRscFrameworkModule, sanitizeRscChunkFileName, withBuildBundlerOptions };
@@ -0,0 +1,163 @@
1
+ import { actionOwnerRouteEntryIds } from "./action-owner-manifest.js";
2
+ import { Rollup } from "vite";
3
+ //#region src/build/client-reference-groups.d.ts
4
+ /**
5
+ * Client references whose estimated group cost (see
6
+ * {@link measureClientReferenceGroupCosts}) is larger than this many
7
+ * transformed source bytes keep their own lazy chunk instead of joining a route
8
+ * group. Grouping makes every member load with the group, so a heavy component
9
+ * that a route can reach but rarely renders must not be pulled into that
10
+ * route's startup bundle.
11
+ */
12
+ export declare const CLIENT_REFERENCE_GROUP_MAX_COST_BYTES: number;
13
+ type ClientReferenceGroupRoute = Parameters<typeof actionOwnerRouteEntryIds>[0];
14
+ type ModuleGraphInfo = Pick<Rollup.ModuleInfo, "dynamicallyImportedIds" | "importedIds">;
15
+ /**
16
+ * Map each client reference reachable from App Router route files to a
17
+ * signature naming the owners that reach it. A route owns its page, layouts,
18
+ * templates, boundaries and parallel slots, which render with it. Intercepting
19
+ * routes (which only render on soft navigation), global-error and
20
+ * global-not-found render on their own, so each is owned by its file, named by
21
+ * its path relative to `root`. References with the same signature are needed
22
+ * together, mirroring Next.js' per-route client entries. The map is in the
23
+ * order a depth-first walk in import order first reaches each reference from
24
+ * the route files in render order, which follows ES module evaluation order.
25
+ *
26
+ * References reachable from no route file (for example vinext's internal
27
+ * runtime references) are omitted and keep their own lazy chunk. So are
28
+ * references that route code reaches through a dynamic import (`next/dynamic`,
29
+ * `React.lazy`), directly or through the dynamically imported module's graph.
30
+ */
31
+ export declare function collectClientReferenceRouteSignatures(options: {
32
+ canonicalizeModuleId?: (id: string) => string;
33
+ clientReferenceIds: ReadonlySet<string>;
34
+ getModuleInfo: (id: string) => ModuleGraphInfo | null;
35
+ root: string;
36
+ routes: readonly ClientReferenceGroupRoute[];
37
+ sharedRoots?: readonly string[];
38
+ }): Map<string, string>;
39
+ export type ClientReferencePreloadPlan = {
40
+ /**
41
+ * Client references any render may use: those reached from outside route
42
+ * files (vinext's runtime, server actions), those of `alwaysRoots`
43
+ * (global-error, the root boundaries), and those no walk reaches.
44
+ */
45
+ always: string[];
46
+ /** The client references each route file reaches, through any import. */
47
+ files: string[][];
48
+ /** Each route pattern's files, as indices into `files`. */
49
+ routes: Map<string, number[]>;
50
+ /** The files of a render without a route, as indices into `files`. */
51
+ routeless: number[];
52
+ };
53
+ /**
54
+ * Plan which client references SSR loads before rendering each route. A route
55
+ * preloads every client reference its page, layouts, templates, boundaries and
56
+ * parallel slots reach, statically or through dynamic imports (a
57
+ * `next/dynamic` component renders on the server), plus the `always` set.
58
+ * Intercepting routes only render on soft navigation, which SSR never
59
+ * renders, so they add to no set. `entryIds` are the RSC graph's entries:
60
+ * walking them up to route files finds what renders outside any route.
61
+ */
62
+ export declare function collectClientReferencePreloadPlan(options: {
63
+ alwaysRoots?: readonly string[];
64
+ canonicalizeModuleId?: (id: string) => string;
65
+ clientReferenceIds: ReadonlySet<string>;
66
+ entryIds: readonly string[];
67
+ getModuleInfo: (id: string) => ModuleGraphInfo | null;
68
+ routelessFiles?: readonly string[];
69
+ routes: readonly ClientReferenceGroupRoute[];
70
+ }): ClientReferencePreloadPlan;
71
+ /** Export names an importer uses from a module, or `"*"` for all of them. */
72
+ type UsedNames = ReadonlySet<string> | "*";
73
+ type ModuleBindings = {
74
+ /** Transformed source bytes, not counting import and export-list statements. */
75
+ bytes: number;
76
+ /** Static imports, with the names each one uses. */
77
+ imports: ReadonlyArray<{
78
+ id: string;
79
+ names: UsedNames;
80
+ }>;
81
+ /**
82
+ * Re-exports: `export { a as b } from`, `export * from` (`exportName` and
83
+ * `importName` are `"*"`), `export * as ns from` (`importName` is `"*"`), and
84
+ * imported bindings that the module only re-exports.
85
+ */
86
+ reexports: ReadonlyArray<{
87
+ id: string;
88
+ exportName: string;
89
+ importName: string;
90
+ }>;
91
+ };
92
+ type LoadedModule = {
93
+ code: string | null;
94
+ importedIds: readonly string[];
95
+ /**
96
+ * Without bindings, every static import of the module counts in full. With
97
+ * them, a side-effect-free module's re-exports only count for the names its
98
+ * importers use, as tree-shaking would keep them.
99
+ */
100
+ bindings?: ModuleBindings;
101
+ };
102
+ /**
103
+ * Read a module's static imports and re-exports for
104
+ * {@link measureClientReferenceGroupCosts}. Returns undefined when the code does
105
+ * not parse or a specifier does not resolve to one of `importedIds`.
106
+ */
107
+ export declare function readClientModuleBindings(options: {
108
+ code: string;
109
+ importedIds: readonly string[];
110
+ resolve: (specifier: string) => Promise<string | null>;
111
+ }): Promise<ModuleBindings | undefined>;
112
+ /**
113
+ * Estimate, in transformed source bytes, how much code each client reference
114
+ * would add to a route group's chunk: the modules only it uses, plus the cost
115
+ * of every client reference it statically imports (grouping a reference pulls
116
+ * those along). Modules shared with other client references are not charged
117
+ * to any one of them, so shared libraries do not block grouping. With
118
+ * {@link readClientModuleBindings}, a side-effect-free module only charges the
119
+ * re-exports that are imported from it, so a reference that imports one icon
120
+ * from a barrel is not charged for the whole library.
121
+ *
122
+ * `references` maps each client reference id to its module id in the client
123
+ * graph. `isSideEffectFree` reports a module's package `sideEffects` flag as
124
+ * the bundler resolved it. Traversal stops at modules for which `isExcluded`
125
+ * returns true (CSS, always-loaded framework chunks, virtual modules that must
126
+ * not be loaded re-entrantly). A reference whose import graph cannot be fully
127
+ * loaded is reported as `null` so callers keep it out of groups.
128
+ */
129
+ export declare function measureClientReferenceGroupCosts(options: {
130
+ references: ReadonlyMap<string, string>;
131
+ loadModule: (id: string) => Promise<LoadedModule>;
132
+ isExcluded: (id: string) => boolean;
133
+ /**
134
+ * Whether a module has no side effects. A side-effect-free module is not
135
+ * loaded until a reference uses one of its exports.
136
+ */
137
+ isSideEffectFree: (id: string) => boolean;
138
+ }): Promise<Map<string, number | null>>;
139
+ export type ClientReferenceGroup = {
140
+ /** Stable, filename-safe identifier derived from the route signature. */
141
+ key: string;
142
+ /**
143
+ * Member client reference ids in signature (route walk) order, which sets
144
+ * module evaluation and CSS order inside the group chunk.
145
+ */
146
+ referenceIds: string[];
147
+ };
148
+ /**
149
+ * Group client references that share a route signature. References without a
150
+ * signature, references whose cost is unknown or above `maxCostBytes`, and
151
+ * signatures with a single member stay ungrouped. Group keys derive from the
152
+ * members' `referenceKeys`, so a group keeps its chunk name when routes change
153
+ * but its members do not.
154
+ */
155
+ export declare function planClientReferenceGroups(options: {
156
+ referenceIds: ReadonlySet<string>;
157
+ /** Stable, machine-independent key of each client reference. */
158
+ referenceKeys: ReadonlyMap<string, string>;
159
+ signatures: ReadonlyMap<string, string>;
160
+ costs: ReadonlyMap<string, number | null>;
161
+ maxCostBytes: number;
162
+ }): ClientReferenceGroup[];
163
+ //#endregion