vinext 0.2.0 → 0.2.1
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/dist/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +3 -0
- package/dist/build/inject-pregenerated-paths.js +4 -1
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.js +86 -22
- package/dist/build/run-prerender.js +2 -1
- package/dist/check.d.ts +4 -6
- package/dist/check.js +8 -9
- package/dist/cli.js +1 -1
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/config/config-matchers.js +33 -11
- package/dist/config/next-config.d.ts +36 -6
- package/dist/config/next-config.js +16 -2
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -2
- package/dist/entries/app-rsc-entry.js +4 -0
- package/dist/entries/pages-client-entry.js +14 -3
- package/dist/entries/pages-server-entry.js +18 -4
- package/dist/index.js +320 -25
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
- package/dist/packages/cloudflare/src/deploy.js +1 -5
- package/dist/packages/cloudflare/src/tpr.js +26 -5
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/routing/app-route-graph.js +22 -16
- package/dist/routing/file-matcher.d.ts +8 -1
- package/dist/routing/file-matcher.js +15 -3
- package/dist/server/app-browser-entry.js +46 -14
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +5 -3
- package/dist/server/app-browser-state.d.ts +1 -0
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +3 -3
- package/dist/server/app-page-cache.js +23 -6
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +25 -8
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-render-identity.d.ts +1 -0
- package/dist/server/app-page-render-identity.js +2 -1
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +67 -16
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -4
- package/dist/server/app-rsc-handler.d.ts +6 -0
- package/dist/server/app-rsc-handler.js +89 -11
- 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.d.ts +3 -4
- package/dist/server/app-rsc-request-normalization.js +4 -5
- package/dist/server/app-server-action-execution.js +4 -3
- package/dist/server/app-ssr-entry.js +3 -3
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +78 -20
- package/dist/server/headers.d.ts +6 -2
- package/dist/server/headers.js +11 -5
- package/dist/server/isr-cache.d.ts +2 -1
- package/dist/server/isr-cache.js +7 -3
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +12 -1
- package/dist/server/pages-node-compat.js +50 -1
- package/dist/server/pages-page-data.d.ts +9 -0
- package/dist/server/pages-page-data.js +17 -9
- package/dist/server/pages-page-handler.js +19 -7
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.d.ts +8 -6
- package/dist/server/pages-request-pipeline.js +30 -6
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prod-server.d.ts +4 -2
- package/dist/server/prod-server.js +38 -22
- package/dist/server/request-pipeline.js +1 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.js +3 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
- package/dist/shims/internal/pages-data-target.d.ts +8 -3
- package/dist/shims/internal/pages-data-target.js +9 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +179 -42
- package/dist/shims/navigation.d.ts +15 -3
- package/dist/shims/navigation.js +202 -39
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/router.js +31 -15
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/middleware-request-headers.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/vite-version.d.ts +2 -0
- package/dist/utils/vite-version.js +11 -1
- package/package.json +2 -2
package/dist/check.d.ts
CHANGED
|
@@ -60,9 +60,8 @@ declare function hasFreeCjsGlobal(content: string): boolean;
|
|
|
60
60
|
/**
|
|
61
61
|
* Scan source files for `import ... from 'next/...'` statements.
|
|
62
62
|
*
|
|
63
|
-
* `root` must be forward-slash: it is passed to `findSourceFiles
|
|
64
|
-
* requires it
|
|
65
|
-
* a canonical relative path when both operands are forward-slash.
|
|
63
|
+
* `root` must be forward-slash: it is passed to `findSourceFiles`, which
|
|
64
|
+
* requires it.
|
|
66
65
|
*/
|
|
67
66
|
declare function scanImports(root: string): CheckItem[];
|
|
68
67
|
/**
|
|
@@ -82,9 +81,8 @@ declare function checkLibraries(root: string): CheckItem[];
|
|
|
82
81
|
/**
|
|
83
82
|
* Check file conventions (pages, app directory, middleware, etc.)
|
|
84
83
|
*
|
|
85
|
-
* `root` must be forward-slash — joined with `path.posix.join
|
|
86
|
-
* `findDir
|
|
87
|
-
* `runCheck`, which normalizes it.
|
|
84
|
+
* `root` must be forward-slash — joined with `path.posix.join` and passed to
|
|
85
|
+
* `findDir`. Only called from `runCheck`, which normalizes it.
|
|
88
86
|
*/
|
|
89
87
|
declare function checkConventions(root: string): CheckItem[];
|
|
90
88
|
/**
|
package/dist/check.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { detectPackageManager, findDir } 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";
|
|
@@ -300,7 +301,7 @@ const CONFIG_SUPPORT = {
|
|
|
300
301
|
},
|
|
301
302
|
reactStrictMode: {
|
|
302
303
|
status: "partial",
|
|
303
|
-
detail: "
|
|
304
|
+
detail: "enforced for the Pages Router (client root wrapped in <React.StrictMode> when true); App Router is not yet wrapped (Next.js defaults App Router strict mode on)"
|
|
304
305
|
},
|
|
305
306
|
poweredByHeader: {
|
|
306
307
|
status: "supported",
|
|
@@ -588,9 +589,8 @@ function hasFreeCjsGlobal(content) {
|
|
|
588
589
|
/**
|
|
589
590
|
* Scan source files for `import ... from 'next/...'` statements.
|
|
590
591
|
*
|
|
591
|
-
* `root` must be forward-slash: it is passed to `findSourceFiles
|
|
592
|
-
* requires it
|
|
593
|
-
* a canonical relative path when both operands are forward-slash.
|
|
592
|
+
* `root` must be forward-slash: it is passed to `findSourceFiles`, which
|
|
593
|
+
* requires it.
|
|
594
594
|
*/
|
|
595
595
|
function scanImports(root) {
|
|
596
596
|
const files = findSourceFiles(root);
|
|
@@ -608,7 +608,7 @@ function scanImports(root) {
|
|
|
608
608
|
if (mod.startsWith("next/") || mod === "next" || mod === "server-only" || mod === "client-only") {
|
|
609
609
|
const normalized = mod === "next" ? "next" : mod;
|
|
610
610
|
if (!importUsage.has(normalized)) importUsage.set(normalized, []);
|
|
611
|
-
const relFile = path.
|
|
611
|
+
const relFile = normalizePathSeparators(path.relative(root, file));
|
|
612
612
|
const usedInFiles = importUsage.get(normalized) ?? [];
|
|
613
613
|
if (!usedInFiles.includes(relFile)) usedInFiles.push(relFile);
|
|
614
614
|
}
|
|
@@ -830,9 +830,8 @@ function checkLibraries(root) {
|
|
|
830
830
|
/**
|
|
831
831
|
* Check file conventions (pages, app directory, middleware, etc.)
|
|
832
832
|
*
|
|
833
|
-
* `root` must be forward-slash — joined with `path.posix.join
|
|
834
|
-
* `findDir
|
|
835
|
-
* `runCheck`, which normalizes it.
|
|
833
|
+
* `root` must be forward-slash — joined with `path.posix.join` and passed to
|
|
834
|
+
* `findDir`. Only called from `runCheck`, which normalizes it.
|
|
836
835
|
*/
|
|
837
836
|
function checkConventions(root) {
|
|
838
837
|
const items = [];
|
|
@@ -931,7 +930,7 @@ function checkConventions(root) {
|
|
|
931
930
|
const cjsGlobalFiles = [];
|
|
932
931
|
for (const file of allSourceFiles) {
|
|
933
932
|
const content = fs.readFileSync(file, "utf-8");
|
|
934
|
-
const rel = path.
|
|
933
|
+
const rel = normalizePathSeparators(path.relative(root, file));
|
|
935
934
|
if (viewTransitionRegex.test(content)) viewTransitionFiles.push(rel);
|
|
936
935
|
if (hasFreeCjsGlobal(content)) cjsGlobalFiles.push(rel);
|
|
937
936
|
}
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { detectPackageManager, ensureViteConfigCompatibility, hasAppDir, hasViteConfig } from "./utils/project.js";
|
|
3
|
+
import { normalizePathSeparators } from "./utils/path.js";
|
|
3
4
|
import { formatReport, runCheck } from "./check.js";
|
|
4
5
|
import { parseArgs } from "./cli-args.js";
|
|
5
6
|
import { createDevServerConfigPlugin, normalizeDevServerHostname } from "./cli-dev-config.js";
|
|
6
|
-
import { normalizePathSeparators } from "./utils/path.js";
|
|
7
7
|
import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
|
|
8
8
|
import { createRscCompatibilityId, loadNextConfig, resolveNextConfig } from "./config/next-config.js";
|
|
9
9
|
import { generateRouteTypes } from "./typegen.js";
|
|
@@ -6,6 +6,7 @@ type VinextLinkPrefetchRoute = {
|
|
|
6
6
|
documentOnly?: boolean;
|
|
7
7
|
isDynamic: boolean;
|
|
8
8
|
patternParts: string[];
|
|
9
|
+
requiresDynamicNavigationRequest?: boolean;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
11
12
|
* Pages Router route pattern exposed to the client so the App Router's
|
|
@@ -22,13 +23,15 @@ type VinextPagesLinkPrefetchRoute = {
|
|
|
22
23
|
documentOnly?: boolean;
|
|
23
24
|
isDynamic: boolean;
|
|
24
25
|
patternParts: string[];
|
|
26
|
+
requiresDynamicNavigationRequest?: boolean;
|
|
25
27
|
};
|
|
26
28
|
type VinextNextData = {
|
|
27
29
|
/** vinext-specific additions (not part of Next.js upstream). */__vinext?: {
|
|
28
30
|
/** Absolute URL of the page module for dynamic import. */pageModuleUrl?: string; /** Absolute URL of the `_app` module for dynamic import. */
|
|
29
31
|
appModuleUrl?: string; /** True when the Pages Router server has middleware/proxy configured. */
|
|
30
32
|
hasMiddleware?: boolean; /** True when build-time rewrites can affect the initial Pages Router ready state. */
|
|
31
|
-
hasRewrites?: boolean;
|
|
33
|
+
hasRewrites?: boolean; /** Server-resolved Pages route URL used to hydrate fallback shells behind rewrites. */
|
|
34
|
+
routeUrl?: string;
|
|
32
35
|
};
|
|
33
36
|
} & NEXT_DATA;
|
|
34
37
|
type BrowserVinextNextData = NonNullable<Window["__NEXT_DATA__"]> & VinextNextData;
|
|
@@ -133,7 +133,7 @@ function _getRedirectIndex(redirects) {
|
|
|
133
133
|
const alternation = m[1];
|
|
134
134
|
const optional = m[2] === "?";
|
|
135
135
|
const suffix = "/" + m[3];
|
|
136
|
-
const altRe = safeRegExp("^(?:" + alternation + ")$");
|
|
136
|
+
const altRe = safeRegExp("^(?:" + alternation + ")$", "i");
|
|
137
137
|
if (!altRe) {
|
|
138
138
|
linear.push([i, redirect]);
|
|
139
139
|
continue;
|
|
@@ -145,9 +145,10 @@ function _getRedirectIndex(redirects) {
|
|
|
145
145
|
redirect,
|
|
146
146
|
originalIndex: i
|
|
147
147
|
};
|
|
148
|
-
const
|
|
148
|
+
const bucketKey = suffix.toLowerCase();
|
|
149
|
+
const bucket = localeStatic.get(bucketKey);
|
|
149
150
|
if (bucket) bucket.push(entry);
|
|
150
|
-
else localeStatic.set(
|
|
151
|
+
else localeStatic.set(bucketKey, [entry]);
|
|
151
152
|
} else linear.push([i, redirect]);
|
|
152
153
|
}
|
|
153
154
|
index = {
|
|
@@ -393,7 +394,7 @@ function normalizeHost(hostHeader, fallbackHostname) {
|
|
|
393
394
|
*/
|
|
394
395
|
function applyMiddlewareRequestHeaders(middlewareHeaders, request, options = {}) {
|
|
395
396
|
const nextHeaders = buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders, options);
|
|
396
|
-
for (const key of Object.keys(middlewareHeaders)) if (key.startsWith("x-middleware-")) delete middlewareHeaders[key];
|
|
397
|
+
for (const key of Object.keys(middlewareHeaders)) if (key.startsWith("x-middleware-") && key !== "x-middleware-cache") delete middlewareHeaders[key];
|
|
397
398
|
if (nextHeaders) request = new Request(request.url, {
|
|
398
399
|
method: request.method,
|
|
399
400
|
headers: nextHeaders,
|
|
@@ -529,6 +530,12 @@ function extractConstraint(str, re) {
|
|
|
529
530
|
function stripTrailingSlashForConfigMatch(value) {
|
|
530
531
|
return value.length > 1 && value.endsWith("/") ? value.slice(0, -1) : value;
|
|
531
532
|
}
|
|
533
|
+
function configPathEquals(a, b) {
|
|
534
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
535
|
+
}
|
|
536
|
+
function configPathStartsWith(pathname, prefix) {
|
|
537
|
+
return pathname.slice(0, prefix.length).toLowerCase() === prefix.toLowerCase();
|
|
538
|
+
}
|
|
532
539
|
function matchConfigPattern(pathname, pattern) {
|
|
533
540
|
const pathnameHadTrailingSlash = pathname.length > 1 && pathname.endsWith("/");
|
|
534
541
|
pathname = stripTrailingSlashForConfigMatch(pathname);
|
|
@@ -558,7 +565,7 @@ function matchConfigPattern(pathname, pattern) {
|
|
|
558
565
|
}
|
|
559
566
|
} else if (tok[0] === ".") regexStr += "\\.";
|
|
560
567
|
else regexStr += tok[0];
|
|
561
|
-
const re = safeRegExp("^" + regexStr + "$");
|
|
568
|
+
const re = safeRegExp("^" + regexStr + "$", "i");
|
|
562
569
|
return re ? {
|
|
563
570
|
re,
|
|
564
571
|
paramNames
|
|
@@ -577,7 +584,7 @@ function matchConfigPattern(pathname, pattern) {
|
|
|
577
584
|
const paramName = catchAllMatch[1];
|
|
578
585
|
const isPlus = catchAllMatch[2] === "+";
|
|
579
586
|
const prefixNoSlash = prefix.replace(/\/$/, "");
|
|
580
|
-
if (!pathname
|
|
587
|
+
if (!configPathStartsWith(pathname, prefixNoSlash)) return null;
|
|
581
588
|
const charAfter = pathname[prefixNoSlash.length];
|
|
582
589
|
if (charAfter !== void 0 && charAfter !== "/") return null;
|
|
583
590
|
const rest = pathname.slice(prefixNoSlash.length);
|
|
@@ -590,7 +597,7 @@ function matchConfigPattern(pathname, pattern) {
|
|
|
590
597
|
if (parts.length !== pathParts.length) return null;
|
|
591
598
|
const params = Object.create(null);
|
|
592
599
|
for (let i = 0; i < parts.length; i++) if (parts[i].startsWith(":")) params[parts[i].slice(1)] = pathParts[i];
|
|
593
|
-
else if (parts[i]
|
|
600
|
+
else if (!configPathEquals(parts[i], pathParts[i])) return null;
|
|
594
601
|
return params;
|
|
595
602
|
}
|
|
596
603
|
/**
|
|
@@ -635,7 +642,7 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
|
|
|
635
642
|
let localeMatch = null;
|
|
636
643
|
let localeMatchIndex = Infinity;
|
|
637
644
|
if (index.localeStatic.size > 0) {
|
|
638
|
-
const noLocaleBucket = index.localeStatic.get(normalizedPathname);
|
|
645
|
+
const noLocaleBucket = index.localeStatic.get(normalizedPathname.toLowerCase());
|
|
639
646
|
if (noLocaleBucket) for (const entry of noLocaleBucket) {
|
|
640
647
|
if (!entry.optional) continue;
|
|
641
648
|
if (entry.originalIndex >= localeMatchIndex) continue;
|
|
@@ -657,7 +664,7 @@ function matchRedirect(pathname, redirects, ctx, basePathState = _BASEPATH_DEFAU
|
|
|
657
664
|
if (slashTwo !== -1) {
|
|
658
665
|
const suffix = normalizedPathname.slice(slashTwo);
|
|
659
666
|
const localePart = normalizedPathname.slice(1, slashTwo);
|
|
660
|
-
const localeBucket = index.localeStatic.get(suffix);
|
|
667
|
+
const localeBucket = index.localeStatic.get(suffix.toLowerCase());
|
|
661
668
|
if (localeBucket) for (const entry of localeBucket) {
|
|
662
669
|
if (entry.originalIndex >= localeMatchIndex) continue;
|
|
663
670
|
if (!entry.altRe.test(localePart)) continue;
|
|
@@ -748,7 +755,22 @@ function substituteDestinationParams(destination, params) {
|
|
|
748
755
|
paramRe = new RegExp(`:(${paramAlternation})([+*])?(?![A-Za-z0-9_])`, "g");
|
|
749
756
|
_compiledDestinationParamCache.set(cacheKey, paramRe);
|
|
750
757
|
}
|
|
751
|
-
|
|
758
|
+
const replaceParams = (value, encodeParam) => value.replace(paramRe, (_token, key) => encodeParam(params[key]));
|
|
759
|
+
const hashIndex = destination.indexOf("#");
|
|
760
|
+
const beforeHash = hashIndex === -1 ? destination : destination.slice(0, hashIndex);
|
|
761
|
+
const hash = hashIndex === -1 ? "" : destination.slice(hashIndex);
|
|
762
|
+
const queryIndex = beforeHash.indexOf("?");
|
|
763
|
+
if (queryIndex !== -1) {
|
|
764
|
+
const beforeQuery = beforeHash.slice(0, queryIndex);
|
|
765
|
+
const query = beforeHash.slice(queryIndex + 1);
|
|
766
|
+
return `${replaceParams(beforeQuery, (value) => value)}?${replaceParams(query, encodeDestinationQueryParamValue)}${replaceParams(hash, (value) => value)}`;
|
|
767
|
+
}
|
|
768
|
+
return replaceParams(destination, (value) => value);
|
|
769
|
+
}
|
|
770
|
+
function encodeDestinationQueryParamValue(value) {
|
|
771
|
+
const params = new URLSearchParams();
|
|
772
|
+
params.set("", value);
|
|
773
|
+
return params.toString().slice(1);
|
|
752
774
|
}
|
|
753
775
|
/**
|
|
754
776
|
* Substitute params into a redirect/rewrite destination and sanitize the
|
|
@@ -964,7 +986,7 @@ function matchHeaders(pathname, headers, ctx, basePathState = _BASEPATH_DEFAULT)
|
|
|
964
986
|
for (const rule of headers) {
|
|
965
987
|
if (!shouldEvaluateRule(rule.basePath, basePathState)) continue;
|
|
966
988
|
const source = pathnameHadTrailingSlash ? stripTrailingSlashForConfigMatch(rule.source) : rule.source;
|
|
967
|
-
const sourceRegex = getCachedRegex(_compiledHeaderSourceCache, source, () => safeRegExp("^" + escapeHeaderSource(source) + "$"));
|
|
989
|
+
const sourceRegex = getCachedRegex(_compiledHeaderSourceCache, source, () => safeRegExp("^" + escapeHeaderSource(source) + "$", "i"));
|
|
968
990
|
if (sourceRegex && sourceRegex.test(pathname)) {
|
|
969
991
|
if (rule.has || rule.missing) {
|
|
970
992
|
if (!checkHasConditions(rule.has, rule.missing, ctx)) continue;
|
|
@@ -82,6 +82,10 @@ type MdxOptions = {
|
|
|
82
82
|
rehypePlugins?: unknown[];
|
|
83
83
|
recmaPlugins?: unknown[];
|
|
84
84
|
};
|
|
85
|
+
type PrefetchInliningConfig = false | {
|
|
86
|
+
maxBundleSize: number;
|
|
87
|
+
maxSize: number;
|
|
88
|
+
};
|
|
85
89
|
type NextConfig = {
|
|
86
90
|
/** Additional env variables */env?: Record<string, string>; /** Base URL path prefix */
|
|
87
91
|
basePath?: string;
|
|
@@ -123,7 +127,15 @@ type NextConfig = {
|
|
|
123
127
|
dangerouslyAllowLocalIP?: boolean; /** Content-Disposition header for image responses. Defaults to "inline". */
|
|
124
128
|
contentDispositionType?: "inline" | "attachment"; /** Content-Security-Policy header for image responses. Defaults to "script-src 'none'; frame-src 'none'; sandbox;" */
|
|
125
129
|
contentSecurityPolicy?: string;
|
|
126
|
-
};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Enable React Strict Mode. When `true`, the client root is wrapped in
|
|
133
|
+
* `<React.StrictMode>` so React runs its dev-only strict checks (double-
|
|
134
|
+
* invoked effects/render, deprecation warnings). `null`/unset resolves per
|
|
135
|
+
* router: OFF for the Pages Router, ON for the App Router — matching Next.js.
|
|
136
|
+
* @see https://nextjs.org/docs/app/api-reference/config/next-config-js/reactStrictMode
|
|
137
|
+
*/
|
|
138
|
+
reactStrictMode?: boolean | null; /** Build output mode: 'export' for full static export, 'standalone' for single server */
|
|
127
139
|
output?: "export" | "standalone"; /** File extensions treated as routable pages/routes (Next.js pageExtensions) */
|
|
128
140
|
pageExtensions?: string[]; /** Turbopack-compatible module resolution options. */
|
|
129
141
|
turbopack?: {
|
|
@@ -194,6 +206,15 @@ type NextConfig = {
|
|
|
194
206
|
* `useRouter().experimental_gesturePush()`.
|
|
195
207
|
*/
|
|
196
208
|
gestureTransition?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Enables App Router Segment Cache prefetch inlining. When provided as an
|
|
211
|
+
* object, thresholds are resolved with Next.js defaults and non-finite
|
|
212
|
+
* values are clamped to Number.MAX_SAFE_INTEGER.
|
|
213
|
+
*/
|
|
214
|
+
prefetchInlining?: boolean | {
|
|
215
|
+
maxBundleSize?: number;
|
|
216
|
+
maxSize?: number;
|
|
217
|
+
};
|
|
197
218
|
[key: string]: unknown;
|
|
198
219
|
};
|
|
199
220
|
/**
|
|
@@ -254,11 +275,10 @@ type ResolvedNextConfig = {
|
|
|
254
275
|
*/
|
|
255
276
|
gestureTransition: boolean;
|
|
256
277
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* segment payload.
|
|
278
|
+
* Resolved `experimental.prefetchInlining` config. Next.js normalizes `true`
|
|
279
|
+
* and partial object config into concrete thresholds.
|
|
260
280
|
*/
|
|
261
|
-
prefetchInlining:
|
|
281
|
+
prefetchInlining: PrefetchInliningConfig;
|
|
262
282
|
redirects: NextRedirect[];
|
|
263
283
|
rewrites: {
|
|
264
284
|
beforeFiles: NextRewrite[];
|
|
@@ -350,6 +370,16 @@ type ResolvedNextConfig = {
|
|
|
350
370
|
* `test/e2e/optimized-loading` test fixture.
|
|
351
371
|
*/
|
|
352
372
|
disableOptimizedLoading: boolean;
|
|
373
|
+
/**
|
|
374
|
+
* Resolved `reactStrictMode` from next.config, preserved as `boolean | null`
|
|
375
|
+
* so each router can apply its own default (Next.js resolves `null` to OFF
|
|
376
|
+
* for the Pages Router and ON for the App Router). When the effective value
|
|
377
|
+
* is `true`, the client root is wrapped in `<React.StrictMode>`.
|
|
378
|
+
*
|
|
379
|
+
* See `.nextjs-ref/packages/next/src/build/define-env.ts`
|
|
380
|
+
* (`__NEXT_STRICT_MODE` / `__NEXT_STRICT_MODE_APP`).
|
|
381
|
+
*/
|
|
382
|
+
reactStrictMode: boolean | null;
|
|
353
383
|
/**
|
|
354
384
|
* Mirrors Next.js `experimental.scrollRestoration`. When true, the Pages
|
|
355
385
|
* Router client takes ownership of browser history scroll restoration by
|
|
@@ -534,4 +564,4 @@ declare function extractMdxOptions(config: NextConfig, root?: string): Promise<M
|
|
|
534
564
|
*/
|
|
535
565
|
declare function detectNextIntlConfig(root: string, resolved: ResolvedNextConfig): void;
|
|
536
566
|
//#endregion
|
|
537
|
-
export { HasCondition, MdxOptions, NextConfig, NextConfigInput, NextHeader, NextI18nConfig, NextRedirect, NextRewrite, PHASE_PRODUCTION_BUILD, ResolvedNextConfig, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
|
|
567
|
+
export { HasCondition, MdxOptions, NextConfig, NextConfigInput, NextHeader, NextI18nConfig, NextRedirect, NextRewrite, PHASE_PRODUCTION_BUILD, PrefetchInliningConfig, ResolvedNextConfig, createRscCompatibilityId, detectNextIntlConfig, extractMdxOptions, findNextConfigPath, lightningCssFeatureNamesToMask, loadNextConfig, normalizeAssetPrefix, parseBodySizeLimit, reassignsModuleExports, referencesCjsGlobals, resolveNextConfig, resolveNextConfigInput };
|
|
@@ -560,6 +560,18 @@ function resolveStaleTimes(experimental) {
|
|
|
560
560
|
static: Number.isFinite(staticRaw) && staticRaw >= 0 ? staticRaw : DEFAULT_STALE_TIMES.static
|
|
561
561
|
};
|
|
562
562
|
}
|
|
563
|
+
function normalizePrefetchInliningConfig(value) {
|
|
564
|
+
if (!value) return false;
|
|
565
|
+
const raw = isUnknownRecord(value) ? value : null;
|
|
566
|
+
const maxSize = raw ? raw.maxSize ?? 2048 : 2048;
|
|
567
|
+
const maxBundleSize = raw ? raw.maxBundleSize ?? 10240 : 10240;
|
|
568
|
+
const normalizedMaxSize = Number(maxSize);
|
|
569
|
+
const normalizedMaxBundleSize = Number(maxBundleSize);
|
|
570
|
+
return {
|
|
571
|
+
maxBundleSize: Number.isFinite(normalizedMaxBundleSize) ? normalizedMaxBundleSize : Number.MAX_SAFE_INTEGER,
|
|
572
|
+
maxSize: Number.isFinite(normalizedMaxSize) ? normalizedMaxSize : Number.MAX_SAFE_INTEGER
|
|
573
|
+
};
|
|
574
|
+
}
|
|
563
575
|
/**
|
|
564
576
|
* Resolve a NextConfig into a fully-resolved ResolvedNextConfig.
|
|
565
577
|
* Awaits async functions for redirects/rewrites/headers.
|
|
@@ -615,6 +627,7 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
|
|
|
615
627
|
sassOptions: null,
|
|
616
628
|
removeConsole: false,
|
|
617
629
|
disableOptimizedLoading: false,
|
|
630
|
+
reactStrictMode: null,
|
|
618
631
|
scrollRestoration: false,
|
|
619
632
|
compilerDefine: {},
|
|
620
633
|
compilerDefineServer: {},
|
|
@@ -683,12 +696,12 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
|
|
|
683
696
|
const optimizePackageImports = Array.isArray(rawOptimize) ? rawOptimize.filter((x) => typeof x === "string") : [];
|
|
684
697
|
const inlineCss = experimental?.inlineCss === true;
|
|
685
698
|
const globalNotFound = experimental?.globalNotFound === true;
|
|
686
|
-
const prefetchInlining =
|
|
699
|
+
const prefetchInlining = normalizePrefetchInliningConfig(experimental?.prefetchInlining);
|
|
687
700
|
const appShells = experimental?.appShells === true;
|
|
688
701
|
if (appShells) {
|
|
689
702
|
const missingCoFlags = [];
|
|
690
703
|
if (!config.cacheComponents) missingCoFlags.push("cacheComponents");
|
|
691
|
-
if (
|
|
704
|
+
if (!prefetchInlining) missingCoFlags.push("experimental.prefetchInlining");
|
|
692
705
|
if (experimental?.varyParams !== true) missingCoFlags.push("experimental.varyParams");
|
|
693
706
|
if (experimental?.optimisticRouting !== true) missingCoFlags.push("experimental.optimisticRouting");
|
|
694
707
|
if (experimental?.cachedNavigations !== true) missingCoFlags.push("experimental.cachedNavigations");
|
|
@@ -791,6 +804,7 @@ async function resolveNextConfig(config, root = process.cwd(), options = {}) {
|
|
|
791
804
|
sassOptions: readOptionalRecord(config.sassOptions) ?? null,
|
|
792
805
|
removeConsole: config.compiler?.removeConsole === true ? true : isUnknownRecord(config.compiler?.removeConsole) ? { exclude: readStringArray(config.compiler.removeConsole.exclude) } : false,
|
|
793
806
|
disableOptimizedLoading: experimental?.disableOptimizedLoading === true,
|
|
807
|
+
reactStrictMode: typeof config.reactStrictMode === "boolean" ? config.reactStrictMode : null,
|
|
794
808
|
scrollRestoration: experimental?.scrollRestoration === true,
|
|
795
809
|
compilerDefine: serializeCompilerDefine(config.compiler?.define),
|
|
796
810
|
compilerDefineServer: serializeCompilerDefine(config.compiler?.defineServer),
|
|
@@ -47,12 +47,16 @@ function toDocumentOnlyAppRoute(route) {
|
|
|
47
47
|
isDynamic: route.isDynamic
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
+
function requiresDynamicNavigationRequest(route) {
|
|
51
|
+
return route.isDynamic && route.parallelSlots.length > 0;
|
|
52
|
+
}
|
|
50
53
|
/** Project an `AppRoute` down to the public `VinextLinkPrefetchRoute` shape. */
|
|
51
54
|
function toLinkPrefetchRoute(route) {
|
|
52
55
|
return {
|
|
53
56
|
canPrefetchLoadingShell: route.loadingPath !== null,
|
|
54
57
|
patternParts: [...route.patternParts],
|
|
55
|
-
isDynamic: route.isDynamic
|
|
58
|
+
isDynamic: route.isDynamic,
|
|
59
|
+
...requiresDynamicNavigationRequest(route) ? { requiresDynamicNavigationRequest: true } : {}
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
function buildRouteManifestExpression(routeManifest) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
|
|
1
|
+
import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite, PrefetchInliningConfig } from "../config/next-config.js";
|
|
2
2
|
import { AppRoute } from "../routing/app-route-graph.js";
|
|
3
3
|
import { MetadataFileRoute } from "../server/metadata-routes.js";
|
|
4
4
|
import { ImageConfig } from "../server/image-optimization.js";
|
|
@@ -45,7 +45,8 @@ type AppRouterConfig = {
|
|
|
45
45
|
cacheMaxMemorySize?: number; /** Inline app CSS into production HTML (from experimental.inlineCss). */
|
|
46
46
|
inlineCss?: boolean; /** Enable standalone route-miss 404 handling (from experimental.globalNotFound). */
|
|
47
47
|
globalNotFound?: boolean; /** Enables Next.js Cache Components semantics for App Router document HTML. */
|
|
48
|
-
cacheComponents?: boolean; /**
|
|
48
|
+
cacheComponents?: boolean; /** Resolved `experimental.prefetchInlining` thresholds. */
|
|
49
|
+
prefetchInlining?: PrefetchInliningConfig; /** Whether the RSC build discovered any server references. Defaults to true. */
|
|
49
50
|
hasServerActions?: boolean; /** Internationalization routing config for middleware matcher locale handling. */
|
|
50
51
|
i18n?: NextI18nConfig | null;
|
|
51
52
|
imageConfig?: ImageConfig;
|
|
@@ -78,6 +78,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
78
78
|
const cacheMaxMemorySize = config?.cacheMaxMemorySize;
|
|
79
79
|
const inlineCss = config?.inlineCss === true;
|
|
80
80
|
const cacheComponents = config?.cacheComponents === true;
|
|
81
|
+
const prefetchInlining = config?.prefetchInlining ?? false;
|
|
81
82
|
const hasServerActions = config?.hasServerActions !== false;
|
|
82
83
|
const i18nConfig = config?.i18n ?? null;
|
|
83
84
|
const hasPagesDir = config?.hasPagesDir ?? false;
|
|
@@ -493,6 +494,7 @@ export default createAppRscHandler({
|
|
|
493
494
|
basePath: __basePath,
|
|
494
495
|
buildId: process.env.__VINEXT_BUILD_ID ?? null,
|
|
495
496
|
ensureRouteLoaded: __ensureRouteLoaded,
|
|
497
|
+
prefetchInlining: ${JSON.stringify(prefetchInlining)},
|
|
496
498
|
clearRequestContext() {
|
|
497
499
|
__clearRequestContext();
|
|
498
500
|
},
|
|
@@ -527,6 +529,7 @@ export default createAppRscHandler({
|
|
|
527
529
|
staticParamsValidationParams,
|
|
528
530
|
rootParams,
|
|
529
531
|
request,
|
|
532
|
+
renderedPathAndSearch,
|
|
530
533
|
route,
|
|
531
534
|
scriptNonce,
|
|
532
535
|
searchParams,
|
|
@@ -693,6 +696,7 @@ export default createAppRscHandler({
|
|
|
693
696
|
prerenderToReadableStream,
|
|
694
697
|
request,
|
|
695
698
|
revalidateSeconds: __segmentConfig.revalidateSeconds,
|
|
699
|
+
renderedPathAndSearch,
|
|
696
700
|
resolveRouteFetchCacheMode(targetRoute) {
|
|
697
701
|
return __resolveRouteFetchCacheMode(targetRoute);
|
|
698
702
|
},
|
|
@@ -57,7 +57,10 @@ async function generateClientEntry(pagesDir, nextConfig, fileMatcher, options =
|
|
|
57
57
|
return ` ${JSON.stringify(nextFormatPattern)}: () => import(${JSON.stringify(absPath)})`;
|
|
58
58
|
});
|
|
59
59
|
const appFileBase = appFilePath ? normalizePathSeparators(appFilePath) : void 0;
|
|
60
|
-
|
|
60
|
+
const userInstrumentationImport = instrumentationClientPath ? `import ${JSON.stringify(normalizePathSeparators(instrumentationClientPath))};\n` : "";
|
|
61
|
+
const reactPreambleImport = options.reactPreamble === false ? "" : "import \"@vitejs/plugin-react/preamble\";\n";
|
|
62
|
+
const reactStrictModeEnabled = nextConfig.reactStrictMode === true;
|
|
63
|
+
return `${userInstrumentationImport}${reactPreambleImport}
|
|
61
64
|
import "vinext/instrumentation-client";
|
|
62
65
|
import React from "react";
|
|
63
66
|
import { hydrateRoot } from "react-dom/client";
|
|
@@ -89,6 +92,9 @@ const appLoader = undefined;
|
|
|
89
92
|
// can iterate in order and trust the first match.
|
|
90
93
|
window.__VINEXT_PAGE_LOADERS__ = pageLoaders;
|
|
91
94
|
window.__VINEXT_PAGE_PATTERNS__ = Object.keys(pageLoaders);
|
|
95
|
+
// reactStrictMode flag — read by wrapWithRouterContext (next/router) so the
|
|
96
|
+
// <React.StrictMode> wrap is applied on initial hydration and every navigation.
|
|
97
|
+
window.__VINEXT_REACT_STRICT_MODE__ = ${JSON.stringify(reactStrictModeEnabled)};
|
|
92
98
|
window.__VINEXT_PAGES_SSG_PATTERNS__ = ${JSON.stringify(pagesSsgPatterns)};
|
|
93
99
|
window.__VINEXT_PAGES_SSP_PATTERNS__ = ${JSON.stringify(pagesSspPatterns)};
|
|
94
100
|
window.__VINEXT_MIDDLEWARE_MATCHER__ = ${JSON.stringify(options.middlewareMatcher)};
|
|
@@ -186,6 +192,9 @@ async function hydrate() {
|
|
|
186
192
|
});
|
|
187
193
|
|
|
188
194
|
// Wrap with RouterContext.Provider so next/router and next/compat/router work during hydration.
|
|
195
|
+
// When reactStrictMode is enabled, wrapWithRouterContext also wraps the tree
|
|
196
|
+
// in <React.StrictMode> (see next/router) — applied here and on every
|
|
197
|
+
// navigation render, matching Next.js.
|
|
189
198
|
element = wrapWithRouterContext(element, resolveHydrationCommit);
|
|
190
199
|
|
|
191
200
|
const container = document.getElementById("__next");
|
|
@@ -204,9 +213,11 @@ async function hydrate() {
|
|
|
204
213
|
window.__NEXT_HYDRATED_CB?.();
|
|
205
214
|
|
|
206
215
|
if (nextData.isFallback) {
|
|
216
|
+
const currentUrl = window.location.pathname + window.location.search + window.location.hash;
|
|
217
|
+
const routeUrl = nextData.__vinext?.routeUrl;
|
|
207
218
|
await Router.replace(
|
|
208
|
-
|
|
209
|
-
undefined,
|
|
219
|
+
routeUrl || currentUrl,
|
|
220
|
+
routeUrl ? currentUrl : undefined,
|
|
210
221
|
{ _h: 1, scroll: false },
|
|
211
222
|
);
|
|
212
223
|
}
|
|
@@ -4,6 +4,8 @@ import { apiRouter, pagesRouter } from "../routing/pages-router.js";
|
|
|
4
4
|
import { resolveEntryPath } from "./runtime-entry-module.js";
|
|
5
5
|
import { isProxyFile } from "../server/middleware.js";
|
|
6
6
|
import "./pages-entry-helpers.js";
|
|
7
|
+
import { hasExportedName } from "../build/report.js";
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
7
9
|
//#region src/entries/pages-server-entry.ts
|
|
8
10
|
/**
|
|
9
11
|
* Pages Router server entry generator.
|
|
@@ -24,6 +26,12 @@ const _pagesApiRoutePath = resolveEntryPath("../server/pages-api-route.js", impo
|
|
|
24
26
|
const _serverGlobalsPath = resolveEntryPath("../server/server-globals.js", import.meta.url);
|
|
25
27
|
const _queryUtilsPath = resolveEntryPath("../utils/query.js", import.meta.url);
|
|
26
28
|
const _pagesPageHandlerPath = resolveEntryPath("../server/pages-page-handler.js", import.meta.url);
|
|
29
|
+
async function getPagesDataKind(filePath) {
|
|
30
|
+
const source = await readFile(filePath, "utf8");
|
|
31
|
+
if (hasExportedName(source, "getStaticProps")) return "static";
|
|
32
|
+
if (hasExportedName(source, "getServerSideProps")) return "server";
|
|
33
|
+
return "none";
|
|
34
|
+
}
|
|
27
35
|
/**
|
|
28
36
|
* Generate the virtual SSR server entry module.
|
|
29
37
|
* This is the entry point for `vite build --ssr`.
|
|
@@ -39,10 +47,11 @@ async function generateServerEntry(pagesDir, nextConfig, fileMatcher, middleware
|
|
|
39
47
|
const absPath = normalizePathSeparators(r.filePath);
|
|
40
48
|
return `import * as api_${i} from ${JSON.stringify(absPath)};`;
|
|
41
49
|
});
|
|
42
|
-
const pageRouteEntries = pageRoutes.map((r, i) => {
|
|
50
|
+
const pageRouteEntries = await Promise.all(pageRoutes.map(async (r, i) => {
|
|
43
51
|
const absPath = normalizePathSeparators(r.filePath);
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const dataKind = await getPagesDataKind(r.filePath);
|
|
53
|
+
return ` { pattern: ${JSON.stringify(r.pattern)}, patternParts: ${JSON.stringify(r.patternParts)}, isDynamic: ${r.isDynamic}, params: ${JSON.stringify(r.params)}, module: page_${i}, filePath: ${JSON.stringify(absPath)}, dataKind: ${JSON.stringify(dataKind)} }`;
|
|
54
|
+
}));
|
|
46
55
|
const apiRouteEntries = apiRoutes.map((r, i) => ` { pattern: ${JSON.stringify(r.pattern)}, patternParts: ${JSON.stringify(r.patternParts)}, isDynamic: ${r.isDynamic}, params: ${JSON.stringify(r.params)}, module: api_${i} }`);
|
|
47
56
|
const appFilePath = findFileWithExts(pagesDir, "_app", fileMatcher);
|
|
48
57
|
const docFilePath = findFileWithExts(pagesDir, "_document", fileMatcher);
|
|
@@ -164,7 +173,12 @@ const i18nConfig = ${i18nConfigJson};
|
|
|
164
173
|
// to load next.config.js at runtime.
|
|
165
174
|
export const buildId = ${buildIdJson};
|
|
166
175
|
export function normalizeDataRequest(request) {
|
|
167
|
-
return __normalizePagesDataRequest(
|
|
176
|
+
return __normalizePagesDataRequest(
|
|
177
|
+
request,
|
|
178
|
+
buildId,
|
|
179
|
+
vinextConfig.basePath,
|
|
180
|
+
hasMiddleware && vinextConfig.trailingSlash,
|
|
181
|
+
);
|
|
168
182
|
}
|
|
169
183
|
export const hasMiddleware = ${JSON.stringify(Boolean(middlewarePath))};
|
|
170
184
|
|