vinext 1.2.1 → 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.
- package/README.md +12 -9
- package/dist/build/client-build-config.d.ts +64 -3
- package/dist/build/client-build-config.js +131 -4
- package/dist/build/client-reference-groups.d.ts +163 -0
- package/dist/build/client-reference-groups.js +534 -0
- package/dist/build/module-dependency-cache.d.ts +31 -0
- package/dist/build/module-dependency-cache.js +51 -1
- package/dist/build/next-client-runtime-manifests.d.ts +10 -1
- package/dist/build/next-client-runtime-manifests.js +19 -4
- package/dist/build/nitro-public-files.d.ts +24 -0
- package/dist/build/nitro-public-files.js +60 -0
- package/dist/build/pages-client-assets-module.js +1 -1
- package/dist/build/prerender-paths.js +5 -2
- package/dist/build/server-actions-encryption-key.d.ts +23 -0
- package/dist/build/server-actions-encryption-key.js +101 -0
- package/dist/build/ssr-manifest.d.ts +3 -0
- package/dist/build/ssr-manifest.js +10 -1
- package/dist/client/client-rewrite-params.d.ts +9 -0
- package/dist/client/client-rewrite-params.js +20 -0
- package/dist/client/dev-error-overlay.js +2 -1
- package/dist/client/navigation-runtime.d.ts +25 -2
- package/dist/client/navigation-runtime.js +42 -11
- package/dist/client/vinext-next-data.d.ts +0 -1
- package/dist/config/config-matchers.d.ts +15 -40
- package/dist/config/config-matchers.js +183 -255
- package/dist/config/config-source.d.ts +34 -0
- package/dist/config/config-source.js +141 -0
- package/dist/config/header-params.d.ts +29 -0
- package/dist/config/header-params.js +106 -0
- package/dist/config/next-config.d.ts +7 -5
- package/dist/config/next-config.js +120 -7
- package/dist/entries/app-browser-entry.d.ts +14 -1
- package/dist/entries/app-browser-entry.js +26 -36
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +92 -57
- package/dist/entries/app-rsc-manifest.d.ts +10 -0
- package/dist/entries/app-rsc-manifest.js +20 -1
- package/dist/entries/app-ssr-entry.d.ts +4 -1
- package/dist/entries/app-ssr-entry.js +9 -2
- package/dist/entries/pages-client-entry.d.ts +1 -0
- package/dist/entries/pages-client-entry.js +6 -6
- package/dist/entries/pages-server-entry.js +17 -14
- package/dist/index.d.ts +11 -0
- package/dist/index.js +239 -83
- package/dist/init.js +17 -0
- package/dist/plugins/optimize-imports.d.ts +25 -2
- package/dist/plugins/optimize-imports.js +106 -20
- package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
- package/dist/plugins/rsc-client-reference-loaders.js +336 -18
- package/dist/plugins/use-cache-callable.d.ts +5 -0
- package/dist/plugins/use-cache-callable.js +30 -8
- package/dist/plugins/worker-image-imports.d.ts +1 -0
- package/dist/plugins/worker-image-imports.js +1 -1
- package/dist/routing/app-route-graph.d.ts +1 -1
- package/dist/routing/browser-route-manifest.d.ts +43 -0
- package/dist/routing/browser-route-manifest.js +195 -0
- package/dist/routing/hashed-route-patterns.d.ts +4 -0
- package/dist/routing/hashed-route-patterns.js +22 -0
- package/dist/routing/optimistic-route-trie.d.ts +27 -0
- package/dist/routing/optimistic-route-trie.js +102 -0
- package/dist/routing/route-validation.d.ts +6 -1
- package/dist/routing/route-validation.js +26 -10
- package/dist/server/app-action-forwarding.d.ts +8 -0
- package/dist/server/app-action-forwarding.js +15 -1
- package/dist/server/app-browser-entry.js +147 -60
- package/dist/server/app-browser-error.d.ts +3 -1
- package/dist/server/app-browser-error.js +7 -2
- package/dist/server/app-browser-interception-context.d.ts +2 -2
- package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
- package/dist/server/app-browser-mpa-navigation.js +6 -5
- package/dist/server/app-browser-navigation-controller.d.ts +17 -6
- package/dist/server/app-browser-navigation-controller.js +88 -26
- package/dist/server/app-browser-state.d.ts +2 -2
- package/dist/server/app-browser-visible-commit.d.ts +4 -4
- package/dist/server/app-client-reference-preloader.d.ts +23 -0
- package/dist/server/app-client-reference-preloader.js +30 -7
- package/dist/server/app-fallback-renderer.js +2 -1
- package/dist/server/app-middleware.d.ts +6 -0
- package/dist/server/app-middleware.js +8 -10
- package/dist/server/app-optimistic-routing.d.ts +8 -10
- package/dist/server/app-optimistic-routing.js +4 -95
- package/dist/server/app-page-boundary-render.js +8 -1
- package/dist/server/app-page-cache-render.js +1 -0
- package/dist/server/app-page-dispatch.js +2 -0
- package/dist/server/app-page-render.js +3 -1
- package/dist/server/app-page-rsc-render-status.d.ts +1 -0
- package/dist/server/app-page-rsc-render-status.js +1 -0
- package/dist/server/app-page-search-params-observation.d.ts +1 -4
- package/dist/server/app-page-search-params-observation.js +8 -10
- package/dist/server/app-page-stream.d.ts +7 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +11 -7
- package/dist/server/app-prerender-static-params.js +3 -2
- package/dist/server/app-render-dependency.js +42 -2
- package/dist/server/app-request-stage-independent-entry.js +2 -2
- package/dist/server/app-response-stage-entry.js +3 -3
- package/dist/server/app-route-handler-dispatch.js +3 -1
- package/dist/server/app-route-handler-execution.d.ts +2 -0
- package/dist/server/app-route-handler-execution.js +9 -2
- package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
- package/dist/server/app-route-handler-middleware-context.js +3 -3
- package/dist/server/app-route-handler-response.d.ts +2 -1
- package/dist/server/app-route-handler-response.js +2 -2
- package/dist/server/app-route-handler-runtime.d.ts +2 -0
- package/dist/server/app-route-handler-runtime.js +20 -3
- package/dist/server/app-route-module-loader.js +7 -6
- package/dist/server/app-route-tree.d.ts +20 -0
- package/dist/server/app-route-tree.js +18 -0
- package/dist/server/app-router-entry.js +2 -2
- package/dist/server/app-rsc-combined-handler.js +8 -1
- package/dist/server/app-rsc-errors.d.ts +7 -0
- package/dist/server/app-rsc-errors.js +9 -2
- package/dist/server/app-rsc-handler.d.ts +4 -1
- package/dist/server/app-rsc-handler.js +146 -130
- package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
- package/dist/server/app-rsc-response-finalizer.js +4 -1
- package/dist/server/app-rsc-response-stage.js +3 -1
- package/dist/server/app-rsc-route-matching.d.ts +1 -0
- package/dist/server/app-rsc-route-matching.js +1 -1
- package/dist/server/app-server-action-execution.d.ts +23 -6
- package/dist/server/app-server-action-execution.js +50 -56
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +16 -7
- package/dist/server/app-ssr-stream.d.ts +7 -0
- package/dist/server/app-ssr-stream.js +13 -1
- package/dist/server/config-headers.js +12 -3
- package/dist/server/isolate-shared-promise.d.ts +10 -0
- package/dist/server/isolate-shared-promise.js +33 -0
- package/dist/server/isr-cache.js +3 -2
- package/dist/server/middleware-matcher-pattern.d.ts +0 -1
- package/dist/server/middleware-matcher-pattern.js +11 -140
- package/dist/server/middleware-matcher.js +5 -6
- package/dist/server/middleware-response-headers.d.ts +31 -0
- package/dist/server/middleware-response-headers.js +57 -1
- package/dist/server/middleware-runtime.js +26 -13
- package/dist/server/navigation-planner.d.ts +2 -2
- package/dist/server/nitro-public-files-plugin.d.ts +38 -0
- package/dist/server/nitro-public-files-plugin.js +106 -0
- package/dist/server/nitro-public-files.d.ts +21 -0
- package/dist/server/nitro-public-files.js +39 -0
- package/dist/server/pages-asset-tags.d.ts +5 -0
- package/dist/server/pages-asset-tags.js +9 -2
- package/dist/server/pages-client-assets.d.ts +4 -1
- package/dist/server/pages-i18n.d.ts +18 -0
- package/dist/server/pages-i18n.js +18 -2
- package/dist/server/pages-node-compat.d.ts +5 -3
- package/dist/server/pages-node-compat.js +35 -16
- package/dist/server/pages-request-pipeline.d.ts +6 -1
- package/dist/server/pages-request-pipeline.js +31 -35
- package/dist/server/pages-request-stage-entry.js +16 -6
- package/dist/server/pages-response-stage-entry.js +1 -1
- package/dist/server/pages-revalidate.js +1 -0
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +71 -33
- package/dist/server/proxy-trust.d.ts +6 -0
- package/dist/server/proxy-trust.js +12 -6
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +12 -1
- package/dist/server/server-reference-loader.js +10 -1
- package/dist/server/static-file-cache.js +15 -3
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/cache-handler.js +3 -2
- package/dist/shims/cache-request-state.d.ts +40 -3
- package/dist/shims/cache-request-state.js +70 -5
- package/dist/shims/cache-runtime.js +47 -19
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +17 -8
- package/dist/shims/cdn-purge-routes.d.ts +24 -0
- package/dist/shims/cdn-purge-routes.js +77 -0
- package/dist/shims/dynamic.js +17 -4
- package/dist/shims/form.js +8 -3
- package/dist/shims/image-props.d.ts +93 -0
- package/dist/shims/image-props.js +323 -0
- package/dist/shims/image.d.ts +4 -18
- package/dist/shims/image.js +4 -319
- package/dist/shims/internal/headers-state.d.ts +7 -0
- package/dist/shims/internal/headers-state.js +14 -2
- package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +31 -14
- package/dist/shims/internal/hybrid-client-route-owner.js +8 -8
- package/dist/shims/link.js +5 -3
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.js +17 -5
- package/dist/shims/og.js +35 -10
- package/dist/shims/request-context.d.ts +13 -0
- package/dist/shims/router.js +19 -40
- package/dist/shims/server.d.ts +31 -4
- package/dist/shims/server.js +58 -10
- package/dist/shims/thenable-params.d.ts +6 -1
- package/dist/shims/thenable-params.js +11 -2
- package/dist/shims/unified-request-context.d.ts +5 -0
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/utils/asset-prefix.d.ts +7 -0
- package/dist/utils/asset-prefix.js +10 -1
- package/dist/utils/client-build-manifest.js +12 -5
- package/dist/utils/client-runtime-metadata.d.ts +1 -0
- package/dist/utils/client-runtime-metadata.js +15 -2
- package/dist/utils/lazy-chunks.d.ts +4 -0
- package/dist/utils/manifest-paths.d.ts +14 -0
- package/dist/utils/manifest-paths.js +22 -1
- package/dist/utils/path-to-regexp.d.ts +21 -0
- package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
- package/dist/utils/plugin-react-version.d.ts +15 -0
- package/dist/utils/plugin-react-version.js +64 -0
- package/dist/utils/public-routes.d.ts +2 -0
- package/dist/utils/public-routes.js +18 -7
- package/package.json +1 -1
- package/dist/server/middleware-path-to-regexp.d.ts +0 -13
- package/dist/utils/regex-safety.d.ts +0 -17
- 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
|
|
|
@@ -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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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/[
|
|
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}/[
|
|
117
|
-
chunkFileNames: `${chunksDir}/[
|
|
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,
|
|
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
|