vinext 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -10
- package/dist/build/client-build-config.d.ts +64 -3
- package/dist/build/client-build-config.js +131 -4
- package/dist/build/client-reference-groups.d.ts +163 -0
- package/dist/build/client-reference-groups.js +534 -0
- package/dist/build/module-dependency-cache.d.ts +31 -0
- package/dist/build/module-dependency-cache.js +51 -1
- package/dist/build/next-client-runtime-manifests.d.ts +10 -1
- package/dist/build/next-client-runtime-manifests.js +19 -4
- package/dist/build/nitro-public-files.d.ts +24 -0
- package/dist/build/nitro-public-files.js +60 -0
- package/dist/build/output-root-externals.d.ts +21 -0
- package/dist/build/output-root-externals.js +40 -0
- package/dist/build/pages-client-assets-module.js +1 -1
- package/dist/build/prerender-paths.js +6 -3
- package/dist/build/prerender.js +1 -1
- package/dist/build/server-actions-encryption-key.d.ts +23 -0
- package/dist/build/server-actions-encryption-key.js +101 -0
- package/dist/build/ssr-manifest.d.ts +3 -0
- package/dist/build/ssr-manifest.js +10 -1
- package/dist/check.js +5 -6
- package/dist/cli-dev-config.js +3 -3
- package/dist/cli.js +1 -1
- package/dist/client/client-rewrite-params.d.ts +9 -0
- package/dist/client/client-rewrite-params.js +20 -0
- package/dist/client/dev-error-overlay.js +2 -1
- package/dist/client/navigation-runtime.d.ts +25 -2
- package/dist/client/navigation-runtime.js +42 -11
- package/dist/client/vinext-next-data.d.ts +0 -1
- package/dist/config/config-matchers.d.ts +15 -40
- package/dist/config/config-matchers.js +195 -262
- package/dist/config/config-source.d.ts +34 -0
- package/dist/config/config-source.js +141 -0
- package/dist/config/header-params.d.ts +29 -0
- package/dist/config/header-params.js +106 -0
- package/dist/config/next-config.d.ts +7 -5
- package/dist/config/next-config.js +120 -7
- package/dist/entries/app-browser-entry.d.ts +14 -1
- package/dist/entries/app-browser-entry.js +26 -36
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +92 -57
- package/dist/entries/app-rsc-manifest.d.ts +10 -0
- package/dist/entries/app-rsc-manifest.js +20 -1
- package/dist/entries/app-ssr-entry.d.ts +4 -1
- package/dist/entries/app-ssr-entry.js +9 -2
- package/dist/entries/pages-client-entry.d.ts +1 -0
- package/dist/entries/pages-client-entry.js +6 -6
- package/dist/entries/pages-server-entry.js +17 -14
- package/dist/index.d.ts +11 -0
- package/dist/index.js +350 -175
- package/dist/init.d.ts +1 -1
- package/dist/init.js +103 -6
- package/dist/plugins/ast-utils.d.ts +53 -2
- package/dist/plugins/ast-utils.js +90 -2
- package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
- package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
- package/dist/plugins/commonjs-esm-facade.js +2 -2
- package/dist/plugins/css-module-imports.js +13 -20
- package/dist/plugins/dynamic-preload-metadata.js +2 -3
- package/dist/plugins/extensionless-dynamic-import.js +2 -3
- package/dist/plugins/fonts.d.ts +1 -1
- package/dist/plugins/fonts.js +3 -3
- package/dist/plugins/ignore-dynamic-requests.js +2 -3
- package/dist/plugins/import-meta-url.js +3 -4
- package/dist/plugins/instrumentation-client.js +3 -2
- package/dist/plugins/middleware-export-validation.js +2 -3
- package/dist/plugins/og-harfbuzz.js +2 -3
- package/dist/plugins/optimize-imports.d.ts +25 -2
- package/dist/plugins/optimize-imports.js +109 -24
- package/dist/plugins/pages-node-externals.js +2 -3
- package/dist/plugins/remove-console.js +2 -18
- package/dist/plugins/require-condition-resolution.js +3 -3
- package/dist/plugins/require-context.js +2 -3
- package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
- package/dist/plugins/rsc-client-reference-loaders.js +336 -18
- package/dist/plugins/strip-server-exports.js +3 -4
- package/dist/plugins/styled-jsx.js +2 -3
- package/dist/plugins/use-cache-callable.d.ts +26 -2
- package/dist/plugins/use-cache-callable.js +101 -36
- package/dist/plugins/worker-image-imports.d.ts +1 -0
- package/dist/plugins/worker-image-imports.js +31 -34
- package/dist/plugins/worker-use-server.js +38 -14
- package/dist/routing/app-route-graph.d.ts +1 -1
- package/dist/routing/browser-route-manifest.d.ts +43 -0
- package/dist/routing/browser-route-manifest.js +195 -0
- package/dist/routing/hashed-route-patterns.d.ts +4 -0
- package/dist/routing/hashed-route-patterns.js +22 -0
- package/dist/routing/optimistic-route-trie.d.ts +27 -0
- package/dist/routing/optimistic-route-trie.js +102 -0
- package/dist/routing/route-validation.d.ts +6 -1
- package/dist/routing/route-validation.js +26 -10
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-action-forwarding.d.ts +8 -0
- package/dist/server/app-action-forwarding.js +17 -3
- package/dist/server/app-browser-entry.js +149 -62
- package/dist/server/app-browser-error.d.ts +3 -1
- package/dist/server/app-browser-error.js +7 -2
- package/dist/server/app-browser-interception-context.d.ts +2 -2
- package/dist/server/app-browser-interception-context.js +1 -1
- package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
- package/dist/server/app-browser-mpa-navigation.js +6 -5
- package/dist/server/app-browser-navigation-controller.d.ts +17 -6
- package/dist/server/app-browser-navigation-controller.js +88 -26
- package/dist/server/app-browser-prefetch-response.js +2 -2
- package/dist/server/app-browser-state.d.ts +2 -2
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-supplemental-refresh.js +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +4 -4
- package/dist/server/app-client-reference-preloader.d.ts +23 -0
- package/dist/server/app-client-reference-preloader.js +30 -7
- package/dist/server/app-fallback-renderer.js +2 -1
- package/dist/server/app-middleware.d.ts +6 -0
- package/dist/server/app-middleware.js +8 -10
- package/dist/server/app-optimistic-routing.d.ts +8 -10
- package/dist/server/app-optimistic-routing.js +4 -95
- package/dist/server/app-page-boundary-render.js +8 -1
- package/dist/server/app-page-cache-render.js +1 -0
- package/dist/server/app-page-dispatch.js +3 -1
- package/dist/server/app-page-render.js +4 -2
- package/dist/server/app-page-rsc-render-status.d.ts +1 -0
- package/dist/server/app-page-rsc-render-status.js +1 -0
- package/dist/server/app-page-search-params-observation.d.ts +1 -4
- package/dist/server/app-page-search-params-observation.js +8 -10
- package/dist/server/app-page-stream.d.ts +7 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +12 -8
- package/dist/server/app-prerender-endpoints.js +1 -1
- package/dist/server/app-prerender-static-params.js +3 -2
- package/dist/server/app-render-abort-error.d.ts +19 -0
- package/dist/server/app-render-abort-error.js +31 -1
- package/dist/server/app-render-dependency.js +42 -2
- package/dist/server/app-request-stage-independent-entry.js +7 -7
- package/dist/server/app-response-stage-entry.js +5 -5
- package/dist/server/app-route-handler-dispatch.js +3 -1
- package/dist/server/app-route-handler-execution.d.ts +2 -0
- package/dist/server/app-route-handler-execution.js +9 -2
- package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
- package/dist/server/app-route-handler-middleware-context.js +3 -3
- package/dist/server/app-route-handler-response.d.ts +2 -1
- package/dist/server/app-route-handler-response.js +2 -2
- package/dist/server/app-route-handler-runtime.d.ts +2 -0
- package/dist/server/app-route-handler-runtime.js +21 -4
- package/dist/server/app-route-module-loader.js +7 -6
- package/dist/server/app-route-tree.d.ts +20 -0
- package/dist/server/app-route-tree.js +18 -0
- package/dist/server/app-router-entry.js +7 -7
- package/dist/server/app-rsc-cache-busting.d.ts +16 -0
- package/dist/server/app-rsc-cache-busting.js +29 -12
- package/dist/server/app-rsc-combined-handler.js +8 -1
- package/dist/server/app-rsc-errors.d.ts +7 -0
- package/dist/server/app-rsc-errors.js +9 -2
- package/dist/server/app-rsc-handler.d.ts +4 -1
- package/dist/server/app-rsc-handler.js +151 -135
- package/dist/server/app-rsc-request-normalization.js +3 -3
- package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
- package/dist/server/app-rsc-response-finalizer.js +4 -1
- package/dist/server/app-rsc-response-stage.js +5 -3
- package/dist/server/app-rsc-route-matching.d.ts +1 -0
- package/dist/server/app-rsc-route-matching.js +1 -1
- package/dist/server/app-server-action-execution.d.ts +23 -6
- package/dist/server/app-server-action-execution.js +51 -57
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +21 -11
- package/dist/server/app-ssr-stream.d.ts +7 -0
- package/dist/server/app-ssr-stream.js +13 -1
- package/dist/server/app-visited-response-cache.js +2 -2
- package/dist/server/config-headers.js +13 -4
- package/dist/server/defer-until-stream-consumed.d.ts +2 -1
- package/dist/server/defer-until-stream-consumed.js +3 -1
- package/dist/server/dev-server.js +1 -1
- package/dist/server/image-optimization.js +1 -0
- package/dist/server/isolate-shared-promise.d.ts +10 -0
- package/dist/server/isolate-shared-promise.js +33 -0
- package/dist/server/isr-cache.js +3 -2
- package/dist/server/metadata-route-response.js +2 -2
- package/dist/server/middleware-matcher-pattern.d.ts +0 -1
- package/dist/server/middleware-matcher-pattern.js +11 -140
- package/dist/server/middleware-matcher.js +5 -6
- package/dist/server/middleware-response-headers.d.ts +31 -0
- package/dist/server/middleware-response-headers.js +57 -1
- package/dist/server/middleware-runtime.js +30 -17
- package/dist/server/navigation-planner.d.ts +2 -2
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/nitro-public-files-plugin.d.ts +38 -0
- package/dist/server/nitro-public-files-plugin.js +106 -0
- package/dist/server/nitro-public-files.d.ts +21 -0
- package/dist/server/nitro-public-files.js +39 -0
- package/dist/server/open-redirect.d.ts +11 -4
- package/dist/server/open-redirect.js +11 -4
- package/dist/server/pages-api-route.js +2 -2
- package/dist/server/pages-asset-tags.d.ts +5 -0
- package/dist/server/pages-asset-tags.js +9 -2
- package/dist/server/pages-client-assets.d.ts +4 -1
- package/dist/server/pages-data-route.js +2 -1
- package/dist/server/pages-i18n.d.ts +18 -0
- package/dist/server/pages-i18n.js +18 -2
- package/dist/server/pages-node-compat.d.ts +5 -3
- package/dist/server/pages-node-compat.js +35 -16
- package/dist/server/pages-page-data.js +1 -1
- package/dist/server/pages-page-handler.js +1 -1
- package/dist/server/pages-page-response.js +1 -1
- package/dist/server/pages-request-pipeline.d.ts +6 -1
- package/dist/server/pages-request-pipeline.js +35 -39
- package/dist/server/pages-request-stage-entry.js +20 -10
- package/dist/server/pages-response-stage-entry.js +1 -1
- package/dist/server/pages-revalidate.js +3 -2
- package/dist/server/pages-router-entry.js +2 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +74 -36
- package/dist/server/proxy-trust.d.ts +6 -0
- package/dist/server/proxy-trust.js +12 -6
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +12 -1
- package/dist/server/rsc-stream-hints.d.ts +1 -1
- package/dist/server/rsc-stream-hints.js +21 -3
- package/dist/server/server-reference-loader.js +10 -1
- package/dist/server/static-file-cache.js +15 -3
- package/dist/server/worker-image-optimization.js +19 -6
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/cache-handler.js +3 -2
- package/dist/shims/cache-request-state.d.ts +40 -3
- package/dist/shims/cache-request-state.js +70 -5
- package/dist/shims/cache-runtime.js +47 -19
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +17 -8
- package/dist/shims/cdn-purge-routes.d.ts +24 -0
- package/dist/shims/cdn-purge-routes.js +77 -0
- package/dist/shims/dynamic.js +17 -4
- package/dist/shims/form.js +8 -3
- package/dist/shims/head.js +1 -1
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image-props.d.ts +93 -0
- package/dist/shims/image-props.js +323 -0
- package/dist/shims/image.d.ts +4 -18
- package/dist/shims/image.js +4 -319
- package/dist/shims/internal/headers-state.d.ts +7 -0
- package/dist/shims/internal/headers-state.js +14 -2
- package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
- package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
- package/dist/shims/link-prefetch.js +5 -4
- package/dist/shims/link.js +7 -5
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.js +21 -10
- package/dist/shims/og.js +35 -10
- package/dist/shims/request-context.d.ts +13 -0
- package/dist/shims/router.js +28 -52
- package/dist/shims/server.d.ts +42 -8
- package/dist/shims/server.js +99 -15
- package/dist/shims/thenable-params.d.ts +6 -1
- package/dist/shims/thenable-params.js +11 -2
- package/dist/shims/unified-request-context.d.ts +5 -0
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/url-utils.d.ts +7 -0
- package/dist/shims/url-utils.js +12 -3
- package/dist/utils/asset-prefix.d.ts +7 -0
- package/dist/utils/asset-prefix.js +10 -1
- package/dist/utils/client-build-manifest.js +12 -5
- package/dist/utils/client-runtime-metadata.d.ts +1 -0
- package/dist/utils/client-runtime-metadata.js +15 -2
- package/dist/utils/domain-locale.js +1 -1
- package/dist/utils/lazy-chunks.d.ts +4 -0
- package/dist/utils/manifest-paths.d.ts +14 -0
- package/dist/utils/manifest-paths.js +22 -1
- package/dist/utils/path-to-regexp.d.ts +21 -0
- package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
- package/dist/utils/plugin-react-version.d.ts +15 -0
- package/dist/utils/plugin-react-version.js +64 -0
- package/dist/utils/plugin-rsc-version.d.ts +2 -0
- package/dist/utils/plugin-rsc-version.js +28 -2
- package/dist/utils/public-routes.d.ts +2 -0
- package/dist/utils/public-routes.js +18 -7
- package/dist/utils/react-version.d.ts +7 -0
- package/dist/utils/react-version.js +39 -16
- package/package.json +6 -6
- package/dist/build/nitro-route-rules.d.ts +0 -47
- package/dist/build/nitro-route-rules.js +0 -79
- package/dist/plugins/cache-flight-codec.d.ts +0 -19
- package/dist/plugins/cache-flight-codec.js +0 -68
- package/dist/server/middleware-path-to-regexp.d.ts +0 -13
- package/dist/utils/regex-safety.d.ts +0 -17
- package/dist/utils/regex-safety.js +0 -789
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import { parseModuleRecord } from "../plugins/ast-utils.js";
|
|
3
|
+
import { actionOwnerRouteEntryIds } from "./action-owner-manifest.js";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
//#region src/build/client-reference-groups.ts
|
|
6
|
+
/**
|
|
7
|
+
* Client references whose estimated group cost (see
|
|
8
|
+
* {@link measureClientReferenceGroupCosts}) is larger than this many
|
|
9
|
+
* transformed source bytes keep their own lazy chunk instead of joining a route
|
|
10
|
+
* group. Grouping makes every member load with the group, so a heavy component
|
|
11
|
+
* that a route can reach but rarely renders must not be pulled into that
|
|
12
|
+
* route's startup bundle.
|
|
13
|
+
*/
|
|
14
|
+
const CLIENT_REFERENCE_GROUP_MAX_COST_BYTES = 102400;
|
|
15
|
+
const SEGMENT_FILE_ORDER = [
|
|
16
|
+
"layout",
|
|
17
|
+
"template",
|
|
18
|
+
"error",
|
|
19
|
+
"unauthorized",
|
|
20
|
+
"forbidden",
|
|
21
|
+
"not-found",
|
|
22
|
+
"loading",
|
|
23
|
+
"default",
|
|
24
|
+
"page"
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Order route files as they render: outer segments first and, within a
|
|
28
|
+
* segment, each file before the ones it wraps. A group evaluates its members in
|
|
29
|
+
* the order the walk reaches them, so this keeps an outer layout's top-level
|
|
30
|
+
* side effects and CSS ahead of its page's, as Next.js evaluates client
|
|
31
|
+
* references in render order.
|
|
32
|
+
*/
|
|
33
|
+
function inRenderOrder(files) {
|
|
34
|
+
const rank = (file) => {
|
|
35
|
+
const index = SEGMENT_FILE_ORDER.indexOf(path.basename(file).split(".")[0]);
|
|
36
|
+
return index === -1 ? SEGMENT_FILE_ORDER.length : index;
|
|
37
|
+
};
|
|
38
|
+
return files.map((file) => ({
|
|
39
|
+
file,
|
|
40
|
+
depth: path.dirname(file).split("/").length,
|
|
41
|
+
rank: rank(file)
|
|
42
|
+
})).sort((a, b) => a.depth - b.depth || a.rank - b.rank).map(({ file }) => file);
|
|
43
|
+
}
|
|
44
|
+
function interceptEntryIds(intercept) {
|
|
45
|
+
return [
|
|
46
|
+
intercept.pagePath,
|
|
47
|
+
...intercept.layoutPaths,
|
|
48
|
+
...intercept.loadingPaths ?? [],
|
|
49
|
+
intercept.notFoundPath
|
|
50
|
+
].filter((value) => typeof value === "string");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Map each client reference reachable from App Router route files to a
|
|
54
|
+
* signature naming the owners that reach it. A route owns its page, layouts,
|
|
55
|
+
* templates, boundaries and parallel slots, which render with it. Intercepting
|
|
56
|
+
* routes (which only render on soft navigation), global-error and
|
|
57
|
+
* global-not-found render on their own, so each is owned by its file, named by
|
|
58
|
+
* its path relative to `root`. References with the same signature are needed
|
|
59
|
+
* together, mirroring Next.js' per-route client entries. The map is in the
|
|
60
|
+
* order a depth-first walk in import order first reaches each reference from
|
|
61
|
+
* the route files in render order, which follows ES module evaluation order.
|
|
62
|
+
*
|
|
63
|
+
* References reachable from no route file (for example vinext's internal
|
|
64
|
+
* runtime references) are omitted and keep their own lazy chunk. So are
|
|
65
|
+
* references that route code reaches through a dynamic import (`next/dynamic`,
|
|
66
|
+
* `React.lazy`), directly or through the dynamically imported module's graph.
|
|
67
|
+
*/
|
|
68
|
+
function collectClientReferenceRouteSignatures(options) {
|
|
69
|
+
const canonicalize = options.canonicalizeModuleId ?? ((id) => id);
|
|
70
|
+
const moduleInfoCache = /* @__PURE__ */ new Map();
|
|
71
|
+
const getModuleInfo = (id) => {
|
|
72
|
+
let info = moduleInfoCache.get(id);
|
|
73
|
+
if (info === void 0) {
|
|
74
|
+
info = options.getModuleInfo(id);
|
|
75
|
+
moduleInfoCache.set(id, info);
|
|
76
|
+
}
|
|
77
|
+
return info;
|
|
78
|
+
};
|
|
79
|
+
const lazyReferences = /* @__PURE__ */ new Set();
|
|
80
|
+
const lazyVisited = /* @__PURE__ */ new Set();
|
|
81
|
+
const markLazy = (root) => {
|
|
82
|
+
const stack = [root];
|
|
83
|
+
while (stack.length > 0) {
|
|
84
|
+
const id = stack.pop();
|
|
85
|
+
if (lazyVisited.has(id)) continue;
|
|
86
|
+
lazyVisited.add(id);
|
|
87
|
+
if (options.clientReferenceIds.has(id)) {
|
|
88
|
+
lazyReferences.add(id);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const info = getModuleInfo(id);
|
|
92
|
+
if (info) stack.push(...info.importedIds, ...info.dynamicallyImportedIds);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const referencesByFile = /* @__PURE__ */ new Map();
|
|
96
|
+
const referencesReachedFrom = (file) => {
|
|
97
|
+
let references = referencesByFile.get(file);
|
|
98
|
+
if (references) return references;
|
|
99
|
+
references = /* @__PURE__ */ new Set();
|
|
100
|
+
const visited = /* @__PURE__ */ new Set();
|
|
101
|
+
const stack = [canonicalize(file)];
|
|
102
|
+
while (stack.length > 0) {
|
|
103
|
+
const id = stack.pop();
|
|
104
|
+
if (visited.has(id)) continue;
|
|
105
|
+
visited.add(id);
|
|
106
|
+
if (options.clientReferenceIds.has(id)) {
|
|
107
|
+
references.add(id);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const info = getModuleInfo(id);
|
|
111
|
+
if (!info) continue;
|
|
112
|
+
for (const importedId of info.dynamicallyImportedIds) markLazy(importedId);
|
|
113
|
+
for (let index = info.importedIds.length - 1; index >= 0; index--) stack.push(info.importedIds[index]);
|
|
114
|
+
}
|
|
115
|
+
referencesByFile.set(file, references);
|
|
116
|
+
return references;
|
|
117
|
+
};
|
|
118
|
+
const owners = /* @__PURE__ */ new Map();
|
|
119
|
+
const addOwner = (owner, files) => {
|
|
120
|
+
for (const file of files) for (const reference of referencesReachedFrom(file)) {
|
|
121
|
+
let referenceOwners = owners.get(reference);
|
|
122
|
+
if (!referenceOwners) {
|
|
123
|
+
referenceOwners = /* @__PURE__ */ new Set();
|
|
124
|
+
owners.set(reference, referenceOwners);
|
|
125
|
+
}
|
|
126
|
+
referenceOwners.add(owner);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const fileOwner = (file) => path.relative(options.root, file);
|
|
130
|
+
for (const route of options.routes) {
|
|
131
|
+
addOwner(route.pattern, inRenderOrder(actionOwnerRouteEntryIds({
|
|
132
|
+
...route,
|
|
133
|
+
parallelSlots: route.parallelSlots.map((slot) => ({
|
|
134
|
+
...slot,
|
|
135
|
+
interceptingRoutes: []
|
|
136
|
+
})),
|
|
137
|
+
siblingIntercepts: []
|
|
138
|
+
})));
|
|
139
|
+
const intercepts = [...route.parallelSlots.flatMap((slot) => slot.interceptingRoutes), ...route.siblingIntercepts];
|
|
140
|
+
for (const intercept of intercepts) addOwner(fileOwner(intercept.pagePath), inRenderOrder(interceptEntryIds(intercept)));
|
|
141
|
+
}
|
|
142
|
+
for (const file of options.sharedRoots ?? []) addOwner(fileOwner(file), [file]);
|
|
143
|
+
const signatures = /* @__PURE__ */ new Map();
|
|
144
|
+
for (const [reference, referenceOwners] of owners) {
|
|
145
|
+
if (lazyReferences.has(reference)) continue;
|
|
146
|
+
signatures.set(reference, [...referenceOwners].sort().join("\n"));
|
|
147
|
+
}
|
|
148
|
+
return signatures;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Plan which client references SSR loads before rendering each route. A route
|
|
152
|
+
* preloads every client reference its page, layouts, templates, boundaries and
|
|
153
|
+
* parallel slots reach, statically or through dynamic imports (a
|
|
154
|
+
* `next/dynamic` component renders on the server), plus the `always` set.
|
|
155
|
+
* Intercepting routes only render on soft navigation, which SSR never
|
|
156
|
+
* renders, so they add to no set. `entryIds` are the RSC graph's entries:
|
|
157
|
+
* walking them up to route files finds what renders outside any route.
|
|
158
|
+
*/
|
|
159
|
+
function collectClientReferencePreloadPlan(options) {
|
|
160
|
+
const canonicalize = options.canonicalizeModuleId ?? ((id) => id);
|
|
161
|
+
const moduleInfoCache = /* @__PURE__ */ new Map();
|
|
162
|
+
const getModuleInfo = (id) => {
|
|
163
|
+
let info = moduleInfoCache.get(id);
|
|
164
|
+
if (info === void 0) {
|
|
165
|
+
info = options.getModuleInfo(id);
|
|
166
|
+
moduleInfoCache.set(id, info);
|
|
167
|
+
}
|
|
168
|
+
return info;
|
|
169
|
+
};
|
|
170
|
+
const reached = /* @__PURE__ */ new Set();
|
|
171
|
+
const referencesReachedFrom = (roots, stopAt) => {
|
|
172
|
+
const references = [];
|
|
173
|
+
const visited = /* @__PURE__ */ new Set();
|
|
174
|
+
const stack = roots.map(canonicalize).reverse();
|
|
175
|
+
while (stack.length > 0) {
|
|
176
|
+
const id = stack.pop();
|
|
177
|
+
if (visited.has(id)) continue;
|
|
178
|
+
visited.add(id);
|
|
179
|
+
if (stopAt?.has(id)) continue;
|
|
180
|
+
if (options.clientReferenceIds.has(id)) {
|
|
181
|
+
references.push(id);
|
|
182
|
+
reached.add(id);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const info = getModuleInfo(id);
|
|
186
|
+
if (!info) continue;
|
|
187
|
+
const imports = [...info.importedIds, ...info.dynamicallyImportedIds];
|
|
188
|
+
for (let index = imports.length - 1; index >= 0; index--) stack.push(imports[index]);
|
|
189
|
+
}
|
|
190
|
+
return references;
|
|
191
|
+
};
|
|
192
|
+
const files = [];
|
|
193
|
+
const fileIndices = /* @__PURE__ */ new Map();
|
|
194
|
+
const fileIndex = (file) => {
|
|
195
|
+
const id = canonicalize(file);
|
|
196
|
+
let index = fileIndices.get(id);
|
|
197
|
+
if (index === void 0) {
|
|
198
|
+
index = files.length;
|
|
199
|
+
fileIndices.set(id, index);
|
|
200
|
+
files.push(referencesReachedFrom([id]));
|
|
201
|
+
}
|
|
202
|
+
return index;
|
|
203
|
+
};
|
|
204
|
+
const routes = /* @__PURE__ */ new Map();
|
|
205
|
+
const interceptFiles = [];
|
|
206
|
+
for (const route of options.routes) {
|
|
207
|
+
const indices = inRenderOrder(actionOwnerRouteEntryIds({
|
|
208
|
+
...route,
|
|
209
|
+
parallelSlots: route.parallelSlots.map((slot) => ({
|
|
210
|
+
...slot,
|
|
211
|
+
interceptingRoutes: []
|
|
212
|
+
})),
|
|
213
|
+
siblingIntercepts: []
|
|
214
|
+
})).map(fileIndex);
|
|
215
|
+
routes.set(route.pattern, [.../* @__PURE__ */ new Set([...routes.get(route.pattern) ?? [], ...indices])]);
|
|
216
|
+
for (const intercept of [...route.parallelSlots.flatMap((slot) => slot.interceptingRoutes), ...route.siblingIntercepts]) interceptFiles.push(...interceptEntryIds(intercept));
|
|
217
|
+
}
|
|
218
|
+
const routeless = [...new Set((options.routelessFiles ?? []).map(fileIndex))];
|
|
219
|
+
referencesReachedFrom(interceptFiles);
|
|
220
|
+
const alwaysRoots = options.alwaysRoots ?? [];
|
|
221
|
+
const stopAt = /* @__PURE__ */ new Set([...fileIndices.keys(), ...[...interceptFiles, ...alwaysRoots].map(canonicalize)]);
|
|
222
|
+
const always = /* @__PURE__ */ new Set([...referencesReachedFrom(options.entryIds, stopAt), ...referencesReachedFrom(alwaysRoots)]);
|
|
223
|
+
for (const id of options.clientReferenceIds) if (!reached.has(id)) always.add(id);
|
|
224
|
+
return {
|
|
225
|
+
always: [...always],
|
|
226
|
+
files,
|
|
227
|
+
routes,
|
|
228
|
+
routeless
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function importedName(kind, name) {
|
|
232
|
+
if (kind === "Name") return name;
|
|
233
|
+
return kind === "Default" ? "default" : "*";
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Read a module's static imports and re-exports for
|
|
237
|
+
* {@link measureClientReferenceGroupCosts}. Returns undefined when the code does
|
|
238
|
+
* not parse or a specifier does not resolve to one of `importedIds`.
|
|
239
|
+
*/
|
|
240
|
+
async function readClientModuleBindings(options) {
|
|
241
|
+
const { code } = options;
|
|
242
|
+
const record = parseModuleRecord(code, "js");
|
|
243
|
+
if (!record) return void 0;
|
|
244
|
+
const specifiers = /* @__PURE__ */ new Set([...record.staticImports.map((statement) => statement.moduleRequest.value), ...record.staticExports.flatMap((statement) => statement.entries.flatMap((entry) => entry.moduleRequest ? [entry.moduleRequest.value] : []))]);
|
|
245
|
+
const importedIds = new Set(options.importedIds);
|
|
246
|
+
const ids = /* @__PURE__ */ new Map();
|
|
247
|
+
for (const [specifier, id] of await Promise.all([...specifiers].map(async (specifier) => [specifier, await options.resolve(specifier)]))) {
|
|
248
|
+
if (id === null || !importedIds.has(id)) return void 0;
|
|
249
|
+
ids.set(specifier, id);
|
|
250
|
+
}
|
|
251
|
+
const isIndirect = (statement) => code.startsWith("import", statement.start);
|
|
252
|
+
const exportList = /export\s*[{*]/y;
|
|
253
|
+
const ranges = [
|
|
254
|
+
...record.staticImports,
|
|
255
|
+
...record.staticExports.filter((statement) => {
|
|
256
|
+
exportList.lastIndex = statement.start;
|
|
257
|
+
return exportList.test(code);
|
|
258
|
+
}),
|
|
259
|
+
...record.staticExports.filter(isIndirect).flatMap((statement) => statement.entries)
|
|
260
|
+
].sort((a, b) => a.start - b.start);
|
|
261
|
+
let body = "";
|
|
262
|
+
let offset = 0;
|
|
263
|
+
for (const range of ranges) {
|
|
264
|
+
if (range.start > offset) body += code.slice(offset, range.start);
|
|
265
|
+
offset = Math.max(offset, range.end);
|
|
266
|
+
}
|
|
267
|
+
body += code.slice(offset);
|
|
268
|
+
const reexports = [];
|
|
269
|
+
const localExports = /* @__PURE__ */ new Map();
|
|
270
|
+
const addLocalExport = (key, exportName) => localExports.set(key, [...localExports.get(key) ?? [], exportName]);
|
|
271
|
+
for (const statement of record.staticExports) for (const entry of statement.entries) {
|
|
272
|
+
const exportName = importedName(entry.exportName.kind, entry.exportName.name);
|
|
273
|
+
const importName = importedName(entry.importName.kind, entry.importName.name);
|
|
274
|
+
if (entry.moduleRequest && isIndirect(statement)) addLocalExport(`\0${entry.importName.start}`, exportName);
|
|
275
|
+
else if (entry.moduleRequest) reexports.push({
|
|
276
|
+
id: ids.get(entry.moduleRequest.value),
|
|
277
|
+
exportName,
|
|
278
|
+
importName
|
|
279
|
+
});
|
|
280
|
+
else if (entry.localName.name !== null) addLocalExport(entry.localName.name, exportName);
|
|
281
|
+
}
|
|
282
|
+
const imports = [];
|
|
283
|
+
for (const statement of record.staticImports) {
|
|
284
|
+
const id = ids.get(statement.moduleRequest.value);
|
|
285
|
+
imports.push({
|
|
286
|
+
id,
|
|
287
|
+
names: /* @__PURE__ */ new Set()
|
|
288
|
+
});
|
|
289
|
+
for (const entry of statement.entries) {
|
|
290
|
+
if (entry.isType) continue;
|
|
291
|
+
const name = importedName(entry.importName.kind, entry.importName.name);
|
|
292
|
+
const local = entry.localName.value;
|
|
293
|
+
const exportNames = [...localExports.get(local) ?? [], ...entry.importName.start !== null && localExports.get(`\0${entry.importName.start}`) || []];
|
|
294
|
+
if (exportNames.length > 0 && !new RegExp(`(?<![\\w$])${local.replaceAll("$", "\\$")}(?![\\w$])`).test(body)) for (const exportName of exportNames) reexports.push({
|
|
295
|
+
id,
|
|
296
|
+
exportName,
|
|
297
|
+
importName: name
|
|
298
|
+
});
|
|
299
|
+
else imports.push({
|
|
300
|
+
id,
|
|
301
|
+
names: name === "*" ? "*" : /* @__PURE__ */ new Set([name])
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const covered = new Set(ids.values());
|
|
306
|
+
for (const id of options.importedIds) if (!covered.has(id)) imports.push({
|
|
307
|
+
id,
|
|
308
|
+
names: "*"
|
|
309
|
+
});
|
|
310
|
+
return {
|
|
311
|
+
bytes: Buffer.byteLength(body, "utf8"),
|
|
312
|
+
imports,
|
|
313
|
+
reexports
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Estimate, in transformed source bytes, how much code each client reference
|
|
318
|
+
* would add to a route group's chunk: the modules only it uses, plus the cost
|
|
319
|
+
* of every client reference it statically imports (grouping a reference pulls
|
|
320
|
+
* those along). Modules shared with other client references are not charged
|
|
321
|
+
* to any one of them, so shared libraries do not block grouping. With
|
|
322
|
+
* {@link readClientModuleBindings}, a side-effect-free module only charges the
|
|
323
|
+
* re-exports that are imported from it, so a reference that imports one icon
|
|
324
|
+
* from a barrel is not charged for the whole library.
|
|
325
|
+
*
|
|
326
|
+
* `references` maps each client reference id to its module id in the client
|
|
327
|
+
* graph. `isSideEffectFree` reports a module's package `sideEffects` flag as
|
|
328
|
+
* the bundler resolved it. Traversal stops at modules for which `isExcluded`
|
|
329
|
+
* returns true (CSS, always-loaded framework chunks, virtual modules that must
|
|
330
|
+
* not be loaded re-entrantly). A reference whose import graph cannot be fully
|
|
331
|
+
* loaded is reported as `null` so callers keep it out of groups.
|
|
332
|
+
*/
|
|
333
|
+
async function measureClientReferenceGroupCosts(options) {
|
|
334
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
335
|
+
const load = (id) => {
|
|
336
|
+
let module = loaded.get(id);
|
|
337
|
+
if (!module) {
|
|
338
|
+
module = options.loadModule(id).catch(() => null);
|
|
339
|
+
loaded.set(id, module);
|
|
340
|
+
}
|
|
341
|
+
return module;
|
|
342
|
+
};
|
|
343
|
+
const referenceByModuleId = /* @__PURE__ */ new Map();
|
|
344
|
+
for (const [referenceId, moduleId] of options.references) referenceByModuleId.set(moduleId, referenceId);
|
|
345
|
+
const reexportIndexes = /* @__PURE__ */ new Map();
|
|
346
|
+
const indexReexports = (id, bindings) => {
|
|
347
|
+
let index = reexportIndexes.get(id);
|
|
348
|
+
if (index) return index;
|
|
349
|
+
index = {
|
|
350
|
+
byName: /* @__PURE__ */ new Map(),
|
|
351
|
+
stars: [],
|
|
352
|
+
sideEffectTargets: /* @__PURE__ */ new Set()
|
|
353
|
+
};
|
|
354
|
+
for (const edge of bindings.reexports) {
|
|
355
|
+
if (edge.exportName === "*") {
|
|
356
|
+
index.stars.push(edge);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const edges = index.byName.get(edge.exportName);
|
|
360
|
+
if (edges) edges.push(edge);
|
|
361
|
+
else index.byName.set(edge.exportName, [edge]);
|
|
362
|
+
if (!options.isSideEffectFree(edge.id)) index.sideEffectTargets.add(edge.id);
|
|
363
|
+
}
|
|
364
|
+
reexportIndexes.set(id, index);
|
|
365
|
+
return index;
|
|
366
|
+
};
|
|
367
|
+
const noNames = /* @__PURE__ */ new Set();
|
|
368
|
+
const importedNames = (edge) => edge.importName === "*" ? "*" : /* @__PURE__ */ new Set([edge.importName]);
|
|
369
|
+
const slots = /* @__PURE__ */ new Map();
|
|
370
|
+
const moduleBytes = /* @__PURE__ */ new Map();
|
|
371
|
+
let frontier = [];
|
|
372
|
+
const slot = (id, name) => {
|
|
373
|
+
const key = `${name}\0${id}`;
|
|
374
|
+
let found = slots.get(key);
|
|
375
|
+
if (!found) {
|
|
376
|
+
found = {
|
|
377
|
+
id,
|
|
378
|
+
name,
|
|
379
|
+
children: [],
|
|
380
|
+
references: [],
|
|
381
|
+
failed: false
|
|
382
|
+
};
|
|
383
|
+
slots.set(key, found);
|
|
384
|
+
frontier.push(found);
|
|
385
|
+
}
|
|
386
|
+
return found;
|
|
387
|
+
};
|
|
388
|
+
const link = (from, id, names) => {
|
|
389
|
+
if (options.isExcluded(id)) return;
|
|
390
|
+
const reference = referenceByModuleId.get(id);
|
|
391
|
+
if (reference !== void 0) from.references.push(reference);
|
|
392
|
+
else if (names === "*" || !options.isSideEffectFree(id)) from.children.push(slot(id, "*"));
|
|
393
|
+
else for (const name of names) from.children.push(slot(id, name));
|
|
394
|
+
};
|
|
395
|
+
const rootSlots = /* @__PURE__ */ new Map();
|
|
396
|
+
for (const [referenceId, rootModuleId] of options.references) rootSlots.set(referenceId, slot(rootModuleId, "*"));
|
|
397
|
+
while (frontier.length > 0) {
|
|
398
|
+
const current = frontier;
|
|
399
|
+
frontier = [];
|
|
400
|
+
const modules = await Promise.all(current.map((from) => load(from.id)));
|
|
401
|
+
for (let index = 0; index < modules.length; index++) {
|
|
402
|
+
const module = modules[index];
|
|
403
|
+
const from = current[index];
|
|
404
|
+
if (!module) {
|
|
405
|
+
from.failed = true;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const { bindings } = module;
|
|
409
|
+
moduleBytes.set(from.id, bindings?.bytes ?? (module.code ? Buffer.byteLength(module.code, "utf8") : 0));
|
|
410
|
+
if (!bindings) {
|
|
411
|
+
for (const importedId of module.importedIds) link(from, importedId, "*");
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
for (const edge of bindings.imports) link(from, edge.id, edge.names);
|
|
415
|
+
if (from.name === "*") {
|
|
416
|
+
for (const edge of bindings.reexports) link(from, edge.id, importedNames(edge));
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const reexports = indexReexports(from.id, bindings);
|
|
420
|
+
for (const edge of reexports.byName.get(from.name) ?? []) link(from, edge.id, importedNames(edge));
|
|
421
|
+
const starNames = from.name === "default" ? noNames : /* @__PURE__ */ new Set([from.name]);
|
|
422
|
+
for (const edge of reexports.stars) link(from, edge.id, starNames);
|
|
423
|
+
for (const target of reexports.sideEffectTargets) link(from, target, noNames);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const parents = /* @__PURE__ */ new Map();
|
|
427
|
+
const leads = /* @__PURE__ */ new Set();
|
|
428
|
+
for (const from of slots.values()) {
|
|
429
|
+
for (const child of from.children) {
|
|
430
|
+
let childParents = parents.get(child);
|
|
431
|
+
if (!childParents) {
|
|
432
|
+
childParents = [];
|
|
433
|
+
parents.set(child, childParents);
|
|
434
|
+
}
|
|
435
|
+
childParents.push(from);
|
|
436
|
+
}
|
|
437
|
+
if (from.references.length > 0 || from.failed) leads.add(from);
|
|
438
|
+
}
|
|
439
|
+
for (const lead of leads) for (const parent of parents.get(lead) ?? []) leads.add(parent);
|
|
440
|
+
const importedReferences = /* @__PURE__ */ new Map();
|
|
441
|
+
const unloadable = /* @__PURE__ */ new Set();
|
|
442
|
+
for (const [referenceId, root] of rootSlots) {
|
|
443
|
+
const imported = /* @__PURE__ */ new Set();
|
|
444
|
+
importedReferences.set(referenceId, imported);
|
|
445
|
+
if (!leads.has(root)) continue;
|
|
446
|
+
const visited = /* @__PURE__ */ new Set([root]);
|
|
447
|
+
const stack = [root];
|
|
448
|
+
while (stack.length > 0) {
|
|
449
|
+
const current = stack.pop();
|
|
450
|
+
if (current.failed) unloadable.add(referenceId);
|
|
451
|
+
for (const reference of current.references) if (reference !== referenceId) imported.add(reference);
|
|
452
|
+
for (const child of current.children) if (leads.has(child) && !visited.has(child)) {
|
|
453
|
+
visited.add(child);
|
|
454
|
+
stack.push(child);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
const slotOwners = /* @__PURE__ */ new Map();
|
|
459
|
+
const marks = [];
|
|
460
|
+
for (const [referenceId, root] of rootSlots) if (!unloadable.has(referenceId)) marks.push([root, referenceId]);
|
|
461
|
+
while (marks.length > 0) {
|
|
462
|
+
const [marked, owner] = marks.pop();
|
|
463
|
+
const current = slotOwners.get(marked);
|
|
464
|
+
const next = current === void 0 || current === owner ? owner : null;
|
|
465
|
+
if (next === current) continue;
|
|
466
|
+
slotOwners.set(marked, next);
|
|
467
|
+
for (const child of marked.children) marks.push([child, next]);
|
|
468
|
+
}
|
|
469
|
+
const moduleOwners = /* @__PURE__ */ new Map();
|
|
470
|
+
for (const [marked, owner] of slotOwners) {
|
|
471
|
+
const current = moduleOwners.get(marked.id);
|
|
472
|
+
moduleOwners.set(marked.id, current === void 0 || current === owner ? owner : null);
|
|
473
|
+
}
|
|
474
|
+
const exclusiveBytes = /* @__PURE__ */ new Map();
|
|
475
|
+
for (const [moduleId, owner] of moduleOwners) {
|
|
476
|
+
if (owner === null) continue;
|
|
477
|
+
exclusiveBytes.set(owner, (exclusiveBytes.get(owner) ?? 0) + (moduleBytes.get(moduleId) ?? 0));
|
|
478
|
+
}
|
|
479
|
+
const costs = /* @__PURE__ */ new Map();
|
|
480
|
+
for (const referenceId of options.references.keys()) {
|
|
481
|
+
let cost = 0;
|
|
482
|
+
const visited = /* @__PURE__ */ new Set();
|
|
483
|
+
const queue = [referenceId];
|
|
484
|
+
for (let index = 0; index < queue.length && cost !== null; index++) {
|
|
485
|
+
const current = queue[index];
|
|
486
|
+
if (visited.has(current)) continue;
|
|
487
|
+
visited.add(current);
|
|
488
|
+
cost = unloadable.has(current) ? null : cost + (exclusiveBytes.get(current) ?? 0);
|
|
489
|
+
for (const importedReference of importedReferences.get(current) ?? []) queue.push(importedReference);
|
|
490
|
+
}
|
|
491
|
+
costs.set(referenceId, cost);
|
|
492
|
+
}
|
|
493
|
+
return costs;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Group client references that share a route signature. References without a
|
|
497
|
+
* signature, references whose cost is unknown or above `maxCostBytes`, and
|
|
498
|
+
* signatures with a single member stay ungrouped. Group keys derive from the
|
|
499
|
+
* members' `referenceKeys`, so a group keeps its chunk name when routes change
|
|
500
|
+
* but its members do not.
|
|
501
|
+
*/
|
|
502
|
+
function planClientReferenceGroups(options) {
|
|
503
|
+
const membersBySignature = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const [referenceId, signature] of options.signatures) {
|
|
505
|
+
if (!options.referenceIds.has(referenceId)) continue;
|
|
506
|
+
const cost = options.costs.get(referenceId);
|
|
507
|
+
if (cost == null || cost > options.maxCostBytes) continue;
|
|
508
|
+
let members = membersBySignature.get(signature);
|
|
509
|
+
if (!members) {
|
|
510
|
+
members = [];
|
|
511
|
+
membersBySignature.set(signature, members);
|
|
512
|
+
}
|
|
513
|
+
members.push(referenceId);
|
|
514
|
+
}
|
|
515
|
+
const groups = [];
|
|
516
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
517
|
+
for (const signature of [...membersBySignature.keys()].sort()) {
|
|
518
|
+
const members = membersBySignature.get(signature);
|
|
519
|
+
if (members.length < 2) continue;
|
|
520
|
+
const memberKeys = members.map((referenceId) => options.referenceKeys.get(referenceId));
|
|
521
|
+
const hash = createHash("sha256").update(memberKeys.sort().join("\0")).digest("hex");
|
|
522
|
+
let length = 10;
|
|
523
|
+
while (usedKeys.has(hash.slice(0, length))) length++;
|
|
524
|
+
const key = hash.slice(0, length);
|
|
525
|
+
usedKeys.add(key);
|
|
526
|
+
groups.push({
|
|
527
|
+
key,
|
|
528
|
+
referenceIds: members
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
return groups;
|
|
532
|
+
}
|
|
533
|
+
//#endregion
|
|
534
|
+
export { CLIENT_REFERENCE_GROUP_MAX_COST_BYTES, collectClientReferencePreloadPlan, collectClientReferenceRouteSignatures, measureClientReferenceGroupCosts, planClientReferenceGroups, readClientModuleBindings };
|
|
@@ -1,3 +1,34 @@
|
|
|
1
1
|
//#region src/build/module-dependency-cache.d.ts
|
|
2
2
|
export declare function createModuleDependencyCache<T>(collect: (moduleId: string) => Promise<T>): (moduleId: string) => Promise<T>;
|
|
3
|
+
export type ModuleDependencyEntry<T> = {
|
|
4
|
+
dependencies: T[];
|
|
5
|
+
/** Files the module's imports resolved to, without Vite queries. */
|
|
6
|
+
resolvedFiles: string[];
|
|
7
|
+
/**
|
|
8
|
+
* False when an import did not resolve. Vite only caches modules that
|
|
9
|
+
* transformed, so it retries those imports on every request. So does the store.
|
|
10
|
+
*/
|
|
11
|
+
cacheable: boolean;
|
|
12
|
+
};
|
|
13
|
+
type FileEvent = {
|
|
14
|
+
files: readonly string[];
|
|
15
|
+
event: "create" | "update" | "delete";
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Dependency lists of source modules, kept across loads of a dev virtual
|
|
19
|
+
* module. An entry is dropped by the file events that make Vite transform the
|
|
20
|
+
* module again: an edit, creation or deletion of the module's own file, and
|
|
21
|
+
* deletion of a file one of its imports resolved to.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ModuleDependencyStore<T> {
|
|
24
|
+
private readonly entries;
|
|
25
|
+
private readonly pendingReads;
|
|
26
|
+
read(moduleId: string, collect: (moduleId: string) => Promise<ModuleDependencyEntry<T>>): Promise<T[]>;
|
|
27
|
+
/**
|
|
28
|
+
* `files` holds every spelling of one file, such as its symlinked and real
|
|
29
|
+
* path. Returns whether an entry was dropped.
|
|
30
|
+
*/
|
|
31
|
+
invalidate(files: readonly string[], event: FileEvent["event"]): boolean;
|
|
32
|
+
clear(): void;
|
|
33
|
+
}
|
|
3
34
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripViteModuleQuery } from "../utils/path.js";
|
|
1
2
|
//#region src/build/module-dependency-cache.ts
|
|
2
3
|
function createModuleDependencyCache(collect) {
|
|
3
4
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -9,5 +10,54 @@ function createModuleDependencyCache(collect) {
|
|
|
9
10
|
return pending;
|
|
10
11
|
};
|
|
11
12
|
}
|
|
13
|
+
function isOutdatedBy(moduleId, entry, { files, event }) {
|
|
14
|
+
return files.includes(stripViteModuleQuery(moduleId)) || event === "delete" && entry.resolvedFiles.some((file) => files.includes(file));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Dependency lists of source modules, kept across loads of a dev virtual
|
|
18
|
+
* module. An entry is dropped by the file events that make Vite transform the
|
|
19
|
+
* module again: an edit, creation or deletion of the module's own file, and
|
|
20
|
+
* deletion of a file one of its imports resolved to.
|
|
21
|
+
*/
|
|
22
|
+
var ModuleDependencyStore = class {
|
|
23
|
+
entries = /* @__PURE__ */ new Map();
|
|
24
|
+
pendingReads = /* @__PURE__ */ new Set();
|
|
25
|
+
async read(moduleId, collect) {
|
|
26
|
+
const cached = this.entries.get(moduleId);
|
|
27
|
+
if (cached) return cached.dependencies;
|
|
28
|
+
const pending = { events: [] };
|
|
29
|
+
this.pendingReads.add(pending);
|
|
30
|
+
let entry;
|
|
31
|
+
try {
|
|
32
|
+
entry = await collect(moduleId);
|
|
33
|
+
} finally {
|
|
34
|
+
this.pendingReads.delete(pending);
|
|
35
|
+
}
|
|
36
|
+
if (entry.cacheable && pending.events && !pending.events.some((event) => isOutdatedBy(moduleId, entry, event))) this.entries.set(moduleId, entry);
|
|
37
|
+
return entry.dependencies;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `files` holds every spelling of one file, such as its symlinked and real
|
|
41
|
+
* path. Returns whether an entry was dropped.
|
|
42
|
+
*/
|
|
43
|
+
invalidate(files, event) {
|
|
44
|
+
const fileEvent = {
|
|
45
|
+
files,
|
|
46
|
+
event
|
|
47
|
+
};
|
|
48
|
+
for (const pending of this.pendingReads) pending.events?.push(fileEvent);
|
|
49
|
+
let dropped = false;
|
|
50
|
+
for (const [moduleId, entry] of this.entries) {
|
|
51
|
+
if (!isOutdatedBy(moduleId, entry, fileEvent)) continue;
|
|
52
|
+
this.entries.delete(moduleId);
|
|
53
|
+
dropped = true;
|
|
54
|
+
}
|
|
55
|
+
return dropped;
|
|
56
|
+
}
|
|
57
|
+
clear() {
|
|
58
|
+
for (const pending of this.pendingReads) pending.events = null;
|
|
59
|
+
this.entries.clear();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
12
62
|
//#endregion
|
|
13
|
-
export { createModuleDependencyCache };
|
|
63
|
+
export { ModuleDependencyStore, createModuleDependencyCache };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValidFileMatcher } from "../routing/file-matcher.js";
|
|
1
2
|
import { ResolvedNextConfig } from "../config/next-config.js";
|
|
2
3
|
//#region src/build/next-client-runtime-manifests.d.ts
|
|
3
4
|
type EmitNextClientRuntimeManifestsOptions = {
|
|
@@ -5,8 +6,16 @@ type EmitNextClientRuntimeManifestsOptions = {
|
|
|
5
6
|
assetsSubdir: string;
|
|
6
7
|
buildId: string;
|
|
7
8
|
rewrites: ResolvedNextConfig["rewrites"];
|
|
9
|
+
/** Next.js-format paths of every `pages/` page and API route, e.g. "/posts/[id]". */
|
|
10
|
+
pages: readonly string[];
|
|
8
11
|
};
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Next.js page key for a `pages/` file, e.g. "/posts/[id]". Keeps the raw file
|
|
14
|
+
* name (no decoding), so `pages/caf%C3%A9.js` stays "/caf%C3%A9".
|
|
15
|
+
* Ported from Next.js: packages/next/src/build/route-discovery.ts (`getPageFromPath`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function getPagesManifestPage(pagesDir: string, filePath: string, matcher: Pick<ValidFileMatcher, "stripExtension">): string;
|
|
18
|
+
export declare function buildNextClientBuildManifestContent(rewrites: ResolvedNextConfig["rewrites"], pages: readonly string[]): string;
|
|
10
19
|
export declare function buildNextClientSsgManifestContent(): string;
|
|
11
20
|
export declare function emitNextClientRuntimeManifests(options: EmitNextClientRuntimeManifestsOptions): void;
|
|
12
21
|
//#endregion
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import { getSortedRoutes } from "../routing/route-validation.js";
|
|
2
3
|
import { toClientRewrites } from "../client/client-rewrites.js";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
//#region src/build/next-client-runtime-manifests.ts
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Next.js page key for a `pages/` file, e.g. "/posts/[id]". Keeps the raw file
|
|
8
|
+
* name (no decoding), so `pages/caf%C3%A9.js` stays "/caf%C3%A9".
|
|
9
|
+
* Ported from Next.js: packages/next/src/build/route-discovery.ts (`getPageFromPath`).
|
|
10
|
+
*/
|
|
11
|
+
function getPagesManifestPage(pagesDir, filePath, matcher) {
|
|
12
|
+
const page = `/${matcher.stripExtension(path.relative(pagesDir, filePath))}`;
|
|
13
|
+
const withoutIndex = page.endsWith("/index") ? page.slice(0, -6) : page;
|
|
14
|
+
return withoutIndex === "" ? "/" : withoutIndex;
|
|
15
|
+
}
|
|
16
|
+
function buildNextClientBuildManifestContent(rewrites, pages) {
|
|
6
17
|
const manifest = {
|
|
7
18
|
__rewrites: toClientRewrites(rewrites),
|
|
8
|
-
sortedPages: [
|
|
19
|
+
sortedPages: getSortedRoutes([
|
|
20
|
+
...pages,
|
|
21
|
+
"/_app",
|
|
22
|
+
"/_error"
|
|
23
|
+
])
|
|
9
24
|
};
|
|
10
25
|
return `self.__BUILD_MANIFEST = ${JSON.stringify(manifest)};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()`;
|
|
11
26
|
}
|
|
@@ -15,8 +30,8 @@ function buildNextClientSsgManifestContent() {
|
|
|
15
30
|
function emitNextClientRuntimeManifests(options) {
|
|
16
31
|
const manifestDir = path.join(options.clientDir, options.assetsSubdir, options.buildId);
|
|
17
32
|
fs.mkdirSync(manifestDir, { recursive: true });
|
|
18
|
-
fs.writeFileSync(path.join(manifestDir, "_buildManifest.js"), buildNextClientBuildManifestContent(options.rewrites), "utf-8");
|
|
33
|
+
fs.writeFileSync(path.join(manifestDir, "_buildManifest.js"), buildNextClientBuildManifestContent(options.rewrites, options.pages), "utf-8");
|
|
19
34
|
fs.writeFileSync(path.join(manifestDir, "_ssgManifest.js"), buildNextClientSsgManifestContent(), "utf-8");
|
|
20
35
|
}
|
|
21
36
|
//#endregion
|
|
22
|
-
export { buildNextClientBuildManifestContent, buildNextClientSsgManifestContent, emitNextClientRuntimeManifests };
|
|
37
|
+
export { buildNextClientBuildManifestContent, buildNextClientSsgManifestContent, emitNextClientRuntimeManifests, getPagesManifestPage };
|