vinext 0.1.0 → 0.1.2
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 +2 -5
- package/dist/build/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +33 -1
- package/dist/build/client-build-config.js +66 -1
- package/dist/check.js +4 -3
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +11 -2
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +31 -5
- package/dist/config/config-matchers.js +50 -3
- package/dist/config/next-config.d.ts +29 -3
- package/dist/config/next-config.js +32 -2
- package/dist/deploy.js +47 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +61 -5
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +16 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +233 -280
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +35 -2
- package/dist/routing/app-route-graph.js +179 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +155 -215
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +13 -2
- package/dist/server/app-browser-navigation-controller.js +83 -4
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +10 -10
- package/dist/server/app-browser-visible-commit.js +10 -8
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +45 -21
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +14 -0
- package/dist/server/app-page-dispatch.js +21 -6
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +58 -17
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +11 -16
- package/dist/server/app-page-request.d.ts +9 -6
- package/dist/server/app-page-request.js +14 -10
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +10 -8
- package/dist/server/app-page-stream.d.ts +37 -7
- package/dist/server/app-page-stream.js +36 -6
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +15 -3
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +5 -4
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +22 -1
- package/dist/server/app-server-action-execution.js +73 -12
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +19 -3
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +97 -43
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +62 -1
- package/dist/server/navigation-planner.js +193 -3
- package/dist/server/navigation-trace.d.ts +12 -2
- package/dist/server/navigation-trace.js +11 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +5 -11
- package/dist/server/pages-node-compat.js +175 -118
- package/dist/server/pages-page-data.d.ts +38 -7
- package/dist/server/pages-page-data.js +64 -18
- package/dist/server/pages-page-handler.d.ts +10 -2
- package/dist/server/pages-page-handler.js +49 -20
- package/dist/server/pages-page-response.d.ts +55 -2
- package/dist/server/pages-page-response.js +74 -6
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +113 -0
- package/dist/server/pages-request-pipeline.js +230 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +45 -3
- package/dist/server/prod-server.js +182 -234
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +39 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +17 -7
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +28 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +9 -18
- package/dist/shims/navigation.js +96 -23
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +156 -22
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +41 -6
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -528,22 +528,19 @@ The cache is pluggable. The default `MemoryCacheHandler` works out of the box. S
|
|
|
528
528
|
|
|
529
529
|
#### Configuring cache adapters from `vite.config`
|
|
530
530
|
|
|
531
|
-
Instead of wiring up cache handlers imperatively from a worker entry, you can declare them in the `vinext()` plugin config. The `@vinext/cloudflare` package ships
|
|
531
|
+
Instead of wiring up cache handlers imperatively from a worker entry, you can declare them in the `vinext()` plugin config. The `@vinext/cloudflare` package ships Cloudflare adapters for this:
|
|
532
532
|
|
|
533
533
|
- **`kvDataAdapter()`** (`@vinext/cloudflare/cache/kv-data-adapter`) — backs the `"use cache"` data cache with a Workers KV namespace.
|
|
534
|
-
- **`cdnAdapter()`** (`@vinext/cloudflare/cache/cdn-adapter`) — backs full-route CDN caching with the Workers Cache API.
|
|
535
534
|
|
|
536
535
|
```ts
|
|
537
536
|
import { defineConfig } from "vite";
|
|
538
537
|
import vinext from "vinext";
|
|
539
|
-
import { cdnAdapter } from "@vinext/cloudflare/cache/cdn-adapter";
|
|
540
538
|
import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
|
|
541
539
|
|
|
542
540
|
export default defineConfig({
|
|
543
541
|
plugins: [
|
|
544
542
|
vinext({
|
|
545
543
|
cache: {
|
|
546
|
-
cdn: cdnAdapter(),
|
|
547
544
|
data: kvDataAdapter(),
|
|
548
545
|
},
|
|
549
546
|
}),
|
|
@@ -559,7 +556,7 @@ The KV data adapter reads `env[binding]` at runtime, so add the matching KV name
|
|
|
559
556
|
}
|
|
560
557
|
```
|
|
561
558
|
|
|
562
|
-
`binding` defaults to `VINEXT_KV_CACHE`, so `kvDataAdapter()` with no options works as long as that's your binding name. Other options: `appPrefix` (namespace cache keys to isolate multiple apps in one KV namespace), `ttlSeconds` (default KV `expirationTtl`, default 30 days), and `tagCacheTtlMs` (in-memory tag-invalidation cache TTL, default 5s).
|
|
559
|
+
`binding` defaults to `VINEXT_KV_CACHE`, so `kvDataAdapter()` with no options works as long as that's your binding name. Other options: `appPrefix` (namespace cache keys to isolate multiple apps in one KV namespace), `ttlSeconds` (default KV `expirationTtl`, default 30 days), and `tagCacheTtlMs` (in-memory tag-invalidation cache TTL, default 5s).
|
|
563
560
|
|
|
564
561
|
Each builder returns a plain, serializable `{ adapter, options }` descriptor — **it never touches the Workers runtime**, so nothing throws at build or dev time when bindings aren't available. The actual adapter (and its `env` binding lookup) is instantiated lazily on the first request.
|
|
565
562
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/build/assets-ignore.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build metadata that must never be served by the Cloudflare ASSETS binding.
|
|
4
|
+
*
|
|
5
|
+
* On Cloudflare Workers the ASSETS binding serves any uploaded file whose path
|
|
6
|
+
* matches the request BEFORE the Worker runs, so anything written into the
|
|
7
|
+
* client output directory (`dist/client`) is publicly fetchable unless excluded.
|
|
8
|
+
* Vite writes its build/SSR manifests under `dist/client/.vite/` (enabled for
|
|
9
|
+
* Cloudflare builds so the worker entry can compute lazy chunks), which would
|
|
10
|
+
* otherwise expose the full source-file → chunk mapping — including the paths of
|
|
11
|
+
* routes that are never linked from the UI.
|
|
12
|
+
*
|
|
13
|
+
* The Node production server already blocks `/.vite/` explicitly
|
|
14
|
+
* (see `server/static-file-cache.ts`); `.assetsignore` is the equivalent guard
|
|
15
|
+
* for the Cloudflare deployment target. wrangler matches `.assetsignore`
|
|
16
|
+
* patterns with `.gitignore` semantics (via the `ignore` package), so the bare
|
|
17
|
+
* `.vite` entry excludes the directory and everything beneath it.
|
|
18
|
+
*/
|
|
19
|
+
declare const DEFAULT_VINEXT_ASSET_IGNORE_PATTERNS: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* Ensure a `.assetsignore` in `clientDir` contains every pattern in `patterns`.
|
|
22
|
+
*
|
|
23
|
+
* Any pre-existing (user-authored) content is preserved verbatim and only the
|
|
24
|
+
* missing patterns are appended, so the result is idempotent across rebuilds
|
|
25
|
+
* and never clobbers a `.assetsignore` the developer wrote themselves.
|
|
26
|
+
*
|
|
27
|
+
* @returns `true` when the file was created or modified, `false` when it already
|
|
28
|
+
* covered every requested pattern.
|
|
29
|
+
*/
|
|
30
|
+
declare function ensureAssetsIgnore(clientDir: string, patterns?: readonly string[]): boolean;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { DEFAULT_VINEXT_ASSET_IGNORE_PATTERNS, ensureAssetsIgnore };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/build/assets-ignore.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build metadata that must never be served by the Cloudflare ASSETS binding.
|
|
6
|
+
*
|
|
7
|
+
* On Cloudflare Workers the ASSETS binding serves any uploaded file whose path
|
|
8
|
+
* matches the request BEFORE the Worker runs, so anything written into the
|
|
9
|
+
* client output directory (`dist/client`) is publicly fetchable unless excluded.
|
|
10
|
+
* Vite writes its build/SSR manifests under `dist/client/.vite/` (enabled for
|
|
11
|
+
* Cloudflare builds so the worker entry can compute lazy chunks), which would
|
|
12
|
+
* otherwise expose the full source-file → chunk mapping — including the paths of
|
|
13
|
+
* routes that are never linked from the UI.
|
|
14
|
+
*
|
|
15
|
+
* The Node production server already blocks `/.vite/` explicitly
|
|
16
|
+
* (see `server/static-file-cache.ts`); `.assetsignore` is the equivalent guard
|
|
17
|
+
* for the Cloudflare deployment target. wrangler matches `.assetsignore`
|
|
18
|
+
* patterns with `.gitignore` semantics (via the `ignore` package), so the bare
|
|
19
|
+
* `.vite` entry excludes the directory and everything beneath it.
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_VINEXT_ASSET_IGNORE_PATTERNS = [".vite"];
|
|
22
|
+
/** wrangler reads asset-exclusion patterns from this file in the assets dir. */
|
|
23
|
+
const ASSETS_IGNORE_FILENAME = ".assetsignore";
|
|
24
|
+
const GENERATED_HEADER = "# Keep build metadata out of the deployed asset bundle (generated by vinext)";
|
|
25
|
+
/**
|
|
26
|
+
* Ensure a `.assetsignore` in `clientDir` contains every pattern in `patterns`.
|
|
27
|
+
*
|
|
28
|
+
* Any pre-existing (user-authored) content is preserved verbatim and only the
|
|
29
|
+
* missing patterns are appended, so the result is idempotent across rebuilds
|
|
30
|
+
* and never clobbers a `.assetsignore` the developer wrote themselves.
|
|
31
|
+
*
|
|
32
|
+
* @returns `true` when the file was created or modified, `false` when it already
|
|
33
|
+
* covered every requested pattern.
|
|
34
|
+
*/
|
|
35
|
+
function ensureAssetsIgnore(clientDir, patterns = DEFAULT_VINEXT_ASSET_IGNORE_PATTERNS) {
|
|
36
|
+
const assetsIgnorePath = path.join(clientDir, ASSETS_IGNORE_FILENAME);
|
|
37
|
+
const existing = fs.existsSync(assetsIgnorePath) ? fs.readFileSync(assetsIgnorePath, "utf-8") : null;
|
|
38
|
+
const present = new Set((existing ?? "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
39
|
+
const missing = patterns.filter((pattern) => !present.has(pattern));
|
|
40
|
+
if (missing.length === 0) return false;
|
|
41
|
+
const lines = existing && existing.trim().length > 0 ? [existing.replace(/\s*$/, "")] : [GENERATED_HEADER];
|
|
42
|
+
lines.push(...missing, "");
|
|
43
|
+
fs.mkdirSync(clientDir, { recursive: true });
|
|
44
|
+
fs.writeFileSync(assetsIgnorePath, lines.join("\n"));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { DEFAULT_VINEXT_ASSET_IGNORE_PATTERNS, ensureAssetsIgnore };
|
|
@@ -51,10 +51,16 @@ declare function createClientManualChunks(shimsDir: string): (id: string) => str
|
|
|
51
51
|
* compression efficiency — small files restart the compression dictionary,
|
|
52
52
|
* adding ~5-15% wire overhead vs fewer larger chunks.
|
|
53
53
|
*/
|
|
54
|
+
declare function createClientFileNameConfig(assetsDir: string): {
|
|
55
|
+
entryFileNames: string;
|
|
56
|
+
chunkFileNames: string;
|
|
57
|
+
};
|
|
54
58
|
declare function createClientOutputConfig(clientManualChunks: (id: string) => string | undefined, assetsDir: string): {
|
|
55
59
|
assetFileNames: (assetInfo: ClientAssetFileNameInfo) => string;
|
|
56
60
|
manualChunks: (id: string) => string | undefined;
|
|
57
61
|
experimentalMinChunkSize: number;
|
|
62
|
+
entryFileNames: string;
|
|
63
|
+
chunkFileNames: string;
|
|
58
64
|
};
|
|
59
65
|
declare function createClientCodeSplittingConfig(clientManualChunks: (id: string) => string | undefined): {
|
|
60
66
|
minSize: number;
|
|
@@ -62,6 +68,32 @@ declare function createClientCodeSplittingConfig(clientManualChunks: (id: string
|
|
|
62
68
|
name(moduleId: string): string | null;
|
|
63
69
|
}[];
|
|
64
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Regex matching any {@link FRAMEWORK_PACKAGES} package inside `node_modules`.
|
|
73
|
+
* Derived from the package list so the regex and {@link isRscFrameworkModule}
|
|
74
|
+
* predicate can't drift.
|
|
75
|
+
*/
|
|
76
|
+
declare const RSC_FRAMEWORK_CHUNK_TEST: RegExp;
|
|
77
|
+
declare function isRscFrameworkModule(id: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Output config that isolates React (and the RSC flight runtime) into a
|
|
80
|
+
* dedicated "framework" chunk in the RSC server build. Returns the bundler-
|
|
81
|
+
* appropriate shape: rolldown's `codeSplitting` for Vite 8+, Rollup's
|
|
82
|
+
* `manualChunks` for Vite 7. See {@link RSC_FRAMEWORK_CHUNK_TEST} for the
|
|
83
|
+
* motivation (issue #1549).
|
|
84
|
+
*/
|
|
85
|
+
declare function createRscFrameworkChunkOutputConfig(viteMajorVersion: number): {
|
|
86
|
+
codeSplitting: {
|
|
87
|
+
groups: {
|
|
88
|
+
name: string;
|
|
89
|
+
test: RegExp;
|
|
90
|
+
}[];
|
|
91
|
+
};
|
|
92
|
+
manualChunks?: undefined;
|
|
93
|
+
} | {
|
|
94
|
+
manualChunks(id: string): string | undefined;
|
|
95
|
+
codeSplitting?: undefined;
|
|
96
|
+
};
|
|
65
97
|
/**
|
|
66
98
|
* Rollup treeshake configuration for production client builds.
|
|
67
99
|
*
|
|
@@ -129,4 +161,4 @@ type VinextBuildConfigWithLegacy = VinextBuildConfig & {
|
|
|
129
161
|
declare function getBuildBundlerOptions(build: UserConfig["build"] | undefined): VinextBuildBundlerOptions | undefined;
|
|
130
162
|
declare function withBuildBundlerOptions(viteMajorVersion: number, bundlerOptions: VinextBuildBundlerOptions): Partial<VinextBuildConfigWithLegacy>;
|
|
131
163
|
//#endregion
|
|
132
|
-
export { clientTreeshakeConfig, createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions };
|
|
164
|
+
export { RSC_FRAMEWORK_CHUNK_TEST, clientTreeshakeConfig, createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createClientOutputConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, isRscFrameworkModule, withBuildBundlerOptions };
|
|
@@ -89,8 +89,16 @@ function createClientManualChunks(shimsDir) {
|
|
|
89
89
|
* compression efficiency — small files restart the compression dictionary,
|
|
90
90
|
* adding ~5-15% wire overhead vs fewer larger chunks.
|
|
91
91
|
*/
|
|
92
|
+
function createClientFileNameConfig(assetsDir) {
|
|
93
|
+
const chunksDir = `${assetsDir}/chunks`;
|
|
94
|
+
return {
|
|
95
|
+
entryFileNames: `${chunksDir}/[name]-[hash].js`,
|
|
96
|
+
chunkFileNames: `${chunksDir}/[name]-[hash].js`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
92
99
|
function createClientOutputConfig(clientManualChunks, assetsDir) {
|
|
93
100
|
return {
|
|
101
|
+
...createClientFileNameConfig(assetsDir),
|
|
94
102
|
assetFileNames: createClientAssetFileNames(assetsDir),
|
|
95
103
|
manualChunks: clientManualChunks,
|
|
96
104
|
experimentalMinChunkSize: 1e4
|
|
@@ -105,6 +113,63 @@ function createClientCodeSplittingConfig(clientManualChunks) {
|
|
|
105
113
|
};
|
|
106
114
|
}
|
|
107
115
|
/**
|
|
116
|
+
* Matches React framework packages (and the RSC flight runtime) inside
|
|
117
|
+
* `node_modules`. Used to split them into a dedicated "framework" chunk in the
|
|
118
|
+
* RSC server build.
|
|
119
|
+
*
|
|
120
|
+
* Why the RSC build needs this: without an explicit framework chunk, the
|
|
121
|
+
* bundler colocates React into whichever chunk first reaches it — typically the
|
|
122
|
+
* RSC entry chunk, which also carries the root layout's CSS. Modules that only
|
|
123
|
+
* import React for runtime helpers (notably `app/global-not-found.tsx`, which
|
|
124
|
+
* replaces the root layout for route-miss 404s) then import that entry chunk
|
|
125
|
+
* and inherit the root layout's CSS in their `serverResources` metadata. The
|
|
126
|
+
* 404 document ends up linking the layout's stylesheet last, so the layout's
|
|
127
|
+
* rules win the cascade over global-not-found's — the bug tracked in
|
|
128
|
+
* https://github.com/cloudflare/vinext/issues/1549.
|
|
129
|
+
*
|
|
130
|
+
* Splitting React into its own (CSS-free) chunk means global-not-found imports
|
|
131
|
+
* the framework chunk instead of the layout-bearing entry chunk, so it no
|
|
132
|
+
* longer inherits the root layout's CSS. The match list mirrors the client
|
|
133
|
+
* build's `framework` chunk, plus `react-server-dom-webpack` for the RSC flight
|
|
134
|
+
* runtime that the server environment bundles.
|
|
135
|
+
*
|
|
136
|
+
* Uses `[\\/]` rather than `/` for the path separator so it matches on Windows
|
|
137
|
+
* too, per the rolldown `codeSplitting` docs.
|
|
138
|
+
*/
|
|
139
|
+
const FRAMEWORK_PACKAGES = [
|
|
140
|
+
"react",
|
|
141
|
+
"react-dom",
|
|
142
|
+
"scheduler",
|
|
143
|
+
"react-server-dom-webpack"
|
|
144
|
+
];
|
|
145
|
+
/**
|
|
146
|
+
* Regex matching any {@link FRAMEWORK_PACKAGES} package inside `node_modules`.
|
|
147
|
+
* Derived from the package list so the regex and {@link isRscFrameworkModule}
|
|
148
|
+
* predicate can't drift.
|
|
149
|
+
*/
|
|
150
|
+
const RSC_FRAMEWORK_CHUNK_TEST = new RegExp(`[\\\\/]node_modules[\\\\/](${FRAMEWORK_PACKAGES.join("|")})[\\\\/]`);
|
|
151
|
+
function isRscFrameworkModule(id) {
|
|
152
|
+
if (!id.includes("node_modules")) return false;
|
|
153
|
+
const pkg = getPackageName(id);
|
|
154
|
+
return pkg !== null && FRAMEWORK_PACKAGES.includes(pkg);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Output config that isolates React (and the RSC flight runtime) into a
|
|
158
|
+
* dedicated "framework" chunk in the RSC server build. Returns the bundler-
|
|
159
|
+
* appropriate shape: rolldown's `codeSplitting` for Vite 8+, Rollup's
|
|
160
|
+
* `manualChunks` for Vite 7. See {@link RSC_FRAMEWORK_CHUNK_TEST} for the
|
|
161
|
+
* motivation (issue #1549).
|
|
162
|
+
*/
|
|
163
|
+
function createRscFrameworkChunkOutputConfig(viteMajorVersion) {
|
|
164
|
+
if (viteMajorVersion >= 8) return { codeSplitting: { groups: [{
|
|
165
|
+
name: "framework",
|
|
166
|
+
test: RSC_FRAMEWORK_CHUNK_TEST
|
|
167
|
+
}] } };
|
|
168
|
+
return { manualChunks(id) {
|
|
169
|
+
return isRscFrameworkModule(id) ? "framework" : void 0;
|
|
170
|
+
} };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
108
173
|
* Rollup treeshake configuration for production client builds.
|
|
109
174
|
*
|
|
110
175
|
* Uses the 'recommended' preset as a safe base, then overrides
|
|
@@ -171,4 +236,4 @@ function withBuildBundlerOptions(viteMajorVersion, bundlerOptions) {
|
|
|
171
236
|
return viteMajorVersion >= 8 ? { rolldownOptions: bundlerOptions } : { rollupOptions: bundlerOptions };
|
|
172
237
|
}
|
|
173
238
|
//#endregion
|
|
174
|
-
export { clientTreeshakeConfig, createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions };
|
|
239
|
+
export { RSC_FRAMEWORK_CHUNK_TEST, clientTreeshakeConfig, createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createClientOutputConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, isRscFrameworkModule, withBuildBundlerOptions };
|
package/dist/check.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { detectPackageManager } from "./utils/project.js";
|
|
2
|
+
import { normalizePathSeparators } from "./utils/path.js";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { parseAst } from "vite";
|
|
@@ -342,7 +343,7 @@ function findSourceFiles(dir, extensions = [
|
|
|
342
343
|
if (!fs.existsSync(dir)) return results;
|
|
343
344
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
344
345
|
for (const entry of entries) {
|
|
345
|
-
const fullPath = path.join(dir, entry.name);
|
|
346
|
+
const fullPath = normalizePathSeparators(path.join(dir, entry.name));
|
|
346
347
|
if (entry.isDirectory()) {
|
|
347
348
|
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist" || entry.name === ".git") continue;
|
|
348
349
|
results.push(...findSourceFiles(fullPath, extensions));
|
|
@@ -563,7 +564,7 @@ function scanImports(root) {
|
|
|
563
564
|
if (mod.startsWith("next/") || mod === "next" || mod === "server-only" || mod === "client-only") {
|
|
564
565
|
const normalized = mod === "next" ? "next" : mod;
|
|
565
566
|
if (!importUsage.has(normalized)) importUsage.set(normalized, []);
|
|
566
|
-
const relFile = path.relative(root, file);
|
|
567
|
+
const relFile = normalizePathSeparators(path.relative(root, file));
|
|
567
568
|
const usedInFiles = importUsage.get(normalized) ?? [];
|
|
568
569
|
if (!usedInFiles.includes(relFile)) usedInFiles.push(relFile);
|
|
569
570
|
}
|
|
@@ -876,7 +877,7 @@ function checkConventions(root) {
|
|
|
876
877
|
const cjsGlobalFiles = [];
|
|
877
878
|
for (const file of allSourceFiles) {
|
|
878
879
|
const content = fs.readFileSync(file, "utf-8");
|
|
879
|
-
const rel = path.relative(root, file);
|
|
880
|
+
const rel = normalizePathSeparators(path.relative(root, file));
|
|
880
881
|
if (viewTransitionRegex.test(content)) viewTransitionFiles.push(rel);
|
|
881
882
|
if (hasFreeCjsGlobal(content)) cjsGlobalFiles.push(rel);
|
|
882
883
|
}
|
package/dist/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ import { createRequire } from "node:module";
|
|
|
18
18
|
import fs from "node:fs";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { pathToFileURL } from "node:url";
|
|
21
|
+
import { randomBytes } from "node:crypto";
|
|
21
22
|
import { execFileSync } from "node:child_process";
|
|
22
23
|
//#region src/cli.ts
|
|
23
24
|
/**
|
|
@@ -263,6 +264,7 @@ async function buildApp() {
|
|
|
263
264
|
const resolvedNextConfig = await resolveNextConfig(await loadNextConfig(root, PHASE_PRODUCTION_BUILD), root);
|
|
264
265
|
process.env.__VINEXT_SHARED_BUILD_ID = resolvedNextConfig.buildId;
|
|
265
266
|
process.env.__VINEXT_SHARED_RSC_COMPATIBILITY_ID = createRscCompatibilityId(resolvedNextConfig);
|
|
267
|
+
if (!process.env.__VINEXT_SHARED_REVALIDATE_SECRET) process.env.__VINEXT_SHARED_REVALIDATE_SECRET = randomBytes(32).toString("hex");
|
|
266
268
|
const outputMode = resolvedNextConfig.output;
|
|
267
269
|
const distDir = path.resolve(root, "dist");
|
|
268
270
|
if (outputMode === "standalone") {
|
|
@@ -15,17 +15,26 @@ type NavigationRuntimeRscBootstrap = {
|
|
|
15
15
|
};
|
|
16
16
|
type NavigationRuntimeKind = "navigate" | "traverse" | "refresh";
|
|
17
17
|
type NavigationRuntimeHistoryUpdateMode = "push" | "replace";
|
|
18
|
+
type NavigationRuntimeVisibleCommitMode = "transition" | "synchronous";
|
|
18
19
|
type NavigationRuntimeTraversalIntent = {
|
|
19
20
|
direction: "back" | "forward" | "unknown";
|
|
20
21
|
historyState: unknown;
|
|
21
22
|
targetHistoryIndex: number | null;
|
|
22
23
|
};
|
|
23
|
-
type NavigationRuntimeNavigate = (href: string, redirectDepth?: number, navigationKind?: NavigationRuntimeKind, historyUpdateMode?: NavigationRuntimeHistoryUpdateMode, previousNextUrlOverride?: string | null, programmaticTransition?: boolean, traversalIntent?: NavigationRuntimeTraversalIntent, scrollIntent?: AppRouterScrollIntent | null) => Promise<void>;
|
|
24
|
+
type NavigationRuntimeNavigate = (href: string, redirectDepth?: number, navigationKind?: NavigationRuntimeKind, historyUpdateMode?: NavigationRuntimeHistoryUpdateMode, previousNextUrlOverride?: string | null, programmaticTransition?: boolean, traversalIntent?: NavigationRuntimeTraversalIntent, scrollIntent?: AppRouterScrollIntent | null, visibleCommitMode?: NavigationRuntimeVisibleCommitMode) => Promise<void>;
|
|
24
25
|
type NavigationRuntimeFunctions = {
|
|
25
26
|
clearNavigationCaches?: () => void;
|
|
26
27
|
commitHashNavigation?: (href: string, historyUpdateMode: NavigationRuntimeHistoryUpdateMode, scroll: boolean) => void;
|
|
27
28
|
navigateExternal?: (href: string, historyUpdateMode: NavigationRuntimeHistoryUpdateMode) => Promise<void>;
|
|
28
29
|
navigate?: NavigationRuntimeNavigate;
|
|
30
|
+
/**
|
|
31
|
+
* Called at the start of every App Router navigation so the <Link> shim can
|
|
32
|
+
* reset any link that is still showing a `useLinkStatus()` pending state but
|
|
33
|
+
* is not the one driving this navigation (e.g. a programmatic router.push or
|
|
34
|
+
* a shallow-routing transition). Registered by shims/link.tsx; decoupled
|
|
35
|
+
* through the runtime to avoid a circular import with shims/navigation.ts.
|
|
36
|
+
*/
|
|
37
|
+
notifyLinkNavigationStart?: () => void;
|
|
29
38
|
pingVisibleLinks?: () => void;
|
|
30
39
|
};
|
|
31
40
|
type NavigationRuntimeBootstrap = {
|
|
@@ -58,4 +67,4 @@ declare function hasAppNavigationRuntime(): boolean;
|
|
|
58
67
|
*/
|
|
59
68
|
declare function hasAppNavigationRuntimeBootstrap(): boolean;
|
|
60
69
|
//#endregion
|
|
61
|
-
export { NAVIGATION_RUNTIME_KEY, NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION, NavigationRuntime, NavigationRuntimeBootstrap, NavigationRuntimeFunctions, NavigationRuntimeNavigate, NavigationRuntimeRscBootstrap, NavigationRuntimeRscChunk, NavigationRuntimeSnapshot, ensureNavigationRuntimeRscBootstrap, getNavigationRuntime, hasAppNavigationRuntime, hasAppNavigationRuntimeBootstrap, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions, subscribeNavigationRuntimeRscChunk };
|
|
70
|
+
export { NAVIGATION_RUNTIME_KEY, NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION, NavigationRuntime, NavigationRuntimeBootstrap, NavigationRuntimeFunctions, NavigationRuntimeNavigate, NavigationRuntimeRscBootstrap, NavigationRuntimeRscChunk, NavigationRuntimeSnapshot, NavigationRuntimeVisibleCommitMode, ensureNavigationRuntimeRscBootstrap, getNavigationRuntime, hasAppNavigationRuntime, hasAppNavigationRuntimeBootstrap, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions, subscribeNavigationRuntimeRscChunk };
|
|
@@ -31,7 +31,7 @@ function readRuntimeWindow() {
|
|
|
31
31
|
}
|
|
32
32
|
function isNavigationRuntimeFunctions(value) {
|
|
33
33
|
if (!isUnknownRecord(value)) return false;
|
|
34
|
-
return isOptionalRuntimeFunction(Reflect.get(value, "clearNavigationCaches")) && isOptionalRuntimeFunction(Reflect.get(value, "commitHashNavigation")) && isOptionalRuntimeFunction(Reflect.get(value, "navigateExternal")) && isOptionalRuntimeFunction(Reflect.get(value, "navigate")) && isOptionalRuntimeFunction(Reflect.get(value, "pingVisibleLinks"));
|
|
34
|
+
return isOptionalRuntimeFunction(Reflect.get(value, "clearNavigationCaches")) && isOptionalRuntimeFunction(Reflect.get(value, "commitHashNavigation")) && isOptionalRuntimeFunction(Reflect.get(value, "navigateExternal")) && isOptionalRuntimeFunction(Reflect.get(value, "navigate")) && isOptionalRuntimeFunction(Reflect.get(value, "notifyLinkNavigationStart")) && isOptionalRuntimeFunction(Reflect.get(value, "pingVisibleLinks"));
|
|
35
35
|
}
|
|
36
36
|
function isNavigationRuntimeRscChunk(value) {
|
|
37
37
|
if (typeof value === "string") return true;
|
|
@@ -10,7 +10,8 @@ type VinextNextData = {
|
|
|
10
10
|
/** vinext-specific additions (not part of Next.js upstream). */__vinext?: {
|
|
11
11
|
/** Absolute URL of the page module for dynamic import. */pageModuleUrl?: string; /** Absolute URL of the `_app` module for dynamic import. */
|
|
12
12
|
appModuleUrl?: string; /** True when the Pages Router server has middleware/proxy configured. */
|
|
13
|
-
hasMiddleware?: boolean;
|
|
13
|
+
hasMiddleware?: boolean; /** True when build-time rewrites can affect the initial Pages Router ready state. */
|
|
14
|
+
hasRewrites?: boolean;
|
|
14
15
|
};
|
|
15
16
|
} & NEXT_DATA;
|
|
16
17
|
type BrowserVinextNextData = NonNullable<Window["__NEXT_DATA__"]> & VinextNextData;
|
|
@@ -40,10 +40,9 @@
|
|
|
40
40
|
* `window.next.router`. Mirrors the `publicAppRouterInstance` shape from
|
|
41
41
|
* `packages/next/src/client/components/app-router-instance.ts`.
|
|
42
42
|
*
|
|
43
|
-
* `hmrRefresh`
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* branch, matching what they would do on a production Next.js build.
|
|
43
|
+
* `hmrRefresh` is intentionally omitted — vinext does not implement it.
|
|
44
|
+
* `experimental_gesturePush` is attached only when
|
|
45
|
+
* `experimental.gestureTransition` is enabled, matching Next.js.
|
|
47
46
|
*/
|
|
48
47
|
type AppRouterPublicInstance = {
|
|
49
48
|
push: (href: string, options?: {
|
|
@@ -57,6 +56,9 @@ type AppRouterPublicInstance = {
|
|
|
57
56
|
refresh: () => void;
|
|
58
57
|
prefetch: (href: string, options?: {
|
|
59
58
|
onInvalidate?: () => void;
|
|
59
|
+
}) => void;
|
|
60
|
+
experimental_gesturePush?: (href: string, options?: {
|
|
61
|
+
scroll?: boolean;
|
|
60
62
|
}) => void; /** Default placeholder, matches Next.js. */
|
|
61
63
|
bfcacheId?: string;
|
|
62
64
|
};
|
|
@@ -32,10 +32,10 @@ declare function escapeHeaderSource(source: string): string;
|
|
|
32
32
|
* Callers extract the relevant parts from the incoming Request.
|
|
33
33
|
*/
|
|
34
34
|
type RequestContext = {
|
|
35
|
-
headers: Headers;
|
|
36
|
-
cookies: Record<string, string>;
|
|
37
|
-
query: URLSearchParams;
|
|
38
|
-
host: string;
|
|
35
|
+
readonly headers: Headers;
|
|
36
|
+
readonly cookies: Record<string, string>;
|
|
37
|
+
readonly query: URLSearchParams;
|
|
38
|
+
readonly host: string;
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* basePath gating state passed alongside the pathname to every matcher.
|
|
@@ -65,6 +65,13 @@ type BasePathMatchState = {
|
|
|
65
65
|
declare function parseCookies(cookieHeader: string | null): Record<string, string>;
|
|
66
66
|
/**
|
|
67
67
|
* Build a RequestContext from a Web Request object.
|
|
68
|
+
*
|
|
69
|
+
* `cookies` and `query` are lazy memoized getters: they are consumed only by
|
|
70
|
+
* `has`/`missing` condition evaluation (`checkHasConditions` /
|
|
71
|
+
* `matchesRuleConditions`), and most apps configure no such conditions. The
|
|
72
|
+
* cookie split and `searchParams` access are therefore deferred until first
|
|
73
|
+
* read and computed at most once. Mirrors `headersContextFromRequest` in
|
|
74
|
+
* `shims/headers.ts`.
|
|
68
75
|
*/
|
|
69
76
|
declare function requestContextFromRequest(request: Request): RequestContext;
|
|
70
77
|
declare function normalizeHost(hostHeader: string | null, fallbackHostname: string): string;
|
|
@@ -159,6 +166,25 @@ declare function sanitizeDestination(dest: string): string;
|
|
|
159
166
|
* per RFC 3986, plus protocol-relative URLs (//).
|
|
160
167
|
*/
|
|
161
168
|
declare function isExternalUrl(url: string): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Merge the original request's query params into a config-redirect
|
|
171
|
+
* destination, preserving them on the resulting `Location`.
|
|
172
|
+
*
|
|
173
|
+
* Next.js carries the original request query across config redirects
|
|
174
|
+
* (`prepareDestination({ query: parsedUrl.query })` →
|
|
175
|
+
* `stringifyQuery(...)` in resolve-routes.ts). This matters for App Router
|
|
176
|
+
* RSC client navigations: the cache-busting `_rsc` query must survive the
|
|
177
|
+
* redirect so the browser's auto-followed request to the destination is
|
|
178
|
+
* still treated as an RSC fetch. Dropping it breaks RSC fetch semantics
|
|
179
|
+
* (issue #1529).
|
|
180
|
+
*
|
|
181
|
+
* Destination query params win — a request param is only carried over when
|
|
182
|
+
* the destination does not already specify that key. Mirrors the merge
|
|
183
|
+
* semantics in `proxyExternalRequest`. External destinations are returned
|
|
184
|
+
* untouched (a config redirect to another origin should not leak the
|
|
185
|
+
* original request's query).
|
|
186
|
+
*/
|
|
187
|
+
declare function preserveRedirectDestinationQuery(destination: string, requestSearch: string): string;
|
|
162
188
|
/**
|
|
163
189
|
* Proxy an incoming request to an external URL and return the upstream response.
|
|
164
190
|
*
|
|
@@ -218,4 +244,4 @@ declare function applyLocaleToRoutes<T extends NextRedirect | NextRewrite>(route
|
|
|
218
244
|
trailingSlash?: boolean;
|
|
219
245
|
}): T[];
|
|
220
246
|
//#endregion
|
|
221
|
-
export { BasePathMatchState, RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
247
|
+
export { BasePathMatchState, RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
@@ -356,13 +356,26 @@ function parseCookies(cookieHeader) {
|
|
|
356
356
|
}
|
|
357
357
|
/**
|
|
358
358
|
* Build a RequestContext from a Web Request object.
|
|
359
|
+
*
|
|
360
|
+
* `cookies` and `query` are lazy memoized getters: they are consumed only by
|
|
361
|
+
* `has`/`missing` condition evaluation (`checkHasConditions` /
|
|
362
|
+
* `matchesRuleConditions`), and most apps configure no such conditions. The
|
|
363
|
+
* cookie split and `searchParams` access are therefore deferred until first
|
|
364
|
+
* read and computed at most once. Mirrors `headersContextFromRequest` in
|
|
365
|
+
* `shims/headers.ts`.
|
|
359
366
|
*/
|
|
360
367
|
function requestContextFromRequest(request) {
|
|
361
368
|
const url = new URL(request.url);
|
|
369
|
+
let cookies;
|
|
370
|
+
let query;
|
|
362
371
|
return {
|
|
363
372
|
headers: request.headers,
|
|
364
|
-
cookies
|
|
365
|
-
|
|
373
|
+
get cookies() {
|
|
374
|
+
return cookies ??= parseCookies(request.headers.get("cookie"));
|
|
375
|
+
},
|
|
376
|
+
get query() {
|
|
377
|
+
return query ??= url.searchParams;
|
|
378
|
+
},
|
|
366
379
|
host: normalizeHost(request.headers.get("host"), url.hostname)
|
|
367
380
|
};
|
|
368
381
|
}
|
|
@@ -764,6 +777,40 @@ function isExternalUrl(url) {
|
|
|
764
777
|
return /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith("//");
|
|
765
778
|
}
|
|
766
779
|
/**
|
|
780
|
+
* Merge the original request's query params into a config-redirect
|
|
781
|
+
* destination, preserving them on the resulting `Location`.
|
|
782
|
+
*
|
|
783
|
+
* Next.js carries the original request query across config redirects
|
|
784
|
+
* (`prepareDestination({ query: parsedUrl.query })` →
|
|
785
|
+
* `stringifyQuery(...)` in resolve-routes.ts). This matters for App Router
|
|
786
|
+
* RSC client navigations: the cache-busting `_rsc` query must survive the
|
|
787
|
+
* redirect so the browser's auto-followed request to the destination is
|
|
788
|
+
* still treated as an RSC fetch. Dropping it breaks RSC fetch semantics
|
|
789
|
+
* (issue #1529).
|
|
790
|
+
*
|
|
791
|
+
* Destination query params win — a request param is only carried over when
|
|
792
|
+
* the destination does not already specify that key. Mirrors the merge
|
|
793
|
+
* semantics in `proxyExternalRequest`. External destinations are returned
|
|
794
|
+
* untouched (a config redirect to another origin should not leak the
|
|
795
|
+
* original request's query).
|
|
796
|
+
*/
|
|
797
|
+
function preserveRedirectDestinationQuery(destination, requestSearch) {
|
|
798
|
+
if (requestSearch === "" || requestSearch === "?" || isExternalUrl(destination)) return destination;
|
|
799
|
+
const requestParams = new URLSearchParams(requestSearch);
|
|
800
|
+
if ([...requestParams.keys()].length === 0) return destination;
|
|
801
|
+
const hashIndex = destination.indexOf("#");
|
|
802
|
+
const hash = hashIndex === -1 ? "" : destination.slice(hashIndex);
|
|
803
|
+
const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
|
|
804
|
+
const queryIndex = beforeHash.indexOf("?");
|
|
805
|
+
const pathPart = queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex);
|
|
806
|
+
const destQuery = queryIndex === -1 ? "" : beforeHash.slice(queryIndex + 1);
|
|
807
|
+
const merged = new URLSearchParams(destQuery);
|
|
808
|
+
const destKeys = new Set(merged.keys());
|
|
809
|
+
for (const [key, value] of requestParams) if (!destKeys.has(key)) merged.append(key, value);
|
|
810
|
+
const mergedQuery = merged.toString();
|
|
811
|
+
return mergedQuery === "" ? `${pathPart}${hash}` : `${pathPart}?${mergedQuery}${hash}`;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
767
814
|
* Proxy an incoming request to an external URL and return the upstream response.
|
|
768
815
|
*
|
|
769
816
|
* Used for external rewrites (e.g. `/ph/:path*` → `https://us.i.posthog.com/:path*`).
|
|
@@ -925,4 +972,4 @@ function applyLocaleToRoutes(routes, i18n, type, options = {}) {
|
|
|
925
972
|
return out;
|
|
926
973
|
}
|
|
927
974
|
//#endregion
|
|
928
|
-
export { applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
975
|
+
export { applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
@@ -132,7 +132,14 @@ type NextConfig = {
|
|
|
132
132
|
*/
|
|
133
133
|
instrumentationClientInject?: string[]; /** Extra origins allowed to access the dev server. */
|
|
134
134
|
allowedDevOrigins?: string[]; /** Maximum age in seconds for stale ISR entries before blocking regeneration. */
|
|
135
|
-
expireTime?: number;
|
|
135
|
+
expireTime?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Maximum total length (in characters) of the preload `Link` header emitted
|
|
138
|
+
* during App Router SSR. React drops whole entries once the limit is
|
|
139
|
+
* exceeded; `0` disables emission entirely. Defaults to 6000.
|
|
140
|
+
* @see https://nextjs.org/docs/app/api-reference/config/next-config-js/reactMaxHeadersLength
|
|
141
|
+
*/
|
|
142
|
+
reactMaxHeadersLength?: number; /** User agents that require blocking metadata in the initial head. */
|
|
136
143
|
htmlLimitedBots?: RegExp | string;
|
|
137
144
|
/**
|
|
138
145
|
* Enable Cache Components (Next.js 16).
|
|
@@ -174,6 +181,14 @@ type NextConfig = {
|
|
|
174
181
|
*/
|
|
175
182
|
defineServer?: Record<string, string | number | boolean>;
|
|
176
183
|
};
|
|
184
|
+
experimental?: {
|
|
185
|
+
/**
|
|
186
|
+
* Enables the experimental App Router gesture transition API:
|
|
187
|
+
* `useRouter().experimental_gesturePush()`.
|
|
188
|
+
*/
|
|
189
|
+
gestureTransition?: boolean;
|
|
190
|
+
[key: string]: unknown;
|
|
191
|
+
};
|
|
177
192
|
/**
|
|
178
193
|
* Path to a custom cache handler module (e.g., KV, Redis, DynamoDB).
|
|
179
194
|
* Accepts relative paths, absolute paths, or file:// URLs from import.meta.resolve().
|
|
@@ -223,6 +238,11 @@ type ResolvedNextConfig = {
|
|
|
223
238
|
pageExtensions: string[];
|
|
224
239
|
instrumentationClientInject: string[];
|
|
225
240
|
cacheComponents: boolean;
|
|
241
|
+
/**
|
|
242
|
+
* Enables the experimental App Router gesture transition API:
|
|
243
|
+
* `useRouter().experimental_gesturePush()`.
|
|
244
|
+
*/
|
|
245
|
+
gestureTransition: boolean;
|
|
226
246
|
/**
|
|
227
247
|
* Whether `experimental.prefetchInlining` is configured. Next.js uses this
|
|
228
248
|
* with the Segment Cache to fetch the route tree before the bundled inlined
|
|
@@ -244,8 +264,14 @@ type ResolvedNextConfig = {
|
|
|
244
264
|
serverActionsAllowedOrigins: string[]; /** Packages whose barrel imports should be optimized (from experimental.optimizePackageImports). */
|
|
245
265
|
optimizePackageImports: string[]; /** Inline app CSS into production HTML (from experimental.inlineCss). */
|
|
246
266
|
inlineCss: boolean; /** Parsed body size limit for server actions in bytes (from experimental.serverActions.bodySizeLimit). Defaults to 1MB. */
|
|
247
|
-
serverActionsBodySizeLimit: number; /**
|
|
248
|
-
|
|
267
|
+
serverActionsBodySizeLimit: number; /** Verbatim body size limit config value (e.g. "2mb") for the "Body exceeded {limit} limit" error. Defaults to "1 MB". */
|
|
268
|
+
serverActionsBodySizeLimitLabel: string; /** Route-level expire fallback in seconds for ISR entries with numeric revalidate. */
|
|
269
|
+
expireTime: number;
|
|
270
|
+
/**
|
|
271
|
+
* Maximum total length (in characters) of the preload `Link` header emitted
|
|
272
|
+
* during App Router SSR. `0` disables emission. Defaults to 6000.
|
|
273
|
+
*/
|
|
274
|
+
reactMaxHeadersLength: number; /** Serialized htmlLimitedBots regexp source from next.config. */
|
|
249
275
|
htmlLimitedBots: string | undefined;
|
|
250
276
|
/**
|
|
251
277
|
* Packages that should be treated as server-external (not bundled by Vite).
|