vinext 1.0.0-beta.1 → 1.0.0-beta.3
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 +10 -10
- package/dist/build/client-build-config.js +8 -1
- package/dist/build/report.d.ts +8 -1
- package/dist/build/report.js +12 -2
- package/dist/check.js +19 -2
- package/dist/cli.js +3 -2
- package/dist/config/config-matchers.d.ts +13 -37
- package/dist/config/config-matchers.js +35 -122
- package/dist/config/next-config.d.ts +15 -5
- package/dist/config/next-config.js +7 -1
- package/dist/config/request-context.d.ts +14 -0
- package/dist/config/request-context.js +26 -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 +30 -9
- package/dist/entries/app-rsc-manifest.js +36 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +13 -5
- package/dist/index.js +194 -101
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/init.d.ts +6 -4
- package/dist/init.js +20 -22
- 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/og-assets.js +1 -1
- package/dist/plugins/require-context.js +20 -15
- 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 +27 -11
- package/dist/routing/app-route-graph.js +158 -22
- package/dist/routing/app-router.js +12 -6
- package/dist/routing/file-matcher.d.ts +11 -22
- package/dist/routing/file-matcher.js +21 -33
- package/dist/routing/pages-router.js +23 -29
- package/dist/routing/route-matching.d.ts +14 -1
- package/dist/routing/route-matching.js +13 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +7 -4
- package/dist/routing/route-trie.d.ts +5 -1
- package/dist/routing/route-trie.js +5 -2
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +3 -3
- package/dist/server/app-browser-entry.js +110 -37
- package/dist/server/app-browser-history-controller.d.ts +1 -1
- package/dist/server/app-browser-history-controller.js +3 -3
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +2 -2
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +3 -0
- package/dist/server/app-fallback-renderer.js +4 -2
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +12 -1
- package/dist/server/app-page-boundary-render.js +84 -2
- package/dist/server/app-page-cache-finalizer.d.ts +1 -1
- package/dist/server/app-page-cache-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +2 -2
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +19 -2
- package/dist/server/app-page-dispatch.js +45 -23
- package/dist/server/app-page-element-builder.d.ts +9 -2
- package/dist/server/app-page-element-builder.js +144 -33
- package/dist/server/app-page-head.d.ts +56 -4
- package/dist/server/app-page-head.js +216 -85
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
- 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 +2 -2
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-request.d.ts +15 -0
- package/dist/server/app-page-request.js +134 -14
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +16 -0
- package/dist/server/app-page-route-wiring.js +254 -52
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -1
- package/dist/server/app-post-middleware-context.d.ts +1 -1
- package/dist/server/app-post-middleware-context.js +1 -1
- package/dist/server/app-route-handler-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +40 -20
- package/dist/server/app-route-handler-execution.d.ts +6 -1
- package/dist/server/app-route-handler-execution.js +42 -16
- package/dist/server/app-route-handler-policy.d.ts +2 -0
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +9 -1
- package/dist/server/app-route-module-loader.js +4 -0
- package/dist/server/app-router-entry.js +6 -3
- package/dist/server/app-rsc-cache-busting.d.ts +1 -1
- package/dist/server/app-rsc-errors.d.ts +1 -1
- package/dist/server/app-rsc-errors.js +22 -2
- package/dist/server/app-rsc-handler.d.ts +10 -5
- package/dist/server/app-rsc-handler.js +73 -33
- package/dist/server/app-rsc-request-normalization.d.ts +3 -2
- package/dist/server/app-rsc-request-normalization.js +8 -2
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
- package/dist/server/app-rsc-response-finalizer.js +5 -11
- package/dist/server/app-rsc-route-matching.d.ts +29 -0
- package/dist/server/app-rsc-route-matching.js +93 -11
- package/dist/server/app-segment-config.js +13 -3
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +9 -7
- package/dist/server/app-ssr-entry.js +6 -6
- package/dist/server/app-ssr-stream.d.ts +1 -7
- package/dist/server/app-ssr-stream.js +2 -10
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- package/dist/server/config-headers.d.ts +24 -0
- package/dist/server/config-headers.js +52 -0
- package/dist/server/dev-initial-server-error.d.ts +1 -1
- package/dist/server/dev-server.d.ts +3 -1
- package/dist/server/dev-server.js +170 -321
- package/dist/server/headers.d.ts +2 -2
- package/dist/server/headers.js +4 -3
- package/dist/server/isr-cache.d.ts +11 -34
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- package/dist/server/middleware-matcher-pattern.d.ts +22 -0
- package/dist/server/middleware-matcher-pattern.js +219 -0
- package/dist/server/middleware-matcher.d.ts +2 -7
- package/dist/server/middleware-matcher.js +13 -60
- package/dist/server/middleware-path-to-regexp.d.ts +14 -0
- package/dist/server/middleware-path-to-regexp.js +228 -0
- package/dist/server/middleware-runtime.js +4 -3
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +2 -1
- package/dist/server/pages-api-route.d.ts +2 -0
- package/dist/server/pages-api-route.js +4 -1
- package/dist/server/pages-data-route.d.ts +11 -1
- package/dist/server/pages-data-route.js +16 -1
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-get-initial-props.d.ts +16 -3
- package/dist/server/pages-get-initial-props.js +17 -10
- 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 +7 -3
- package/dist/server/pages-page-data.d.ts +64 -10
- package/dist/server/pages-page-data.js +349 -80
- package/dist/server/pages-page-handler.d.ts +9 -3
- package/dist/server/pages-page-handler.js +131 -36
- package/dist/server/pages-page-response.d.ts +5 -3
- package/dist/server/pages-page-response.js +24 -27
- package/dist/server/pages-readiness.d.ts +3 -3
- package/dist/server/pages-request-pipeline.d.ts +8 -0
- package/dist/server/pages-request-pipeline.js +30 -12
- 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 +16 -4
- package/dist/server/prerender-route-params.js +2 -2
- package/dist/server/prod-server.d.ts +3 -5
- package/dist/server/prod-server.js +72 -35
- package/dist/server/request-pipeline.d.ts +15 -29
- package/dist/server/request-pipeline.js +24 -59
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/rsc-stream-hints.js +122 -18
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +29 -0
- package/dist/shims/app.d.ts +1 -1
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- package/dist/shims/cache-request-state.d.ts +27 -1
- package/dist/shims/cache-request-state.js +60 -1
- package/dist/shims/cache-runtime.d.ts +18 -1
- package/dist/shims/cache-runtime.js +26 -8
- package/dist/shims/cache.d.ts +5 -5
- package/dist/shims/cache.js +27 -11
- package/dist/shims/document.d.ts +42 -83
- package/dist/shims/document.js +62 -53
- package/dist/shims/dynamic.d.ts +5 -25
- package/dist/shims/dynamic.js +29 -8
- package/dist/shims/error.d.ts +1 -1
- package/dist/shims/error.js +2 -2
- package/dist/shims/fetch-cache.js +13 -4
- package/dist/shims/font-google-base.d.ts +11 -4
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.d.ts +10 -3
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/head.d.ts +13 -2
- package/dist/shims/head.js +3 -3
- package/dist/shims/headers.d.ts +37 -43
- package/dist/shims/headers.js +183 -74
- package/dist/shims/image.d.ts +27 -37
- package/dist/shims/image.js +21 -14
- package/dist/shims/internal/cookie-serialize.d.ts +12 -9
- package/dist/shims/internal/cookie-serialize.js +10 -7
- package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- package/dist/shims/internal/utils.d.ts +3 -3
- package/dist/shims/legacy-image.d.ts +3 -37
- package/dist/shims/legacy-image.js +6 -16
- package/dist/shims/link.d.ts +15 -22
- package/dist/shims/link.js +34 -13
- package/dist/shims/metadata.d.ts +7 -17
- package/dist/shims/metadata.js +74 -24
- package/dist/shims/navigation-context-state.d.ts +1 -1
- package/dist/shims/navigation.d.ts +7 -3
- package/dist/shims/navigation.js +25 -14
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/next-shims-augmentations.d.ts +1 -0
- package/dist/shims/next-shims-public.d.ts +1 -0
- package/dist/shims/public-shim-map.json.js +103 -0
- package/dist/shims/readonly-url-search-params.d.ts +3 -3
- package/dist/shims/readonly-url-search-params.js +3 -3
- package/dist/shims/request-context.d.ts +4 -1
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router.d.ts +55 -21
- package/dist/shims/router.js +180 -44
- package/dist/shims/script.d.ts +6 -10
- package/dist/shims/script.js +7 -4
- package/dist/shims/server.d.ts +50 -26
- package/dist/shims/server.js +193 -55
- package/dist/shims/unified-request-context.d.ts +22 -3
- package/dist/shims/unified-request-context.js +84 -1
- package/dist/shims/url-safety.d.ts +1 -1
- package/dist/shims/url-safety.js +2 -2
- package/dist/typegen.d.ts +8 -2
- package/dist/typegen.js +76 -15
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- package/dist/utils/domain-locale.d.ts +2 -2
- package/dist/utils/external-url.d.ts +5 -0
- package/dist/utils/external-url.js +7 -0
- 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/dist/utils/regex-safety.d.ts +8 -0
- package/dist/utils/regex-safety.js +737 -0
- package/package.json +13 -2
package/dist/init-cloudflare.js
CHANGED
|
@@ -16,7 +16,7 @@ function validateCloudflarePlatformSetup(context, cloudflare) {
|
|
|
16
16
|
const projectInfo = detectProject(context.root);
|
|
17
17
|
const wranglerPath = ["wrangler.jsonc", "wrangler.json"].map((fileName) => path.join(context.root, fileName)).find((candidate) => fs.existsSync(candidate));
|
|
18
18
|
const wranglerCode = wranglerPath ? fs.readFileSync(wranglerPath, "utf-8") : void 0;
|
|
19
|
-
const updatedWranglerCode = wranglerCode ? updateWranglerConfigForCloudflare(wranglerCode, cloudflare) : void 0;
|
|
19
|
+
const updatedWranglerCode = wranglerCode ? updateWranglerConfigForCloudflare(wranglerCode, cloudflare, { root: context.root }) : void 0;
|
|
20
20
|
const imagesBinding = updatedWranglerCode ? getWranglerImagesBinding(updatedWranglerCode) : "IMAGES";
|
|
21
21
|
if (context.existingViteConfigPath) updateViteConfigForCloudflare(context.existingViteConfigPath, fs.readFileSync(context.existingViteConfigPath, "utf-8"), {
|
|
22
22
|
isAppRouter: context.isAppRouter,
|
|
@@ -56,7 +56,7 @@ function setupCloudflarePlatform(context, cloudflare) {
|
|
|
56
56
|
fs.writeFileSync(path.join(context.root, "wrangler.jsonc"), generateWranglerConfig(projectInfo, cloudflare, context.today), "utf-8");
|
|
57
57
|
generatedPlatformFiles.push("wrangler.jsonc");
|
|
58
58
|
} else if (wranglerCode) {
|
|
59
|
-
const updatedConfig = updateWranglerConfigForCloudflare(wranglerCode, cloudflare);
|
|
59
|
+
const updatedConfig = updateWranglerConfigForCloudflare(wranglerCode, cloudflare, { root: context.root });
|
|
60
60
|
if (updatedConfig !== wranglerCode) {
|
|
61
61
|
fs.writeFileSync(wranglerPath, updatedConfig, "utf-8");
|
|
62
62
|
generatedPlatformFiles.push(path.basename(wranglerPath));
|
|
@@ -79,8 +79,19 @@ function setupCloudflarePlatform(context, cloudflare) {
|
|
|
79
79
|
] : []
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* `main` is what makes a Wrangler config a Worker rather than a static-assets
|
|
84
|
+
* project. A custom `worker/index.*` wins when present; otherwise the
|
|
85
|
+
* router-selected entry resolves to the App or Pages Router handler at build
|
|
86
|
+
* time.
|
|
87
|
+
*/
|
|
88
|
+
function resolveWorkerEntry(root) {
|
|
89
|
+
if (fs.existsSync(path.join(root, "worker", "index.ts"))) return "./worker/index.ts";
|
|
90
|
+
if (fs.existsSync(path.join(root, "worker", "index.js"))) return "./worker/index.js";
|
|
91
|
+
return "vinext/server/fetch-handler";
|
|
92
|
+
}
|
|
82
93
|
function generateWranglerConfig(info, options = DEFAULT_CLOUDFLARE_INIT_OPTIONS, today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0]) {
|
|
83
|
-
const workerEntry = (
|
|
94
|
+
const workerEntry = resolveWorkerEntry(info.root);
|
|
84
95
|
const config = {
|
|
85
96
|
$schema: "node_modules/wrangler/config-schema.json",
|
|
86
97
|
name: info.projectName,
|
|
@@ -258,13 +269,20 @@ function appendTopLevelJsonProperty(code, property) {
|
|
|
258
269
|
const structuralBefore = stripJsonComments(before);
|
|
259
270
|
return `${before}${!/,\s*$/.test(structuralBefore) && !/{\s*$/.test(structuralBefore) ? "," : ""}\n${property}\n${code.slice(closing)}`;
|
|
260
271
|
}
|
|
261
|
-
function updateWranglerConfigForCloudflare(code, options) {
|
|
272
|
+
function updateWranglerConfigForCloudflare(code, options, context = {}) {
|
|
273
|
+
let config;
|
|
262
274
|
try {
|
|
263
|
-
JSON.parse(stripJsonComments(code));
|
|
275
|
+
config = JSON.parse(stripJsonComments(code));
|
|
264
276
|
} catch (cause) {
|
|
265
277
|
throw new Error("Could not parse the existing Wrangler JSON/JSONC config.", { cause });
|
|
266
278
|
}
|
|
279
|
+
if (Object.hasOwn(config, "pages_build_output_dir")) throw new Error("The existing Wrangler config uses \"pages_build_output_dir\", which cannot be combined with the Worker \"main\" required by vinext. Remove \"pages_build_output_dir\" and rerun vinext init.");
|
|
267
280
|
let output = code;
|
|
281
|
+
if (!findTopLevelJsonProperty(output, "main")) {
|
|
282
|
+
const workerEntry = resolveWorkerEntry(context.root ?? process.cwd());
|
|
283
|
+
output = appendTopLevelJsonProperty(output, ` "main": ${JSON.stringify(workerEntry)}`);
|
|
284
|
+
}
|
|
285
|
+
if (!findTopLevelJsonProperty(output, "assets")) output = appendTopLevelJsonProperty(output, " \"assets\": { \"directory\": \"dist/client\", \"not_found_handling\": \"none\", \"binding\": \"ASSETS\" }");
|
|
268
286
|
if (options.cdnCache === "workers-cache") {
|
|
269
287
|
const cacheProperty = findTopLevelJsonProperty(output, "cache");
|
|
270
288
|
if (!cacheProperty) output = appendTopLevelJsonProperty(output, " \"cache\": { \"enabled\": true }");
|
|
@@ -613,6 +631,41 @@ function endsWithCommaIgnoringWhitespaceAndComments(code) {
|
|
|
613
631
|
function cloudflarePluginExpression(isAppRouter, binding) {
|
|
614
632
|
return isAppRouter ? `${binding}({\n viteEnvironment: {\n name: "rsc",\n childEnvironments: ["ssr"],\n },\n})` : `${binding}()`;
|
|
615
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* An existing bare `cloudflare()` call is left as-is by `ensurePlugins`, which
|
|
636
|
+
* only adds plugins that are absent. For the App Router that silently drops
|
|
637
|
+
* `viteEnvironment`, so the RSC environment never runs in workerd.
|
|
638
|
+
*/
|
|
639
|
+
function ensureCloudflareViteEnvironment(output, config, binding, isAppRouter, code) {
|
|
640
|
+
if (!isAppRouter) return;
|
|
641
|
+
const call = findPluginCall(config, binding);
|
|
642
|
+
if (!call) return;
|
|
643
|
+
const viteEnvironment = `viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] }`;
|
|
644
|
+
const firstArgument = call.arguments[0];
|
|
645
|
+
if (!firstArgument) {
|
|
646
|
+
output.appendLeft(call.end - 1, `{ ${viteEnvironment} }`);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (firstArgument.type === "SpreadElement" || firstArgument.type !== "ObjectExpression") throw new Error("The cloudflare() plugin options must be a static object for vinext init to configure the App Router Vite environment.");
|
|
650
|
+
const argumentObject = firstArgument;
|
|
651
|
+
const existingViteEnvironment = argumentObject.properties.filter((property) => property.type === "Property" && propertyName(property) === "viteEnvironment").at(-1);
|
|
652
|
+
if (existingViteEnvironment) {
|
|
653
|
+
const propertyIndex = argumentObject.properties.lastIndexOf(existingViteEnvironment);
|
|
654
|
+
if (argumentObject.properties.slice(propertyIndex + 1).some((property) => property.type === "SpreadElement")) throw new Error("The cloudflare() viteEnvironment option must appear after any spread properties so vinext init can verify it.");
|
|
655
|
+
if (existingViteEnvironment.value.type !== "ObjectExpression") throw new Error("The cloudflare() viteEnvironment option must be a static object with name: \"rsc\" and childEnvironments containing \"ssr\".");
|
|
656
|
+
const environmentObject = existingViteEnvironment.value;
|
|
657
|
+
const nameProperties = environmentObject.properties.filter((property) => property.type === "Property" && propertyName(property) === "name");
|
|
658
|
+
const childEnvironmentProperties = environmentObject.properties.filter((property) => property.type === "Property" && propertyName(property) === "childEnvironments");
|
|
659
|
+
const name = nameProperties[0];
|
|
660
|
+
const childEnvironments = childEnvironmentProperties[0];
|
|
661
|
+
const hasAmbiguousProperties = environmentObject.properties.some((property) => property.type === "SpreadElement") || nameProperties.length !== 1 || childEnvironmentProperties.length !== 1;
|
|
662
|
+
const hasRequiredName = name?.value.type === "Literal" && name.value.value === "rsc";
|
|
663
|
+
const hasRequiredChild = childEnvironments?.value.type === "ArrayExpression" && childEnvironments.value.elements.some((element) => element?.type === "Literal" && element.value === "ssr");
|
|
664
|
+
if (hasAmbiguousProperties || !hasRequiredName || !hasRequiredChild) throw new Error("The cloudflare() viteEnvironment option must statically set name: \"rsc\" and include \"ssr\" in childEnvironments.");
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
insertObjectProperty(output, argumentObject, `${code.slice(0, call.start).split("\n").at(-1)?.match(/^\s*/)?.[0] ?? ""} ${viteEnvironment},`, code);
|
|
668
|
+
}
|
|
616
669
|
function findPluginCall(config, binding) {
|
|
617
670
|
const plugins = findProperty(config, "plugins");
|
|
618
671
|
if (!plugins || plugins.value.type !== "ArrayExpression") return void 0;
|
|
@@ -819,6 +872,7 @@ function updateViteConfigForCloudflare(filePath, code, options) {
|
|
|
819
872
|
expression: cloudflarePluginExpression(options.isAppRouter, cloudflareBinding),
|
|
820
873
|
binding: cloudflareBinding
|
|
821
874
|
}], code);
|
|
875
|
+
ensureCloudflareViteEnvironment(output, config, cloudflareBinding, options.isAppRouter, code);
|
|
822
876
|
if (existingVinextCall) if (existingVinextCall.arguments.length === 0 && (cacheAdditions.length > 0 || imageOptimizerExpression || needsPrerender)) {
|
|
823
877
|
const properties = [];
|
|
824
878
|
if (cacheAdditions.length > 0) properties.push(`cache: { ${cacheAdditions.map(({ name, expression }) => `${name}: ${expression}`).join(", ")} }`);
|
package/dist/init.d.ts
CHANGED
|
@@ -3,14 +3,15 @@ import { getReactUpgradeDeps } from "./utils/react-version.js";
|
|
|
3
3
|
|
|
4
4
|
//#region src/init.d.ts
|
|
5
5
|
type InitOptions = {
|
|
6
|
-
/** Project root directory */root: string; /** Dev server port (default: 3001) */
|
|
7
|
-
port?: number; /** Skip the compatibility check step */
|
|
6
|
+
/** Project root directory */root: string; /** Dev server port (default: 3001), or false to omit the port flag. */
|
|
7
|
+
port?: number | false; /** Skip the compatibility check step */
|
|
8
8
|
skipCheck?: boolean; /** Force overwrite even if vite.config.ts exists */
|
|
9
9
|
force?: boolean; /** Deployment target selected by the user */
|
|
10
10
|
platform?: InitPlatform; /** Configure build-time pre-rendering for all discovered static routes */
|
|
11
11
|
prerender?: boolean; /** Cloudflare cache and image choices. */
|
|
12
12
|
cloudflare?: CloudflareInitOptions; /** Install missing dependencies with the detected package manager (default: true). */
|
|
13
|
-
install?: boolean; /**
|
|
13
|
+
install?: boolean; /** Script naming style (default: namespaced, e.g. dev:vinext). */
|
|
14
|
+
scriptNames?: "namespaced" | "standard"; /** @internal — override exec for testing (avoids ESM spy issues) */
|
|
14
15
|
_exec?: (cmd: string, opts: {
|
|
15
16
|
cwd: string;
|
|
16
17
|
stdio: string;
|
|
@@ -34,8 +35,9 @@ declare function generateViteConfig(_isAppRouter: boolean, prerender?: boolean):
|
|
|
34
35
|
* Add vinext scripts to package.json without overwriting existing scripts.
|
|
35
36
|
* Returns the list of script names that were added.
|
|
36
37
|
*/
|
|
37
|
-
declare function addScripts(root: string, port: number, platform?: InitPlatform, options?: {
|
|
38
|
+
declare function addScripts(root: string, port: number | false, platform?: InitPlatform, options?: {
|
|
38
39
|
warmCdnCache?: boolean;
|
|
40
|
+
scriptNames?: "namespaced" | "standard";
|
|
39
41
|
}): string[];
|
|
40
42
|
type InitDependencyGroups = {
|
|
41
43
|
dependencies: string[];
|
package/dist/init.js
CHANGED
|
@@ -78,22 +78,16 @@ function addScripts(root, port, platform = "node", options = {}) {
|
|
|
78
78
|
const pkg = JSON.parse(raw);
|
|
79
79
|
if (!pkg.scripts) pkg.scripts = {};
|
|
80
80
|
const added = [];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
added.push("start:vinext");
|
|
92
|
-
}
|
|
93
|
-
if (platform === "cloudflare" && !pkg.scripts["deploy:vinext"]) {
|
|
94
|
-
pkg.scripts["deploy:vinext"] = options.warmCdnCache ? "vinext-cloudflare deploy --config dist/server/wrangler.json --experimental-warm-cdn-cache" : "vinext-cloudflare deploy --config dist/server/wrangler.json";
|
|
95
|
-
added.push("deploy:vinext");
|
|
96
|
-
}
|
|
81
|
+
const addScript = (name, command) => {
|
|
82
|
+
const scriptName = options.scriptNames === "standard" ? name : `${name}:vinext`;
|
|
83
|
+
if (pkg.scripts[scriptName]) return;
|
|
84
|
+
pkg.scripts[scriptName] = command;
|
|
85
|
+
added.push(scriptName);
|
|
86
|
+
};
|
|
87
|
+
addScript("dev", port === false ? "vinext dev" : `vinext dev --port ${port}`);
|
|
88
|
+
addScript("build", "vinext build");
|
|
89
|
+
addScript("start", platform === "cloudflare" ? "wrangler dev --config dist/server/wrangler.json" : "vinext start");
|
|
90
|
+
if (platform === "cloudflare") addScript("deploy", options.warmCdnCache ? "vinext-cloudflare deploy --config dist/server/wrangler.json --experimental-warm-cdn-cache" : "vinext-cloudflare deploy --config dist/server/wrangler.json");
|
|
97
91
|
if (added.length > 0) fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
98
92
|
return added;
|
|
99
93
|
} catch {
|
|
@@ -342,7 +336,10 @@ async function init(options) {
|
|
|
342
336
|
existingViteConfigPath = renamedPath;
|
|
343
337
|
}
|
|
344
338
|
const addedTypeModule = ensureESModule(root);
|
|
345
|
-
const addedScripts = addScripts(root, port, platform, {
|
|
339
|
+
const addedScripts = addScripts(root, port, platform, {
|
|
340
|
+
warmCdnCache: options.cloudflare?.warmCdnCache ?? false,
|
|
341
|
+
scriptNames: options.scriptNames
|
|
342
|
+
});
|
|
346
343
|
const setupContext = {
|
|
347
344
|
root,
|
|
348
345
|
isAppRouter: isApp,
|
|
@@ -436,15 +433,16 @@ async function init(options) {
|
|
|
436
433
|
if (updatedGitignore) console.log(` ${terminalStyle.green("✓")} Added vinext output directories to .gitignore`);
|
|
437
434
|
const nextSteps = [...platformSetup.nextSteps];
|
|
438
435
|
if (dependencyInstallNeedsApproval) nextSteps.push("Dependency installation is incomplete because pnpm blocked dependency build scripts:", "1. Review and approve the required build scripts:", " pnpm approve-builds", "2. Finish installing dependencies:", " pnpm install");
|
|
439
|
-
const
|
|
436
|
+
const scriptName = (name) => options.scriptNames === "standard" ? name : `${name}:vinext`;
|
|
437
|
+
const deployCommandStep = platform === "cloudflare" ? ` ${pmName} run ${scriptName("deploy")} Deploy to Cloudflare Workers\n` : "";
|
|
440
438
|
const startCommandDescription = platform === "cloudflare" ? "Start the built Worker locally with Wrangler" : "Start vinext production server";
|
|
441
439
|
console.log(`
|
|
442
440
|
${terminalStyle.cyan(terminalStyle.bold("Next steps:"))}
|
|
443
441
|
${nextSteps.map((step) => ` ${step}`).join("\n")}${nextSteps.length > 0 ? "\n" : ""}
|
|
444
|
-
${pmName} run dev
|
|
445
|
-
${pmName} run build
|
|
446
|
-
${pmName} run start
|
|
447
|
-
${deployCommandStep} ${pmName} run dev Start Next.js (still works as before)
|
|
442
|
+
${pmName} run ${scriptName("dev")} Start the vinext dev server
|
|
443
|
+
${pmName} run ${scriptName("build")} Build production output
|
|
444
|
+
${pmName} run ${scriptName("start")} ${startCommandDescription}
|
|
445
|
+
${deployCommandStep}${options.scriptNames === "standard" ? "" : ` ${pmName} run dev Start Next.js (still works as before)\n`}
|
|
448
446
|
`);
|
|
449
447
|
return {
|
|
450
448
|
installedDeps: [.../* @__PURE__ */ new Set([...dependencyEntriesAdded, ...devDependencyEntriesAdded])],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DYNAMIC_IMPORT_PRESCAN, forEachAstChild, hasRange, isAstRecord, nodeArray } from "./ast-utils.js";
|
|
2
|
+
import { createTransformCache } from "./transform-cache.js";
|
|
2
3
|
import { parseAst } from "vite";
|
|
3
4
|
import MagicString from "magic-string";
|
|
4
5
|
//#region src/plugins/extensionless-dynamic-import.ts
|
|
@@ -23,6 +24,7 @@ const TRANSFORMABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
23
24
|
]);
|
|
24
25
|
function createExtensionlessDynamicImportPlugin() {
|
|
25
26
|
let moduleExtensions = MODULE_EXTENSIONS;
|
|
27
|
+
const cached = createTransformCache();
|
|
26
28
|
return {
|
|
27
29
|
name: "vinext:extensionless-dynamic-import",
|
|
28
30
|
enforce: "pre",
|
|
@@ -38,28 +40,31 @@ function createExtensionlessDynamicImportPlugin() {
|
|
|
38
40
|
code: DYNAMIC_IMPORT_PRESCAN
|
|
39
41
|
},
|
|
40
42
|
handler(code, id) {
|
|
41
|
-
|
|
42
|
-
let ast;
|
|
43
|
-
try {
|
|
44
|
-
ast = parseAst(code, { lang });
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const imports = collectExtensionlessImports(ast, code, moduleExtensions);
|
|
49
|
-
if (imports.length === 0) return null;
|
|
50
|
-
const output = new MagicString(code);
|
|
51
|
-
for (const dynamicImport of imports) {
|
|
52
|
-
const source = code.slice(dynamicImport.sourceStart, dynamicImport.sourceEnd);
|
|
53
|
-
output.overwrite(dynamicImport.start, dynamicImport.end, buildReplacement(source, dynamicImport.globPattern, dynamicImport.moduleExtensions));
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
code: output.toString(),
|
|
57
|
-
map: output.generateMap({ hires: "boundary" })
|
|
58
|
-
};
|
|
43
|
+
return cached(id, code, moduleExtensions, () => transformExtensionlessImports(code, id, moduleExtensions));
|
|
59
44
|
}
|
|
60
45
|
}
|
|
61
46
|
};
|
|
62
47
|
}
|
|
48
|
+
function transformExtensionlessImports(code, id, moduleExtensions) {
|
|
49
|
+
const lang = langForId(id);
|
|
50
|
+
let ast;
|
|
51
|
+
try {
|
|
52
|
+
ast = parseAst(code, { lang });
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const imports = collectExtensionlessImports(ast, code, moduleExtensions);
|
|
57
|
+
if (imports.length === 0) return null;
|
|
58
|
+
const output = new MagicString(code);
|
|
59
|
+
for (const dynamicImport of imports) {
|
|
60
|
+
const source = code.slice(dynamicImport.sourceStart, dynamicImport.sourceEnd);
|
|
61
|
+
output.overwrite(dynamicImport.start, dynamicImport.end, buildReplacement(source, dynamicImport.globPattern, dynamicImport.moduleExtensions));
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
code: output.toString(),
|
|
65
|
+
map: output.generateMap({ hires: "boundary" })
|
|
66
|
+
};
|
|
67
|
+
}
|
|
63
68
|
function langForId(id) {
|
|
64
69
|
const clean = id.split("?", 1)[0];
|
|
65
70
|
const dot = clean.lastIndexOf(".");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { DYNAMIC_IMPORT_PRESCAN, collectBindingNames, forEachAstChild, hasRange, isAstRecord, isIdentifierNamed, mayContainDynamicImport, nodeArray } from "./ast-utils.js";
|
|
3
|
+
import { createTransformCache } from "./transform-cache.js";
|
|
3
4
|
import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, hasAstBinding, isFunctionNode } from "./ast-scope.js";
|
|
4
5
|
import { parseAst } from "vite";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -505,6 +506,7 @@ function transformVeryDynamicRequests(code, id) {
|
|
|
505
506
|
};
|
|
506
507
|
}
|
|
507
508
|
function createIgnoreDynamicRequestsPlugin(getTranspiledPackages = () => []) {
|
|
509
|
+
const cached = createTransformCache();
|
|
508
510
|
return {
|
|
509
511
|
name: "vinext:ignore-dynamic-requests",
|
|
510
512
|
enforce: "pre",
|
|
@@ -519,7 +521,7 @@ function createIgnoreDynamicRequestsPlugin(getTranspiledPackages = () => []) {
|
|
|
519
521
|
if (!shouldTransformVeryDynamicRequests(this.environment, cleanId, getTranspiledPackages())) return null;
|
|
520
522
|
const absoluteId = path.resolve(cleanId);
|
|
521
523
|
if (absoluteId === VINEXT_SOURCE_ROOT || absoluteId.startsWith(`${VINEXT_SOURCE_ROOT}/`) || PLUGIN_RSC_PATH.test(absoluteId)) return null;
|
|
522
|
-
return transformVeryDynamicRequests(code, id);
|
|
524
|
+
return cached(id, code, void 0, () => transformVeryDynamicRequests(code, id));
|
|
523
525
|
}
|
|
524
526
|
}
|
|
525
527
|
};
|
|
@@ -19,6 +19,7 @@ const TRANSFORMABLE_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
19
19
|
function createImportMetaUrlPlugin(options) {
|
|
20
20
|
let rootPaths;
|
|
21
21
|
let outputDirs = [];
|
|
22
|
+
const transformCache = /* @__PURE__ */ new Map();
|
|
22
23
|
function getRootPaths() {
|
|
23
24
|
const root = options.getRoot();
|
|
24
25
|
if (!root) return rootPaths;
|
|
@@ -46,12 +47,22 @@ function createImportMetaUrlPlugin(options) {
|
|
|
46
47
|
if (!paths) return null;
|
|
47
48
|
const canonicalId = transformableModuleCanonicalId(cleanModuleId(id), paths);
|
|
48
49
|
if (!canonicalId) return null;
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
const environment = this.environment?.name === "client" ? "client" : "server";
|
|
51
|
+
let entry = transformCache.get(id);
|
|
52
|
+
if (!entry || entry.source !== code || entry.canonicalRoot !== paths.canonicalRoot || entry.canonicalId !== canonicalId) {
|
|
53
|
+
entry = {
|
|
54
|
+
source: code,
|
|
55
|
+
canonicalRoot: paths.canonicalRoot,
|
|
56
|
+
canonicalId,
|
|
57
|
+
results: /* @__PURE__ */ new Map()
|
|
58
|
+
};
|
|
59
|
+
transformCache.set(id, entry);
|
|
60
|
+
}
|
|
61
|
+
const cached = entry.results.get(environment);
|
|
62
|
+
if (cached) return cached.value;
|
|
63
|
+
const value = rewriteCanonicalSourceIdentity(code, canonicalId, paths, environment);
|
|
64
|
+
entry.results.set(environment, { value });
|
|
65
|
+
return value;
|
|
55
66
|
}
|
|
56
67
|
}
|
|
57
68
|
};
|
|
@@ -109,7 +109,7 @@ const OG_WASM_ASSETS = ["resvg.wasm", "yoga.wasm"];
|
|
|
109
109
|
*/
|
|
110
110
|
function findEmittedWasmAsset(bundle, baseName) {
|
|
111
111
|
const stem = baseName.replace(/\.wasm$/, "");
|
|
112
|
-
const re = new RegExp(`^${stem}(
|
|
112
|
+
const re = new RegExp(`^${stem}(?:[-.][\\w-]+)?\\.wasm$`);
|
|
113
113
|
for (const output of Object.values(bundle)) {
|
|
114
114
|
if (output.type !== "asset") continue;
|
|
115
115
|
if (re.test(path.basename(output.fileName))) return output.fileName;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { forEachAstChild, hasRange, isAstRecord, nodeArray } from "./ast-utils.js";
|
|
2
|
+
import { createTransformCache } from "./transform-cache.js";
|
|
2
3
|
import { parseAst } from "vite";
|
|
3
4
|
import MagicString from "magic-string";
|
|
4
5
|
//#region src/plugins/require-context.ts
|
|
@@ -13,6 +14,7 @@ const TRANSFORMABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
13
14
|
".cts"
|
|
14
15
|
]);
|
|
15
16
|
function createRequireContextPlugin() {
|
|
17
|
+
const cached = createTransformCache();
|
|
16
18
|
return {
|
|
17
19
|
name: "vinext:require-context",
|
|
18
20
|
enforce: "pre",
|
|
@@ -22,25 +24,28 @@ function createRequireContextPlugin() {
|
|
|
22
24
|
code: /\brequire\b[\s\S]*\.context/
|
|
23
25
|
},
|
|
24
26
|
handler(code, id) {
|
|
25
|
-
|
|
26
|
-
let ast;
|
|
27
|
-
try {
|
|
28
|
-
ast = parseAst(code, { lang });
|
|
29
|
-
} catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const calls = collectRequireContextCalls(ast);
|
|
33
|
-
if (calls.length === 0) return null;
|
|
34
|
-
const output = new MagicString(code);
|
|
35
|
-
for (const call of calls) output.overwrite(call.range.start, call.range.end, buildReplacement(call));
|
|
36
|
-
return {
|
|
37
|
-
code: output.toString(),
|
|
38
|
-
map: output.generateMap({ hires: "boundary" })
|
|
39
|
-
};
|
|
27
|
+
return cached(id, code, void 0, () => transformRequireContext(code, id));
|
|
40
28
|
}
|
|
41
29
|
}
|
|
42
30
|
};
|
|
43
31
|
}
|
|
32
|
+
function transformRequireContext(code, id) {
|
|
33
|
+
const lang = langForId(id);
|
|
34
|
+
let ast;
|
|
35
|
+
try {
|
|
36
|
+
ast = parseAst(code, { lang });
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const calls = collectRequireContextCalls(ast);
|
|
41
|
+
if (calls.length === 0) return null;
|
|
42
|
+
const output = new MagicString(code);
|
|
43
|
+
for (const call of calls) output.overwrite(call.range.start, call.range.end, buildReplacement(call));
|
|
44
|
+
return {
|
|
45
|
+
code: output.toString(),
|
|
46
|
+
map: output.generateMap({ hires: "boundary" })
|
|
47
|
+
};
|
|
48
|
+
}
|
|
44
49
|
function langForId(id) {
|
|
45
50
|
const clean = id.split("?", 1)[0];
|
|
46
51
|
const dot = clean.lastIndexOf(".");
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/plugins/transform-cache.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Memoizes a pure per-module transform across the repeated build passes
|
|
4
|
+
* (scan client/server references + rsc/client/ssr builds), which feed the
|
|
5
|
+
* same module source through the same transform up to five times.
|
|
6
|
+
*
|
|
7
|
+
* Entries are keyed by module id and replaced when the source changes, so dev
|
|
8
|
+
* rebuilds retain at most one source version per id. `variant` distinguishes
|
|
9
|
+
* results that also depend on an environment-derived input (e.g. the
|
|
10
|
+
* typeof-window replacement); callers must pass a primitive or stable
|
|
11
|
+
* reference. Cached values include `null` ("no transform applies") so the
|
|
12
|
+
* negative case is not recomputed either.
|
|
13
|
+
*
|
|
14
|
+
* Only safe for transforms whose result depends solely on (id, source,
|
|
15
|
+
* variant) — no filesystem or plugin-state reads inside `compute`.
|
|
16
|
+
*/
|
|
17
|
+
declare function createTransformCache<V, R>(): (id: string, source: string, variant: V, compute: () => R) => R;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { createTransformCache };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/plugins/transform-cache.ts
|
|
2
|
+
/**
|
|
3
|
+
* Memoizes a pure per-module transform across the repeated build passes
|
|
4
|
+
* (scan client/server references + rsc/client/ssr builds), which feed the
|
|
5
|
+
* same module source through the same transform up to five times.
|
|
6
|
+
*
|
|
7
|
+
* Entries are keyed by module id and replaced when the source changes, so dev
|
|
8
|
+
* rebuilds retain at most one source version per id. `variant` distinguishes
|
|
9
|
+
* results that also depend on an environment-derived input (e.g. the
|
|
10
|
+
* typeof-window replacement); callers must pass a primitive or stable
|
|
11
|
+
* reference. Cached values include `null` ("no transform applies") so the
|
|
12
|
+
* negative case is not recomputed either.
|
|
13
|
+
*
|
|
14
|
+
* Only safe for transforms whose result depends solely on (id, source,
|
|
15
|
+
* variant) — no filesystem or plugin-state reads inside `compute`.
|
|
16
|
+
*/
|
|
17
|
+
function createTransformCache() {
|
|
18
|
+
const cache = /* @__PURE__ */ new Map();
|
|
19
|
+
return (id, source, variant, compute) => {
|
|
20
|
+
let entry = cache.get(id);
|
|
21
|
+
if (entry?.source !== source) {
|
|
22
|
+
entry = {
|
|
23
|
+
source,
|
|
24
|
+
results: /* @__PURE__ */ new Map()
|
|
25
|
+
};
|
|
26
|
+
cache.set(id, entry);
|
|
27
|
+
}
|
|
28
|
+
const boxed = entry.results.get(variant);
|
|
29
|
+
if (boxed) return boxed.value;
|
|
30
|
+
const value = compute();
|
|
31
|
+
entry.results.set(variant, { value });
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createTransformCache };
|
|
@@ -24,8 +24,13 @@ type InterceptingRoute = {
|
|
|
24
24
|
pagePath: string; /** Filesystem segments from app/ root to the intercepting page directory. */
|
|
25
25
|
sourcePageSegments?: string[]; /** Absolute layout paths inside the intercepting route tree, outermost to innermost */
|
|
26
26
|
layoutPaths: string[]; /** Normalized branch segments accumulated at each intercept layout. */
|
|
27
|
-
layoutSegments?: string[][]; /**
|
|
28
|
-
|
|
27
|
+
layoutSegments?: string[][]; /** Loading conventions inside the intercepted branch, outermost to innermost. */
|
|
28
|
+
loadingPaths?: string[]; /** Tree positions for loadingPaths in the normalized interception branch. */
|
|
29
|
+
loadingTreePositions?: number[]; /** Full normalized interception branch segments through the page. */
|
|
30
|
+
branchSegments?: string[]; /** Nearest not-found convention inside the interception branch. */
|
|
31
|
+
notFoundPath?: string | null; /** Slot-root-relative branch segments used to scope not-found params. */
|
|
32
|
+
notFoundBranchSegments?: string[]; /** Tree position relative to the normalized interception branch. */
|
|
33
|
+
notFoundTreePosition?: number | null; /** Parameter names for dynamic segments */
|
|
29
34
|
params: string[];
|
|
30
35
|
/**
|
|
31
36
|
* Synthetic page-carrier slot id for sibling (slot-less) interception.
|
|
@@ -38,15 +43,20 @@ type ParallelSlot = {
|
|
|
38
43
|
key: string; /** Slot name (e.g. "team" from @team) */
|
|
39
44
|
name: string; /** Absolute path to the @slot directory that owns this slot. Internal routing metadata. */
|
|
40
45
|
ownerDir: string; /** Stable tree path for the directory whose layout owns this slot. */
|
|
41
|
-
ownerTreePath: string; /**
|
|
46
|
+
ownerTreePath: string; /** Directory depth of the slot owner from app/ root. */
|
|
47
|
+
ownerTreePosition?: number; /** Whether the slot owner directory declares its own page component. */
|
|
42
48
|
hasPage: boolean; /** Absolute path to the slot's page component */
|
|
43
49
|
pagePath: string | null; /** Absolute path to the slot's default.tsx fallback */
|
|
44
50
|
defaultPath: string | null; /** Absolute path to the slot's layout component (wraps slot content) */
|
|
45
51
|
layoutPath: string | null; /** Nested active-branch layouts whose exports contribute route config. */
|
|
46
52
|
configLayoutPaths?: string[]; /** Tree positions of configLayoutPaths relative to the slot root. */
|
|
47
53
|
configLayoutTreePositions?: number[]; /** Absolute path to the slot's loading component */
|
|
48
|
-
loadingPath: string | null; /**
|
|
49
|
-
|
|
54
|
+
loadingPath: string | null; /** Per-segment loading components from the slot root to its active page. */
|
|
55
|
+
loadingPaths?: string[]; /** Slot-root-relative tree positions aligned with loadingPaths. */
|
|
56
|
+
loadingTreePositions?: number[]; /** Absolute path to the slot's error component */
|
|
57
|
+
errorPath: string | null; /** Nearest not-found convention for the slot's active branch. */
|
|
58
|
+
notFoundPath?: string | null; /** Tree position of that convention relative to the slot root. */
|
|
59
|
+
notFoundTreePosition?: number | null; /** Intercepting routes within this slot */
|
|
50
60
|
interceptingRoutes: InterceptingRoute[];
|
|
51
61
|
/**
|
|
52
62
|
* The layout index (0-based, in route.layouts[]) that this slot belongs to.
|
|
@@ -94,8 +104,10 @@ type AppRoute = {
|
|
|
94
104
|
* On soft-nav, the intercepting page replaces the entire page response.
|
|
95
105
|
* Empty array when there are no sibling-style interception markers.
|
|
96
106
|
*/
|
|
97
|
-
siblingIntercepts: InterceptingRoute[]; /** Loading component path */
|
|
98
|
-
loadingPath: string | null; /**
|
|
107
|
+
siblingIntercepts: InterceptingRoute[]; /** Loading component path (leaf directory only) */
|
|
108
|
+
loadingPath: string | null; /** Per-segment loading component paths, aligned with loadingTreePositions. */
|
|
109
|
+
loadingPaths?: string[]; /** Tree position (directory depth from app/ root) for each loading boundary. */
|
|
110
|
+
loadingTreePositions?: number[]; /** Error component path (leaf directory only) */
|
|
99
111
|
errorPath: string | null;
|
|
100
112
|
/**
|
|
101
113
|
* Per-layout error boundary paths, aligned with the layouts array.
|
|
@@ -105,7 +117,8 @@ type AppRoute = {
|
|
|
105
117
|
layoutErrorPaths: (string | null)[]; /** Per-segment error boundary paths, aligned with errorTreePositions. */
|
|
106
118
|
errorPaths?: string[]; /** Tree position (directory depth from app/ root) for each error boundary. */
|
|
107
119
|
errorTreePositions?: number[]; /** Not-found component path (nearest, walking up from page dir) */
|
|
108
|
-
notFoundPath: string | null;
|
|
120
|
+
notFoundPath: string | null; /** Tree position of the nearest not-found component's owning segment. */
|
|
121
|
+
notFoundTreePosition?: number | null;
|
|
109
122
|
/**
|
|
110
123
|
* Not-found component paths per layout level (aligned with layouts array).
|
|
111
124
|
* Each entry is the not-found.tsx at that layout's directory, or null.
|
|
@@ -119,8 +132,10 @@ type AppRoute = {
|
|
|
119
132
|
* Used to create per-layout ForbiddenBoundary.
|
|
120
133
|
*/
|
|
121
134
|
forbiddenPaths: (string | null)[]; /** Forbidden component path (403) at the route's directory level */
|
|
122
|
-
forbiddenPath: string | null; /**
|
|
123
|
-
|
|
135
|
+
forbiddenPath: string | null; /** Tree position of the nearest forbidden component's owning segment. */
|
|
136
|
+
forbiddenTreePosition?: number | null; /** Unauthorized component path (401) at the route's directory level */
|
|
137
|
+
unauthorizedPath: string | null; /** Tree position of the nearest unauthorized component's owning segment. */
|
|
138
|
+
unauthorizedTreePosition?: number | null; /** Unauthorized component paths per layout level (aligned with layouts array). */
|
|
124
139
|
unauthorizedPaths: (string | null)[];
|
|
125
140
|
/**
|
|
126
141
|
* Filesystem segments from app/ root to the route's directory.
|
|
@@ -298,6 +313,7 @@ declare function buildAppRouteGraph(appDir: string, matcher: ValidFileMatcher):
|
|
|
298
313
|
routeManifest: RouteManifest;
|
|
299
314
|
}>;
|
|
300
315
|
declare function computeRootParamNames(routeSegments: readonly string[], layoutTreePositions: readonly number[]): string[];
|
|
316
|
+
declare function patternsStructurallyEquivalent(a: readonly string[], b: readonly string[]): boolean;
|
|
301
317
|
/**
|
|
302
318
|
* Find the best route to attach a sibling intercept to, given the directory
|
|
303
319
|
* that contains the interception marker.
|
|
@@ -351,4 +367,4 @@ declare function computeAppRouteStaticSiblings(allRoutes: readonly {
|
|
|
351
367
|
patternParts?: readonly string[] | null;
|
|
352
368
|
}): string[];
|
|
353
369
|
//#endregion
|
|
354
|
-
export { AppRoute, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, RootBoundaryId, RouteManifest, RouteManifestInterception, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestSlotBinding, StaticSegmentGraph, buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, findOwnerRouteForDir, isInvisibleSegment };
|
|
370
|
+
export { AppRoute, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, RootBoundaryId, RouteManifest, RouteManifestInterception, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestSlotBinding, StaticSegmentGraph, buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, findOwnerRouteForDir, isInvisibleSegment, patternsStructurallyEquivalent };
|