vinext 1.0.0-beta.2 → 1.0.0-beta.4
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 +6 -9
- package/dist/build/client-build-config.js +7 -1
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +12 -2
- package/dist/check.js +4 -0
- package/dist/cli-args.d.ts +2 -1
- package/dist/cli-args.js +10 -0
- package/dist/cli.js +14 -8
- package/dist/client/navigation-runtime.d.ts +6 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/dotenv.d.ts +3 -4
- package/dist/config/dotenv.js +30 -22
- package/dist/config/next-config.d.ts +16 -5
- package/dist/config/next-config.js +7 -0
- package/dist/entries/app-browser-entry.d.ts +4 -10
- package/dist/entries/app-browser-entry.js +20 -4
- package/dist/entries/app-rsc-entry.js +21 -3
- package/dist/entries/app-rsc-manifest.js +19 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +13 -3
- package/dist/index.js +122 -49
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/plugins/client-reference-dedup.js +7 -5
- package/dist/plugins/extensionless-dynamic-import.js +23 -18
- package/dist/plugins/ignore-dynamic-requests.js +3 -1
- package/dist/plugins/import-meta-url.js +17 -6
- package/dist/plugins/require-context.js +20 -15
- package/dist/plugins/sass.js +3 -4
- package/dist/plugins/transform-cache.d.ts +19 -0
- package/dist/plugins/transform-cache.js +36 -0
- package/dist/routing/app-route-graph.d.ts +14 -6
- package/dist/routing/app-route-graph.js +106 -16
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +7 -6
- package/dist/server/app-bfcache-identity.js +28 -2
- package/dist/server/app-browser-entry.js +175 -75
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +30 -5
- package/dist/server/app-browser-prefetch-response.d.ts +9 -0
- package/dist/server/app-browser-prefetch-response.js +32 -0
- package/dist/server/app-browser-state.d.ts +8 -3
- package/dist/server/app-browser-state.js +9 -3
- package/dist/server/app-page-cache-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +37 -8
- package/dist/server/app-page-element-builder.d.ts +4 -1
- package/dist/server/app-page-element-builder.js +34 -7
- package/dist/server/app-page-head.d.ts +3 -3
- package/dist/server/app-page-head.js +58 -13
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
- package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
- package/dist/server/app-page-probe.d.ts +4 -0
- package/dist/server/app-page-probe.js +6 -2
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +13 -3
- package/dist/server/app-page-request.d.ts +3 -1
- package/dist/server/app-page-request.js +4 -13
- package/dist/server/app-page-response.d.ts +2 -0
- package/dist/server/app-page-response.js +7 -2
- package/dist/server/app-page-route-wiring.d.ts +10 -2
- package/dist/server/app-page-route-wiring.js +269 -59
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +3 -1
- package/dist/server/app-route-handler-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +9 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +6 -0
- package/dist/server/app-route-module-loader.js +3 -0
- package/dist/server/app-router-entry.js +6 -3
- package/dist/server/app-rsc-cache-busting.d.ts +7 -0
- package/dist/server/app-rsc-cache-busting.js +6 -0
- package/dist/server/app-rsc-errors.js +10 -0
- package/dist/server/app-rsc-handler.d.ts +2 -0
- package/dist/server/app-rsc-handler.js +30 -13
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.js +65 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -0
- package/dist/server/app-rsc-route-matching.js +6 -0
- package/dist/server/app-server-action-execution.d.ts +1 -1
- package/dist/server/app-ssr-entry.js +4 -4
- package/dist/server/app-visited-response-cache.d.ts +6 -1
- package/dist/server/app-visited-response-cache.js +49 -1
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- package/dist/server/dev-server.d.ts +3 -1
- package/dist/server/dev-server.js +204 -348
- package/dist/server/edge-api-runtime.d.ts +10 -1
- package/dist/server/edge-api-runtime.js +29 -1
- package/dist/server/headers.d.ts +4 -2
- package/dist/server/headers.js +6 -3
- package/dist/server/isr-cache.d.ts +10 -33
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- package/dist/server/pages-api-route.d.ts +4 -0
- package/dist/server/pages-api-route.js +6 -3
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +6 -4
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-document-asset-props.d.ts +26 -0
- package/dist/server/pages-document-asset-props.js +69 -0
- package/dist/server/pages-get-initial-props.d.ts +1 -1
- package/dist/server/pages-get-initial-props.js +1 -4
- package/dist/server/pages-i18n.js +64 -16
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +10 -6
- package/dist/server/pages-page-data.d.ts +61 -9
- package/dist/server/pages-page-data.js +334 -74
- package/dist/server/pages-page-handler.d.ts +6 -1
- package/dist/server/pages-page-handler.js +119 -20
- package/dist/server/pages-page-response.d.ts +7 -3
- package/dist/server/pages-page-response.js +41 -33
- package/dist/server/pages-request-pipeline.d.ts +7 -0
- package/dist/server/pages-request-pipeline.js +5 -1
- package/dist/server/pages-revalidate.d.ts +1 -1
- package/dist/server/pages-revalidate.js +54 -8
- package/dist/server/pages-router-entry.d.ts +1 -0
- package/dist/server/pages-router-entry.js +10 -4
- package/dist/server/prerender-manifest.d.ts +1 -0
- package/dist/server/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +38 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +30 -0
- package/dist/shims/app-router-scroll-state.d.ts +2 -1
- package/dist/shims/app-router-scroll-state.js +7 -2
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- package/dist/shims/cache-runtime.d.ts +6 -0
- package/dist/shims/cache-runtime.js +4 -1
- package/dist/shims/cache.js +1 -1
- package/dist/shims/document.js +15 -2
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +1 -1
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/hash-scroll.d.ts +1 -1
- package/dist/shims/hash-scroll.js +2 -1
- package/dist/shims/headers.d.ts +10 -13
- package/dist/shims/headers.js +85 -36
- package/dist/shims/internal/cookie-serialize.d.ts +10 -9
- package/dist/shims/internal/cookie-serialize.js +9 -8
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- package/dist/shims/link.d.ts +2 -0
- package/dist/shims/link.js +77 -24
- package/dist/shims/metadata.d.ts +18 -34
- package/dist/shims/metadata.js +98 -56
- package/dist/shims/navigation.d.ts +18 -2
- package/dist/shims/navigation.js +70 -21
- package/dist/shims/request-context.d.ts +6 -2
- package/dist/shims/router.js +18 -7
- package/dist/shims/script.js +1 -1
- package/dist/shims/server.d.ts +7 -6
- package/dist/shims/server.js +156 -57
- package/dist/shims/slot.d.ts +2 -1
- package/dist/shims/slot.js +6 -2
- package/dist/shims/streamed-icons.d.ts +9 -0
- package/dist/shims/streamed-icons.js +33 -0
- package/dist/shims/unified-request-context.d.ts +21 -2
- package/dist/shims/unified-request-context.js +82 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- package/dist/utils/html-limited-bots.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -345,24 +345,16 @@ Requires a custom domain (zone analytics are unavailable on `*.workers.dev`) and
|
|
|
345
345
|
|
|
346
346
|
#### Custom Vite configuration
|
|
347
347
|
|
|
348
|
-
If you need to customize the Vite config, create a `vite.config.ts`. vinext will merge its config with yours.
|
|
348
|
+
If you need to customize the Vite config, create a `vite.config.ts`. vinext will merge its config with yours. For Cloudflare Workers deployment with the App Router, configure `@cloudflare/vite-plugin` so the RSC environment runs in workerd:
|
|
349
349
|
|
|
350
350
|
```ts
|
|
351
351
|
import { defineConfig } from "vite";
|
|
352
352
|
import vinext from "vinext";
|
|
353
|
-
import rsc from "@vitejs/plugin-rsc";
|
|
354
353
|
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
355
354
|
|
|
356
355
|
export default defineConfig({
|
|
357
356
|
plugins: [
|
|
358
357
|
vinext(),
|
|
359
|
-
rsc({
|
|
360
|
-
entries: {
|
|
361
|
-
rsc: "virtual:vinext-rsc-entry",
|
|
362
|
-
ssr: "virtual:vinext-app-ssr-entry",
|
|
363
|
-
client: "virtual:vinext-app-browser-entry",
|
|
364
|
-
},
|
|
365
|
-
}),
|
|
366
358
|
cloudflare({
|
|
367
359
|
viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] },
|
|
368
360
|
}),
|
|
@@ -370,6 +362,11 @@ export default defineConfig({
|
|
|
370
362
|
});
|
|
371
363
|
```
|
|
372
364
|
|
|
365
|
+
> **Do not register `@vitejs/plugin-rsc` yourself.** It is an optional peer dependency, so it must be
|
|
366
|
+
> _installed_ in your project, but vinext auto-registers it whenever an `app/` directory is detected.
|
|
367
|
+
> Adding an explicit `rsc()` call fails the build with `[vinext] Duplicate @vitejs/plugin-rsc detected`.
|
|
368
|
+
> Pass `rsc: false` to `vinext()` only if you want to own that registration.
|
|
369
|
+
|
|
373
370
|
See the [examples](#live-examples) for complete working configurations.
|
|
374
371
|
|
|
375
372
|
### Other platforms (via Nitro)
|
|
@@ -89,7 +89,13 @@ function createClientManualChunks(shimsDir, preserveRouteBoundaries = false) {
|
|
|
89
89
|
if (id.includes("node_modules")) {
|
|
90
90
|
const pkg = getPackageName(id);
|
|
91
91
|
if (!pkg) return void 0;
|
|
92
|
-
if (pkg === "react
|
|
92
|
+
if (pkg === "react-dom") {
|
|
93
|
+
const slashedId = toSlash(id);
|
|
94
|
+
const sub = slashedId.slice(slashedId.lastIndexOf("react-dom/") + 10);
|
|
95
|
+
if (sub.startsWith("server.") || sub.startsWith("static.") || sub.startsWith("cjs/react-dom-server")) return "react-dom-server";
|
|
96
|
+
return "framework";
|
|
97
|
+
}
|
|
98
|
+
if (pkg === "react" || pkg === "scheduler") return "framework";
|
|
93
99
|
return;
|
|
94
100
|
}
|
|
95
101
|
const slashedId = toSlash(id);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { ASSET_PREFIX_URL_DIR } from "../utils/asset-prefix.js";
|
|
3
3
|
import fsp from "node:fs/promises";
|
|
4
|
+
import { promisify } from "node:util";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import zlib from "node:zlib";
|
|
6
|
-
import { promisify } from "node:util";
|
|
7
7
|
//#region src/build/precompress.ts
|
|
8
8
|
/**
|
|
9
9
|
* Build-time precompression for hashed static assets.
|
|
@@ -23,7 +23,8 @@ type PrerenderRouteResult = {
|
|
|
23
23
|
*/
|
|
24
24
|
path?: string; /** Which router produced this route. Used by cache seeding. */
|
|
25
25
|
router: "app" | "pages"; /** Response headers that must be replayed with the prerendered artifact. */
|
|
26
|
-
headers?: Record<string, string>; /**
|
|
26
|
+
headers?: Record<string, string>; /** Cache tags collected while rendering this route. */
|
|
27
|
+
tags?: string[]; /** Set to true when this is a PPR fallback shell. */
|
|
27
28
|
fallback?: boolean;
|
|
28
29
|
} | {
|
|
29
30
|
route: string;
|
package/dist/build/prerender.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { createValidFileMatcher, findFileWithExtensions } from "../routing/file-matcher.js";
|
|
3
3
|
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
4
|
-
import { VINEXT_PRERENDER_CACHE_LIFE_HEADER } from "../server/headers.js";
|
|
4
|
+
import { NEXT_CACHE_TAGS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER } from "../server/headers.js";
|
|
5
5
|
import { classifyAppRoute, classifyPagesRoute, getAppRouteRenderEntryPath } from "./report.js";
|
|
6
6
|
import { NoOpCacheHandler, getCacheHandler, setCacheHandler } from "../shims/cache-handler.js";
|
|
7
7
|
import { headersContextFromRequest, runWithHeadersContext } from "../shims/headers.js";
|
|
@@ -760,6 +760,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
760
760
|
const cacheControl = response.headers.get("cache-control") ?? "";
|
|
761
761
|
const linkHeader = response.headers.get("link");
|
|
762
762
|
const responseCacheLife = readPrerenderCacheLifeHeader(response.headers);
|
|
763
|
+
const cacheTags = readPrerenderCacheTagsHeader(response.headers);
|
|
763
764
|
if (!response.ok || cacheControl.includes("no-store")) {
|
|
764
765
|
await response.body?.cancel();
|
|
765
766
|
return {
|
|
@@ -768,6 +769,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
768
769
|
html: null,
|
|
769
770
|
ok: response.ok,
|
|
770
771
|
requestCacheLife: null,
|
|
772
|
+
tags: [],
|
|
771
773
|
status: response.status
|
|
772
774
|
};
|
|
773
775
|
}
|
|
@@ -779,7 +781,8 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
779
781
|
html,
|
|
780
782
|
ok: true,
|
|
781
783
|
requestCacheLife: responseCacheLife ?? processCacheLife,
|
|
782
|
-
status: response.status
|
|
784
|
+
status: response.status,
|
|
785
|
+
tags: cacheTags
|
|
783
786
|
};
|
|
784
787
|
});
|
|
785
788
|
const htmlCacheControl = htmlRender.cacheControl;
|
|
@@ -842,6 +845,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
842
845
|
revalidate: renderedRevalidate,
|
|
843
846
|
...typeof renderedRevalidate === "number" ? { expire: renderedCacheControl.expire } : {},
|
|
844
847
|
router: "app",
|
|
848
|
+
...htmlRender.tags.length > 0 ? { tags: htmlRender.tags } : {},
|
|
845
849
|
...htmlRender.linkHeader ? { headers: { link: htmlRender.linkHeader } } : {},
|
|
846
850
|
...urlPath !== routePattern ? { path: urlPath } : {},
|
|
847
851
|
...isFallback ? { fallback: true } : {}
|
|
@@ -945,6 +949,11 @@ function readPrerenderCacheLifeHeader(headers) {
|
|
|
945
949
|
return null;
|
|
946
950
|
}
|
|
947
951
|
}
|
|
952
|
+
function readPrerenderCacheTagsHeader(headers) {
|
|
953
|
+
const value = headers.get(NEXT_CACHE_TAGS_HEADER);
|
|
954
|
+
if (!value) return [];
|
|
955
|
+
return [...new Set(value.split(",").filter(Boolean))];
|
|
956
|
+
}
|
|
948
957
|
function resolveRenderedExpireSeconds(options) {
|
|
949
958
|
const { fallbackExpireSeconds, sMaxage, staleWhileRevalidate } = options;
|
|
950
959
|
if (sMaxage === void 0 || staleWhileRevalidate === void 0) return fallbackExpireSeconds;
|
|
@@ -976,6 +985,7 @@ function writePrerenderIndex(routes, outDir, options) {
|
|
|
976
985
|
revalidate: r.revalidate,
|
|
977
986
|
...typeof r.revalidate === "number" ? { expire: r.expire } : {},
|
|
978
987
|
router: r.router,
|
|
988
|
+
...r.tags && r.tags.length > 0 ? { tags: r.tags } : {},
|
|
979
989
|
...r.headers ? { headers: r.headers } : {},
|
|
980
990
|
...r.path ? { path: r.path } : {},
|
|
981
991
|
...r.fallback ? { fallback: true } : {}
|
package/dist/check.js
CHANGED
|
@@ -230,6 +230,10 @@ const CONFIG_SUPPORT = {
|
|
|
230
230
|
status: "supported",
|
|
231
231
|
detail: "server actions via 'use server' directive"
|
|
232
232
|
},
|
|
233
|
+
"experimental.allowedRevalidateHeaderKeys": {
|
|
234
|
+
status: "supported",
|
|
235
|
+
detail: "forwards explicitly allowed request headers during Pages Router revalidation"
|
|
236
|
+
},
|
|
233
237
|
"experimental.prefetchInlining": {
|
|
234
238
|
status: "partial",
|
|
235
239
|
detail: "config recognized; Link prefetch preserves pending/dedup semantics, but vinext does not implement per-segment cache storage"
|
package/dist/cli-args.d.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* CLI argument parser for the vinext CLI.
|
|
4
4
|
*
|
|
5
5
|
* Parses flags for `vinext dev`, `vinext start`, `vinext build`, etc.
|
|
6
|
-
* Validates that value-taking flags (`--port`, `--hostname`) have actual values
|
|
6
|
+
* Validates that value-taking flags (`--port`, `--hostname`, `--mode`) have actual values
|
|
7
7
|
* rather than silently consuming the next flag or returning NaN/undefined.
|
|
8
8
|
*/
|
|
9
9
|
type ParsedArgs = {
|
|
10
10
|
port?: number;
|
|
11
11
|
hostname?: string;
|
|
12
|
+
mode?: string;
|
|
12
13
|
help?: boolean;
|
|
13
14
|
verbose?: boolean;
|
|
14
15
|
turbopack?: boolean;
|
package/dist/cli-args.js
CHANGED
|
@@ -96,6 +96,10 @@ function parseArgs(args) {
|
|
|
96
96
|
result.hostname = takeValue(arg, args, i);
|
|
97
97
|
i++;
|
|
98
98
|
break;
|
|
99
|
+
case "--mode":
|
|
100
|
+
result.mode = takeValue(arg, args, i);
|
|
101
|
+
i++;
|
|
102
|
+
break;
|
|
99
103
|
default: {
|
|
100
104
|
const eqRaw = tryEqualsForm(arg, "port");
|
|
101
105
|
if (eqRaw !== null) {
|
|
@@ -108,6 +112,12 @@ function parseArgs(args) {
|
|
|
108
112
|
result.hostname = hostRaw;
|
|
109
113
|
break;
|
|
110
114
|
}
|
|
115
|
+
const modeRaw = tryEqualsForm(arg, "mode");
|
|
116
|
+
if (modeRaw !== null) {
|
|
117
|
+
if (modeRaw === "") throw new Error(`--mode requires a value, but none was provided.`);
|
|
118
|
+
result.mode = modeRaw;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
111
121
|
const prerenderConcurrencyRaw = tryEqualsForm(arg, "prerender-concurrency");
|
|
112
122
|
if (prerenderConcurrencyRaw !== null) {
|
|
113
123
|
result.prerenderConcurrency = parsePositiveIntegerArg(prerenderConcurrencyRaw, "--prerender-concurrency");
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { parseArgs } from "./cli-args.js";
|
|
|
6
6
|
import { createDevServerConfigPlugin, normalizeDevServerHostname } from "./cli-dev-config.js";
|
|
7
7
|
import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
|
|
8
8
|
import { createRscCompatibilityId, findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
|
|
9
|
+
import { loadDotenv } from "./config/dotenv.js";
|
|
9
10
|
import { generateRouteTypes } from "./typegen.js";
|
|
10
11
|
import { clearPagesClientAssetsBuildMetadata } from "./build/pages-client-assets-module.js";
|
|
11
12
|
import { runWithPreviewBuildCredentials } from "./build/preview-credentials.js";
|
|
@@ -16,7 +17,6 @@ import { emitPrerenderPathManifest } from "./build/prerender-paths.js";
|
|
|
16
17
|
import { getReactUpgradeDeps } from "./utils/react-version.js";
|
|
17
18
|
import { init } from "./init.js";
|
|
18
19
|
import { resolveInitOptions } from "./init-platform.js";
|
|
19
|
-
import { loadDotenv } from "./config/dotenv.js";
|
|
20
20
|
import { resolveVinextPackageRoot } from "./utils/vinext-root.js";
|
|
21
21
|
import { emitStandaloneOutput } from "./build/standalone.js";
|
|
22
22
|
import { cleanBuildOutput } from "./build/clean-output.js";
|
|
@@ -125,7 +125,7 @@ function createBuildLogger(vite) {
|
|
|
125
125
|
function hasPagesDir() {
|
|
126
126
|
return fs.existsSync(path.join(process.cwd(), "pages")) || fs.existsSync(path.join(process.cwd(), "src", "pages"));
|
|
127
127
|
}
|
|
128
|
-
async function loadBuildViteConfigMetadata(vite, root) {
|
|
128
|
+
async function loadBuildViteConfigMetadata(vite, root, mode) {
|
|
129
129
|
if (!hasViteConfig(root)) return {
|
|
130
130
|
nextConfig: null,
|
|
131
131
|
prerenderConfig: null,
|
|
@@ -133,7 +133,7 @@ async function loadBuildViteConfigMetadata(vite, root) {
|
|
|
133
133
|
};
|
|
134
134
|
const loaded = await vite.loadConfigFromFile({
|
|
135
135
|
command: "build",
|
|
136
|
-
mode
|
|
136
|
+
mode
|
|
137
137
|
}, void 0, root);
|
|
138
138
|
const emptyOutDir = loaded?.config.build?.emptyOutDir;
|
|
139
139
|
return {
|
|
@@ -148,14 +148,16 @@ async function loadBuildViteConfigMetadata(vite, root) {
|
|
|
148
148
|
* project, Vite will merge our config with it (theirs takes precedence).
|
|
149
149
|
* If there's no vite.config, this provides everything needed.
|
|
150
150
|
*/
|
|
151
|
-
function buildViteConfig(overrides = {}, logger) {
|
|
151
|
+
function buildViteConfig(overrides = {}, logger, mode) {
|
|
152
152
|
if (hasViteConfig(process.cwd())) return {
|
|
153
153
|
root: process.cwd(),
|
|
154
|
+
...mode ? { mode } : {},
|
|
154
155
|
...logger ? { customLogger: logger } : {},
|
|
155
156
|
...overrides
|
|
156
157
|
};
|
|
157
158
|
return {
|
|
158
159
|
root: process.cwd(),
|
|
160
|
+
...mode ? { mode } : {},
|
|
159
161
|
configFile: false,
|
|
160
162
|
plugins: [vinext()],
|
|
161
163
|
resolve: { dedupe: [
|
|
@@ -274,10 +276,12 @@ async function dev() {
|
|
|
274
276
|
async function buildApp() {
|
|
275
277
|
const parsed = parseArgs(rawArgs);
|
|
276
278
|
if (parsed.help) return printHelp("build");
|
|
279
|
+
const buildMode = parsed.mode ?? "production";
|
|
280
|
+
if (!process.env.NODE_ENV) Reflect.set(process.env, "NODE_ENV", "production");
|
|
277
281
|
if (parsed.precompress) process.env.VINEXT_PRECOMPRESS = "1";
|
|
278
282
|
loadDotenv({
|
|
279
283
|
root: process.cwd(),
|
|
280
|
-
mode:
|
|
284
|
+
mode: buildMode
|
|
281
285
|
});
|
|
282
286
|
applyViteConfigCompatibility(process.cwd());
|
|
283
287
|
const vite = await loadVite();
|
|
@@ -285,7 +289,7 @@ async function buildApp() {
|
|
|
285
289
|
console.log(`\n vinext build (Vite ${getViteVersion()})\n`);
|
|
286
290
|
const root = toSlash(process.cwd());
|
|
287
291
|
const isApp = hasAppDir(root);
|
|
288
|
-
const buildConfigMetadata = await loadBuildViteConfigMetadata(vite, root);
|
|
292
|
+
const buildConfigMetadata = await loadBuildViteConfigMetadata(vite, root, buildMode);
|
|
289
293
|
const resolvedNextConfig = await resolveNextConfig(buildConfigMetadata.nextConfig ? await resolveNextConfigInput(buildConfigMetadata.nextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(root, PHASE_PRODUCTION_BUILD), root);
|
|
290
294
|
process.env.__VINEXT_SHARED_BUILD_ID = resolvedNextConfig.buildId;
|
|
291
295
|
process.env.__VINEXT_SHARED_RSC_COMPATIBILITY_ID = createRscCompatibilityId(resolvedNextConfig);
|
|
@@ -322,7 +326,7 @@ async function buildApp() {
|
|
|
322
326
|
if (pagesClientAssetsBuildSession) process.env.__VINEXT_PAGES_CLIENT_ASSETS_BUILD_SESSION = pagesClientAssetsBuildSession;
|
|
323
327
|
await runWithPreviewBuildCredentials(async () => {
|
|
324
328
|
try {
|
|
325
|
-
const config = buildViteConfig({}, logger);
|
|
329
|
+
const config = buildViteConfig({}, logger, buildMode);
|
|
326
330
|
await (await vite.createBuilder(config)).buildApp();
|
|
327
331
|
if (isHybrid) {
|
|
328
332
|
console.log(" Building Pages Router server (hybrid)...");
|
|
@@ -331,13 +335,14 @@ async function buildApp() {
|
|
|
331
335
|
if (hasViteConfig(process.cwd())) {
|
|
332
336
|
const loaded = await vite.loadConfigFromFile({
|
|
333
337
|
command: "build",
|
|
334
|
-
mode:
|
|
338
|
+
mode: buildMode,
|
|
335
339
|
isSsrBuild: true
|
|
336
340
|
}, void 0, root);
|
|
337
341
|
if (loaded?.config.plugins) userTransformPlugins = loaded.config.plugins.flat(Infinity).filter((p) => !!p && typeof p.name === "string" && !p.name.startsWith("vinext:") && !p.name.startsWith("vite:react") && !p.name.startsWith("rsc:") && p.name !== "vite-rsc-load-module-dev-proxy" && !p.name.startsWith("vite-plugin-cloudflare"));
|
|
338
342
|
}
|
|
339
343
|
await vite.build({
|
|
340
344
|
root,
|
|
345
|
+
mode: buildMode,
|
|
341
346
|
configFile: false,
|
|
342
347
|
plugins: [...userTransformPlugins, vinext({ disableAppRouter: true })],
|
|
343
348
|
resolve: { dedupe: [
|
|
@@ -536,6 +541,7 @@ function printHelp(cmd) {
|
|
|
536
541
|
to vinext({ prerender: true }) and takes priority.
|
|
537
542
|
--prerender-concurrency <count>
|
|
538
543
|
Maximum number of routes to pre-render in parallel
|
|
544
|
+
--mode <mode> Load .env.<mode>* files and pass mode to Vite
|
|
539
545
|
--precompress Precompress static assets at build time (.br, .gz, .zst)
|
|
540
546
|
-h, --help Show this help
|
|
541
547
|
`);
|
|
@@ -18,6 +18,10 @@ type NavigationRuntimeRscBootstrap = {
|
|
|
18
18
|
type NavigationRuntimeKind = "navigate" | "traverse" | "refresh";
|
|
19
19
|
type NavigationRuntimeHistoryUpdateMode = "push" | "replace";
|
|
20
20
|
type NavigationRuntimeVisibleCommitMode = "transition" | "synchronous";
|
|
21
|
+
type NavigationRuntimePrefetchRouterState = {
|
|
22
|
+
pathAndSearch: string;
|
|
23
|
+
routeId: string;
|
|
24
|
+
};
|
|
21
25
|
type NavigationRuntimeTraversalIntent = {
|
|
22
26
|
direction: "back" | "forward" | "unknown";
|
|
23
27
|
historyState: unknown;
|
|
@@ -29,6 +33,7 @@ type NavigationRuntimeFunctions = {
|
|
|
29
33
|
commitHashNavigation?: (href: string, historyUpdateMode: NavigationRuntimeHistoryUpdateMode, scroll: boolean) => void;
|
|
30
34
|
navigateExternal?: (href: string, historyUpdateMode: NavigationRuntimeHistoryUpdateMode) => Promise<void>;
|
|
31
35
|
navigate?: NavigationRuntimeNavigate;
|
|
36
|
+
getPrefetchRouterState?: () => NavigationRuntimePrefetchRouterState | null;
|
|
32
37
|
/**
|
|
33
38
|
* Called at the start of every App Router navigation so the <Link> shim can
|
|
34
39
|
* reset any link that is still showing a `useLinkStatus()` pending state but
|
|
@@ -38,6 +43,7 @@ type NavigationRuntimeFunctions = {
|
|
|
38
43
|
*/
|
|
39
44
|
notifyLinkNavigationStart?: () => void;
|
|
40
45
|
pingVisibleLinks?: () => void;
|
|
46
|
+
preparePrefetchResponse?: (response: Response) => Promise<unknown>;
|
|
41
47
|
};
|
|
42
48
|
type NavigationRuntimeBootstrap = {
|
|
43
49
|
routeManifest: RouteManifest | null;
|
|
@@ -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, "notifyLinkNavigationStart")) && 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, "getPrefetchRouterState")) && isOptionalRuntimeFunction(Reflect.get(value, "notifyLinkNavigationStart")) && isOptionalRuntimeFunction(Reflect.get(value, "pingVisibleLinks")) && isOptionalRuntimeFunction(Reflect.get(value, "preparePrefetchResponse"));
|
|
35
35
|
}
|
|
36
36
|
function isNavigationRuntimeRscChunk(value) {
|
|
37
37
|
if (typeof value === "string") return true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../utils/protocol-headers.js";
|
|
1
|
+
import { PRERENDER_REVALIDATE_HEADER, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
|
|
2
2
|
import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
|
|
3
3
|
import { analyzeRegexSafety } from "../utils/regex-safety.js";
|
|
4
4
|
import { normalizeHost, parseCookies, requestContextFromRequest } from "./request-context.js";
|
|
@@ -835,6 +835,9 @@ async function proxyExternalRequest(request, externalUrl) {
|
|
|
835
835
|
for (const key of keysToDelete) headers.delete(key);
|
|
836
836
|
headers.delete(VINEXT_PRERENDER_SECRET_HEADER);
|
|
837
837
|
headers.delete(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER);
|
|
838
|
+
headers.delete(PRERENDER_REVALIDATE_HEADER);
|
|
839
|
+
headers.delete(PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER);
|
|
840
|
+
headers.delete(VINEXT_REVALIDATE_HOST_HEADER);
|
|
838
841
|
headers.delete(VINEXT_MW_CTX_HEADER);
|
|
839
842
|
const method = request.method;
|
|
840
843
|
const hasBody = method !== "GET" && method !== "HEAD";
|
package/dist/config/dotenv.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/config/dotenv.d.ts
|
|
2
|
-
type VinextEnvMode = "development" | "production" | "test";
|
|
3
2
|
/**
|
|
4
3
|
* Environment-variable bag accepted by {@link loadDotenv}.
|
|
5
4
|
*
|
|
@@ -12,18 +11,18 @@ type VinextEnvMode = "development" | "production" | "test";
|
|
|
12
11
|
type EnvBag = Record<string, string | undefined>;
|
|
13
12
|
type LoadDotenvOptions = {
|
|
14
13
|
root: string;
|
|
15
|
-
mode:
|
|
14
|
+
mode: string;
|
|
16
15
|
processEnv?: EnvBag;
|
|
17
16
|
};
|
|
18
17
|
type LoadDotenvResult = {
|
|
19
|
-
mode:
|
|
18
|
+
mode: string;
|
|
20
19
|
loadedFiles: string[];
|
|
21
20
|
loadedEnv: Record<string, string>;
|
|
22
21
|
};
|
|
23
22
|
/**
|
|
24
23
|
* Next.js-compatible dotenv lookup order (highest priority first).
|
|
25
24
|
*/
|
|
26
|
-
declare function getDotenvFiles(mode:
|
|
25
|
+
declare function getDotenvFiles(mode: string): string[];
|
|
27
26
|
/**
|
|
28
27
|
* Load .env files into processEnv with Next.js-like precedence:
|
|
29
28
|
* process.env > .env.<mode>.local > .env.local > .env.<mode> > .env.
|
package/dist/config/dotenv.js
CHANGED
|
@@ -56,33 +56,41 @@ function loadDotenv({ root, mode, processEnv = process.env }) {
|
|
|
56
56
|
loadedEnv
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
const ENV_REF_RE = /(\\)?\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g;
|
|
60
59
|
function expandEnv(parsed, processEnv) {
|
|
61
|
-
const expanded = {};
|
|
62
|
-
const
|
|
63
|
-
|
|
60
|
+
const expanded = { ...parsed };
|
|
61
|
+
for (const key of Object.keys(expanded)) {
|
|
62
|
+
const processValue = processEnv[key];
|
|
63
|
+
expanded[key] = (processValue && processValue !== expanded[key] ? processValue : expandValue(expanded[key], processEnv, expanded)).replace(/\\\$/g, "$");
|
|
64
|
+
}
|
|
65
|
+
return expanded;
|
|
66
|
+
}
|
|
67
|
+
function expandValue(value, processEnv, parsed) {
|
|
68
|
+
const env = {
|
|
64
69
|
...parsed,
|
|
65
70
|
...processEnv
|
|
66
71
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
const envRefRe = /(?<!\\)\${([^{}]+)}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
73
|
+
const seen = /* @__PURE__ */ new Set();
|
|
74
|
+
let result = value;
|
|
75
|
+
let match;
|
|
76
|
+
while ((match = envRefRe.exec(result)) !== null) {
|
|
77
|
+
seen.add(result);
|
|
78
|
+
const [template, braced, bare] = match;
|
|
79
|
+
const expression = braced || bare;
|
|
80
|
+
const operator = expression.match(/(:\+|\+|:-|-)/)?.[0];
|
|
81
|
+
const parts = operator ? expression.split(operator) : [expression];
|
|
82
|
+
const refKey = parts.shift();
|
|
83
|
+
const operand = parts.join(operator ?? "");
|
|
84
|
+
const refValue = env[refKey];
|
|
85
|
+
let replacement;
|
|
86
|
+
if (operator === ":+" || operator === "+") replacement = refValue ? operand : "";
|
|
87
|
+
else if (refValue) replacement = seen.has(refValue) ? operand : refValue;
|
|
88
|
+
else replacement = operand;
|
|
89
|
+
result = result.replace(template, replacement);
|
|
90
|
+
if (result === parsed[refKey]) break;
|
|
91
|
+
envRefRe.lastIndex = 0;
|
|
83
92
|
}
|
|
84
|
-
|
|
85
|
-
return expanded;
|
|
93
|
+
return result;
|
|
86
94
|
}
|
|
87
95
|
//#endregion
|
|
88
96
|
export { getDotenvFiles, loadDotenv };
|
|
@@ -99,8 +99,13 @@ type NextConfig = {
|
|
|
99
99
|
* `basePath` affects route URLs; `assetPrefix` only affects asset URLs.
|
|
100
100
|
* @see https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix
|
|
101
101
|
*/
|
|
102
|
-
assetPrefix?: string; /**
|
|
103
|
-
|
|
102
|
+
assetPrefix?: string; /** Cross-origin mode applied to framework scripts and preload links. */
|
|
103
|
+
crossOrigin?: "anonymous" | "use-credentials"; /** Whether to add trailing slashes */
|
|
104
|
+
trailingSlash?: boolean; /** TypeScript build settings. */
|
|
105
|
+
typescript?: {
|
|
106
|
+
/** Project-relative path to the TypeScript configuration file. */tsconfigPath?: string;
|
|
107
|
+
[key: string]: unknown;
|
|
108
|
+
}; /** Internationalization routing config */
|
|
104
109
|
i18n?: NextI18nConfig; /** URL redirect rules */
|
|
105
110
|
redirects?: () => Promise<NextRedirect[]> | NextRedirect[]; /** URL rewrite rules */
|
|
106
111
|
rewrites?: () => Promise<NextRewrite[] | {
|
|
@@ -217,7 +222,8 @@ type NextConfig = {
|
|
|
217
222
|
prefetchInlining?: boolean | {
|
|
218
223
|
maxBundleSize?: number;
|
|
219
224
|
maxSize?: number;
|
|
220
|
-
};
|
|
225
|
+
}; /** Header names forwarded by Pages Router `res.revalidate()` internal requests. */
|
|
226
|
+
allowedRevalidateHeaderKeys?: string[];
|
|
221
227
|
[key: string]: unknown;
|
|
222
228
|
};
|
|
223
229
|
/**
|
|
@@ -266,6 +272,9 @@ type ResolvedNextConfig = {
|
|
|
266
272
|
*/
|
|
267
273
|
assetPrefix: string;
|
|
268
274
|
trailingSlash: boolean;
|
|
275
|
+
typescript: {
|
|
276
|
+
tsconfigPath?: string;
|
|
277
|
+
};
|
|
269
278
|
output: "" | "export" | "standalone";
|
|
270
279
|
pageExtensions: string[];
|
|
271
280
|
resolveExtensions: string[] | null;
|
|
@@ -295,7 +304,8 @@ type ResolvedNextConfig = {
|
|
|
295
304
|
mdx: MdxOptions | null; /** Explicit module aliases preserved from wrapped next.config plugins. */
|
|
296
305
|
aliases: Record<string, string>; /** Extra allowed origins for dev server access (from allowedDevOrigins). */
|
|
297
306
|
allowedDevOrigins: string[]; /** Extra allowed origins for server action CSRF validation (from experimental.serverActions.allowedOrigins). */
|
|
298
|
-
serverActionsAllowedOrigins: string[]; /**
|
|
307
|
+
serverActionsAllowedOrigins: string[]; /** Header names forwarded by Pages Router `res.revalidate()` internal requests. */
|
|
308
|
+
allowedRevalidateHeaderKeys: string[]; /** Packages whose barrel imports should be optimized (from experimental.optimizePackageImports). */
|
|
299
309
|
optimizePackageImports: string[]; /** Packages explicitly requested for server/client transpilation. */
|
|
300
310
|
transpilePackages: string[]; /** Packages treated as application code by Turbopack's foreign-code condition. */
|
|
301
311
|
turbopackTranspilePackages: string[]; /** Inline app CSS into production HTML (from experimental.inlineCss). */
|
|
@@ -373,7 +383,8 @@ type ResolvedNextConfig = {
|
|
|
373
383
|
* `defer={!disableOptimizedLoading}`) and the upstream
|
|
374
384
|
* `test/e2e/optimized-loading` test fixture.
|
|
375
385
|
*/
|
|
376
|
-
disableOptimizedLoading: boolean;
|
|
386
|
+
disableOptimizedLoading: boolean; /** Cross-origin mode applied to framework scripts and preload links. */
|
|
387
|
+
crossOrigin: "anonymous" | "use-credentials" | undefined;
|
|
377
388
|
/**
|
|
378
389
|
* Resolved `reactStrictMode` from next.config, preserved as `boolean | null`
|
|
379
390
|
* so each router can apply its own default (Next.js resolves `null` to OFF
|
|
@@ -658,6 +658,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
658
658
|
basePath: "",
|
|
659
659
|
assetPrefix: "",
|
|
660
660
|
trailingSlash: false,
|
|
661
|
+
typescript: {},
|
|
661
662
|
output: "",
|
|
662
663
|
pageExtensions: normalizePageExtensions(),
|
|
663
664
|
resolveExtensions: null,
|
|
@@ -679,6 +680,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
679
680
|
aliases: {},
|
|
680
681
|
allowedDevOrigins: [],
|
|
681
682
|
serverActionsAllowedOrigins: [],
|
|
683
|
+
allowedRevalidateHeaderKeys: [],
|
|
682
684
|
optimizePackageImports: [],
|
|
683
685
|
transpilePackages: [],
|
|
684
686
|
turbopackTranspilePackages: [...DEFAULT_TRANSPILED_PACKAGES],
|
|
@@ -700,6 +702,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
700
702
|
sassOptions: null,
|
|
701
703
|
removeConsole: false,
|
|
702
704
|
disableOptimizedLoading: false,
|
|
705
|
+
crossOrigin: void 0,
|
|
703
706
|
reactStrictMode: null,
|
|
704
707
|
scrollRestoration: false,
|
|
705
708
|
compilerDefine: {},
|
|
@@ -716,6 +719,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
716
719
|
detectNextIntlConfig(root, resolved);
|
|
717
720
|
return resolved;
|
|
718
721
|
}
|
|
722
|
+
if (config.crossOrigin !== void 0 && config.crossOrigin !== "anonymous" && config.crossOrigin !== "use-credentials") console.warn("Invalid next.config options detected:\n Invalid option at \"crossOrigin\": expected \"anonymous\" or \"use-credentials\"\nSee more info here: https://nextjs.org/docs/messages/invalid-next-config");
|
|
719
723
|
warnDeprecatedConfigOptions(config, root);
|
|
720
724
|
const i18n = normalizeI18nConfig(config.i18n);
|
|
721
725
|
let redirects = [];
|
|
@@ -833,6 +837,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
833
837
|
basePath: config.basePath ?? "",
|
|
834
838
|
assetPrefix: normalizeAssetPrefix(config.assetPrefix),
|
|
835
839
|
trailingSlash: config.trailingSlash ?? false,
|
|
840
|
+
typescript: typeof config.typescript?.tsconfigPath === "string" ? { tsconfigPath: config.typescript.tsconfigPath } : {},
|
|
836
841
|
output: output === "export" || output === "standalone" ? output : "",
|
|
837
842
|
pageExtensions,
|
|
838
843
|
resolveExtensions: resolveExtensions ?? webpackProbe.resolveExtensions,
|
|
@@ -851,6 +856,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
851
856
|
aliases,
|
|
852
857
|
allowedDevOrigins,
|
|
853
858
|
serverActionsAllowedOrigins,
|
|
859
|
+
allowedRevalidateHeaderKeys: Array.isArray(experimental?.allowedRevalidateHeaderKeys) ? experimental.allowedRevalidateHeaderKeys.filter((value) => typeof value === "string").map((value) => value.toLowerCase()) : [],
|
|
854
860
|
optimizePackageImports,
|
|
855
861
|
transpilePackages,
|
|
856
862
|
turbopackTranspilePackages,
|
|
@@ -872,6 +878,7 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
872
878
|
sassOptions: readOptionalRecord(config.sassOptions) ?? null,
|
|
873
879
|
removeConsole: config.compiler?.removeConsole === true ? true : isUnknownRecord(config.compiler?.removeConsole) ? { exclude: readStringArray(config.compiler.removeConsole.exclude) } : false,
|
|
874
880
|
disableOptimizedLoading: experimental?.disableOptimizedLoading === true,
|
|
881
|
+
crossOrigin: config.crossOrigin === "anonymous" || config.crossOrigin === "use-credentials" ? config.crossOrigin : void 0,
|
|
875
882
|
reactStrictMode: typeof config.reactStrictMode === "boolean" ? config.reactStrictMode : null,
|
|
876
883
|
scrollRestoration: experimental?.scrollRestoration === true,
|
|
877
884
|
compilerDefine: serializeCompilerDefine(config.compiler?.define),
|
|
@@ -15,15 +15,9 @@ declare function generateBrowserEntry(routes?: readonly AppRoute[], routeManifes
|
|
|
15
15
|
beforeFiles: NextRewrite[];
|
|
16
16
|
fallback: NextRewrite[];
|
|
17
17
|
}): string;
|
|
18
|
-
/**
|
|
19
|
-
* Filter for routes that should appear in the `__VINEXT_LINK_PREFETCH_ROUTES__`
|
|
20
|
-
* manifest. Exported so the Pages Router client entry can reuse it when
|
|
21
|
-
* emitting the same manifest for hybrid builds — see issue #1526 and
|
|
22
|
-
* `pages-client-entry.ts`.
|
|
23
|
-
*/
|
|
24
|
-
declare function isLinkPrefetchRoute(route: AppRoute): boolean;
|
|
25
|
-
declare function toDocumentOnlyAppRoute(route: AppRoute): VinextLinkPrefetchRoute;
|
|
26
18
|
/** Project an `AppRoute` down to the public `VinextLinkPrefetchRoute` shape. */
|
|
27
|
-
declare function toLinkPrefetchRoute(route: AppRoute): VinextLinkPrefetchRoute;
|
|
19
|
+
declare function toLinkPrefetchRoute(route: AppRoute, hasSiblingInterceptLoading?: boolean): VinextLinkPrefetchRoute;
|
|
20
|
+
/** Project App routes together so sibling-intercept loading is applied to its target route. */
|
|
21
|
+
declare function toLinkPrefetchRoutes(routes: readonly AppRoute[]): VinextLinkPrefetchRoute[];
|
|
28
22
|
//#endregion
|
|
29
|
-
export { generateBrowserEntry,
|
|
23
|
+
export { generateBrowserEntry, toLinkPrefetchRoute, toLinkPrefetchRoutes };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveClientRuntimeModule, resolveRuntimeEntryModule } from "./runtime-entry-module.js";
|
|
2
|
+
import { patternsStructurallyEquivalent } from "../routing/app-route-graph.js";
|
|
2
3
|
//#region src/entries/app-browser-entry.ts
|
|
3
4
|
/**
|
|
4
5
|
* Generate the virtual browser entry module.
|
|
@@ -14,7 +15,7 @@ function generateBrowserEntry(routes = [], routeManifest = null, pagesPrefetchRo
|
|
|
14
15
|
}) {
|
|
15
16
|
const entryPath = resolveRuntimeEntryModule("app-browser-entry");
|
|
16
17
|
const navigationRuntimePath = resolveClientRuntimeModule("navigation-runtime");
|
|
17
|
-
const prefetchRoutes = routes
|
|
18
|
+
const prefetchRoutes = toLinkPrefetchRoutes(routes);
|
|
18
19
|
return `import { registerNavigationRuntimeBootstrap } from ${JSON.stringify(navigationRuntimePath)};
|
|
19
20
|
|
|
20
21
|
window.__VINEXT_LINK_PREFETCH_ROUTES__ = ${JSON.stringify(prefetchRoutes)};
|
|
@@ -50,15 +51,30 @@ function toDocumentOnlyAppRoute(route) {
|
|
|
50
51
|
function requiresDynamicNavigationRequest(route) {
|
|
51
52
|
return route.isDynamic && route.parallelSlots.length > 0;
|
|
52
53
|
}
|
|
54
|
+
function splitPatternParts(pattern) {
|
|
55
|
+
return pattern.split("/").filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
function interceptTargetsRoute(interceptTargetPattern, route) {
|
|
58
|
+
return patternsStructurallyEquivalent(splitPatternParts(interceptTargetPattern), route.patternParts);
|
|
59
|
+
}
|
|
60
|
+
function hasLoadingBoundary(route, hasSiblingInterceptLoading) {
|
|
61
|
+
return route.loadingPath !== null || (route.loadingPaths?.some((_, index) => (route.loadingTreePositions?.[index] ?? 0) > 0) ?? false) || route.parallelSlots.some((slot) => slot.loadingPath !== null || (slot.loadingPaths?.length ?? 0) > 0 || slot.interceptingRoutes.some((intercept) => interceptTargetsRoute(intercept.targetPattern, route) && (intercept.loadingPaths?.length ?? 0) > 0)) || hasSiblingInterceptLoading;
|
|
62
|
+
}
|
|
53
63
|
/** Project an `AppRoute` down to the public `VinextLinkPrefetchRoute` shape. */
|
|
54
|
-
function toLinkPrefetchRoute(route) {
|
|
64
|
+
function toLinkPrefetchRoute(route, hasSiblingInterceptLoading = route.siblingIntercepts.some((intercept) => interceptTargetsRoute(intercept.targetPattern, route) && (intercept.loadingPaths?.length ?? 0) > 0)) {
|
|
55
65
|
return {
|
|
56
|
-
canPrefetchLoadingShell: route
|
|
66
|
+
canPrefetchLoadingShell: hasLoadingBoundary(route, hasSiblingInterceptLoading),
|
|
57
67
|
patternParts: [...route.patternParts],
|
|
58
68
|
isDynamic: route.isDynamic,
|
|
59
69
|
...requiresDynamicNavigationRequest(route) ? { requiresDynamicNavigationRequest: true } : {}
|
|
60
70
|
};
|
|
61
71
|
}
|
|
72
|
+
/** Project App routes together so sibling-intercept loading is applied to its target route. */
|
|
73
|
+
function toLinkPrefetchRoutes(routes) {
|
|
74
|
+
const siblingInterceptLoadingTargets = [];
|
|
75
|
+
for (const route of routes) for (const intercept of route.siblingIntercepts) if ((intercept.loadingPaths?.length ?? 0) > 0) siblingInterceptLoadingTargets.push(splitPatternParts(intercept.targetPattern));
|
|
76
|
+
return routes.map((route) => isLinkPrefetchRoute(route) ? toLinkPrefetchRoute(route, siblingInterceptLoadingTargets.some((targetParts) => patternsStructurallyEquivalent(targetParts, route.patternParts))) : toDocumentOnlyAppRoute(route));
|
|
77
|
+
}
|
|
62
78
|
function buildRouteManifestExpression(routeManifest) {
|
|
63
79
|
if (routeManifest === null) return "null";
|
|
64
80
|
const graph = routeManifest.segmentGraph;
|
|
@@ -84,4 +100,4 @@ function buildMapExpression(map) {
|
|
|
84
100
|
return `new Map(${JSON.stringify(Array.from(map.entries()))})`;
|
|
85
101
|
}
|
|
86
102
|
//#endregion
|
|
87
|
-
export { generateBrowserEntry,
|
|
103
|
+
export { generateBrowserEntry, toLinkPrefetchRoute, toLinkPrefetchRoutes };
|