@rangojs/router 0.0.0-experimental.259 → 0.0.0-experimental.26
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 +294 -28
- package/dist/bin/rango.js +355 -47
- package/dist/vite/index.js +1658 -1239
- package/package.json +3 -3
- package/skills/cache-guide/SKILL.md +9 -5
- package/skills/caching/SKILL.md +4 -4
- package/skills/document-cache/SKILL.md +2 -2
- package/skills/hooks/SKILL.md +40 -29
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +79 -0
- package/skills/layout/SKILL.md +62 -2
- package/skills/loader/SKILL.md +229 -15
- package/skills/middleware/SKILL.md +109 -30
- package/skills/parallel/SKILL.md +57 -2
- package/skills/prerender/SKILL.md +189 -19
- package/skills/rango/SKILL.md +1 -2
- package/skills/response-routes/SKILL.md +3 -3
- package/skills/route/SKILL.md +44 -3
- package/skills/router-setup/SKILL.md +80 -3
- package/skills/theme/SKILL.md +5 -4
- package/skills/typesafety/SKILL.md +59 -16
- package/skills/use-cache/SKILL.md +16 -2
- package/src/__internal.ts +1 -1
- package/src/bin/rango.ts +56 -19
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/event-controller.ts +29 -48
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +1 -1
- package/src/browser/link-interceptor.ts +19 -3
- package/src/browser/merge-segment-loaders.ts +9 -2
- package/src/browser/navigation-bridge.ts +66 -443
- package/src/browser/navigation-client.ts +34 -62
- package/src/browser/navigation-store.ts +4 -33
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/partial-update.ts +103 -151
- package/src/browser/prefetch/cache.ts +67 -0
- package/src/browser/prefetch/fetch.ts +137 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +154 -44
- package/src/browser/react/NavigationProvider.tsx +32 -0
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +2 -6
- package/src/browser/react/location-state-shared.ts +29 -11
- package/src/browser/react/location-state.ts +6 -4
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +23 -45
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +21 -64
- package/src/browser/react/use-navigation.ts +7 -32
- package/src/browser/react/use-params.ts +5 -34
- package/src/browser/react/use-pathname.ts +2 -3
- package/src/browser/react/use-router.ts +3 -6
- package/src/browser/react/use-search-params.ts +2 -1
- package/src/browser/react/use-segments.ts +75 -114
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +46 -22
- package/src/browser/scroll-restoration.ts +10 -7
- package/src/browser/server-action-bridge.ts +458 -405
- package/src/browser/types.ts +21 -35
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +38 -13
- package/src/build/generate-route-types.ts +4 -0
- package/src/build/index.ts +1 -0
- package/src/build/route-trie.ts +19 -3
- package/src/build/route-types/codegen.ts +13 -4
- package/src/build/route-types/include-resolution.ts +13 -0
- package/src/build/route-types/per-module-writer.ts +15 -3
- package/src/build/route-types/router-processing.ts +170 -18
- package/src/build/runtime-discovery.ts +13 -1
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +136 -123
- package/src/cache/cache-scope.ts +76 -83
- package/src/cache/cf/cf-cache-store.ts +12 -7
- package/src/cache/document-cache.ts +93 -69
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/index.ts +0 -15
- package/src/cache/memory-segment-store.ts +43 -69
- package/src/cache/profile-registry.ts +43 -8
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +140 -117
- package/src/cache/taint.ts +30 -3
- package/src/cache/types.ts +1 -115
- package/src/client.rsc.tsx +0 -1
- package/src/client.tsx +53 -76
- package/src/errors.ts +6 -1
- package/src/handle.ts +1 -1
- package/src/handles/MetaTags.tsx +5 -2
- package/src/host/cookie-handler.ts +8 -3
- package/src/host/index.ts +0 -3
- package/src/host/router.ts +14 -1
- package/src/href-client.ts +3 -1
- package/src/index.rsc.ts +53 -10
- package/src/index.ts +73 -43
- package/src/loader.rsc.ts +12 -4
- package/src/loader.ts +8 -0
- package/src/prerender/store.ts +60 -18
- package/src/prerender.ts +76 -18
- package/src/reverse.ts +11 -7
- package/src/root-error-boundary.tsx +30 -26
- package/src/route-definition/dsl-helpers.ts +9 -6
- package/src/route-definition/index.ts +0 -3
- package/src/route-definition/redirect.ts +15 -3
- package/src/route-map-builder.ts +38 -2
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +7 -0
- package/src/router/content-negotiation.ts +1 -1
- package/src/router/debug-manifest.ts +16 -3
- package/src/router/handler-context.ts +96 -17
- package/src/router/intercept-resolution.ts +6 -4
- package/src/router/lazy-includes.ts +4 -0
- package/src/router/loader-resolution.ts +6 -11
- package/src/router/logging.ts +100 -3
- package/src/router/manifest.ts +32 -3
- package/src/router/match-api.ts +62 -54
- package/src/router/match-context.ts +3 -0
- package/src/router/match-handlers.ts +185 -11
- package/src/router/match-middleware/background-revalidation.ts +65 -85
- package/src/router/match-middleware/cache-lookup.ts +78 -10
- package/src/router/match-middleware/cache-store.ts +2 -0
- package/src/router/match-pipelines.ts +8 -43
- package/src/router/match-result.ts +0 -9
- package/src/router/metrics.ts +233 -13
- package/src/router/middleware-types.ts +34 -39
- package/src/router/middleware.ts +290 -130
- package/src/router/pattern-matching.ts +61 -10
- package/src/router/prerender-match.ts +36 -6
- package/src/router/preview-match.ts +7 -1
- package/src/router/revalidation.ts +61 -2
- package/src/router/router-context.ts +15 -0
- package/src/router/router-interfaces.ts +158 -40
- package/src/router/router-options.ts +223 -1
- package/src/router/router-registry.ts +5 -2
- package/src/router/segment-resolution/fresh.ts +165 -242
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +102 -98
- package/src/router/segment-resolution/revalidation.ts +394 -272
- package/src/router/segment-resolution/static-store.ts +2 -2
- package/src/router/segment-resolution.ts +1 -3
- package/src/router/segment-wrappers.ts +3 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +20 -2
- package/src/router/types.ts +7 -1
- package/src/router.ts +203 -18
- package/src/rsc/handler-context.ts +13 -2
- package/src/rsc/handler.ts +489 -438
- package/src/rsc/helpers.ts +125 -5
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +84 -42
- package/src/rsc/manifest-init.ts +3 -2
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +245 -19
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +47 -43
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +166 -66
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +20 -2
- package/src/search-params.ts +38 -23
- package/src/server/context.ts +61 -7
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +84 -12
- package/src/server/loader-registry.ts +11 -46
- package/src/server/request-context.ts +275 -49
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +67 -28
- package/src/static-handler.ts +7 -0
- package/src/theme/ThemeProvider.tsx +6 -1
- package/src/theme/index.ts +4 -18
- package/src/theme/theme-context.ts +1 -28
- package/src/theme/theme-script.ts +2 -1
- package/src/types/cache-types.ts +6 -1
- package/src/types/error-types.ts +3 -0
- package/src/types/global-namespace.ts +22 -0
- package/src/types/handler-context.ts +103 -16
- package/src/types/index.ts +1 -1
- package/src/types/loader-types.ts +9 -6
- package/src/types/route-config.ts +17 -26
- package/src/types/route-entry.ts +28 -0
- package/src/types/segments.ts +0 -5
- package/src/urls/include-helper.ts +49 -8
- package/src/urls/index.ts +1 -0
- package/src/urls/path-helper-types.ts +30 -12
- package/src/urls/path-helper.ts +17 -2
- package/src/urls/pattern-types.ts +21 -1
- package/src/urls/response-types.ts +29 -7
- package/src/urls/type-extraction.ts +23 -15
- package/src/use-loader.tsx +27 -9
- package/src/vite/discovery/bundle-postprocess.ts +32 -52
- package/src/vite/discovery/discover-routers.ts +52 -26
- package/src/vite/discovery/prerender-collection.ts +58 -41
- package/src/vite/discovery/route-types-writer.ts +7 -7
- package/src/vite/discovery/state.ts +7 -7
- package/src/vite/discovery/virtual-module-codegen.ts +5 -2
- package/src/vite/index.ts +10 -51
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +3 -3
- package/src/vite/plugins/expose-internal-ids.ts +4 -3
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +91 -3
- package/src/vite/plugins/version-plugin.ts +188 -18
- package/src/vite/rango.ts +61 -36
- package/src/vite/router-discovery.ts +173 -100
- package/src/vite/utils/prerender-utils.ts +81 -0
- package/src/vite/utils/shared-utils.ts +19 -9
- package/skills/testing/SKILL.md +0 -226
- package/src/browser/lru-cache.ts +0 -61
- package/src/browser/react/prefetch.ts +0 -27
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/route-definition/route-function.ts +0 -119
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- /package/{CLAUDE.md → AGENTS.md} +0 -0
package/dist/vite/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// src/vite/rango.ts
|
|
2
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
3
|
+
import { resolve as resolve9 } from "node:path";
|
|
4
|
+
|
|
1
5
|
// src/vite/plugins/expose-action-id.ts
|
|
2
6
|
import MagicString from "magic-string";
|
|
3
7
|
import path2 from "node:path";
|
|
@@ -353,10 +357,10 @@ import path4 from "node:path";
|
|
|
353
357
|
function isDirectivePrologueStatement(node) {
|
|
354
358
|
return node?.type === "ExpressionStatement" && typeof node.directive === "string";
|
|
355
359
|
}
|
|
356
|
-
function findImportInsertionPos(code,
|
|
360
|
+
function findImportInsertionPos(code, parseAst4) {
|
|
357
361
|
let program;
|
|
358
362
|
try {
|
|
359
|
-
program =
|
|
363
|
+
program = parseAst4(code, { jsx: true });
|
|
360
364
|
} catch {
|
|
361
365
|
return 0;
|
|
362
366
|
}
|
|
@@ -393,10 +397,10 @@ function walkNode(node, parent, ancestors, enter) {
|
|
|
393
397
|
}
|
|
394
398
|
ancestors.pop();
|
|
395
399
|
}
|
|
396
|
-
function findHandlerCalls(code, fnName,
|
|
400
|
+
function findHandlerCalls(code, fnName, parseAst4) {
|
|
397
401
|
let program;
|
|
398
402
|
try {
|
|
399
|
-
program =
|
|
403
|
+
program = parseAst4(code, { jsx: true });
|
|
400
404
|
} catch {
|
|
401
405
|
return [];
|
|
402
406
|
}
|
|
@@ -468,18 +472,18 @@ function getImportedLocalNamesFromProgram(program, importedName) {
|
|
|
468
472
|
}
|
|
469
473
|
return localNames;
|
|
470
474
|
}
|
|
471
|
-
function getImportedLocalNames(code, importedName,
|
|
475
|
+
function getImportedLocalNames(code, importedName, parseAst4) {
|
|
472
476
|
try {
|
|
473
|
-
const program =
|
|
477
|
+
const program = parseAst4(code, { jsx: true });
|
|
474
478
|
return getImportedLocalNamesFromProgram(program, importedName);
|
|
475
479
|
} catch {
|
|
476
480
|
return /* @__PURE__ */ new Set();
|
|
477
481
|
}
|
|
478
482
|
}
|
|
479
|
-
function extractImportDeclarations(code,
|
|
483
|
+
function extractImportDeclarations(code, parseAst4) {
|
|
480
484
|
let program;
|
|
481
485
|
try {
|
|
482
|
-
program =
|
|
486
|
+
program = parseAst4(code, { jsx: true });
|
|
483
487
|
} catch {
|
|
484
488
|
return [];
|
|
485
489
|
}
|
|
@@ -531,10 +535,10 @@ function isSafeVariableDeclaration(node, handlerNames) {
|
|
|
531
535
|
(d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
|
|
532
536
|
);
|
|
533
537
|
}
|
|
534
|
-
function extractModuleLevelDeclarations(code,
|
|
538
|
+
function extractModuleLevelDeclarations(code, parseAst4, handlerNames) {
|
|
535
539
|
let program;
|
|
536
540
|
try {
|
|
537
|
-
program =
|
|
541
|
+
program = parseAst4(code, { jsx: true });
|
|
538
542
|
} catch {
|
|
539
543
|
return [];
|
|
540
544
|
}
|
|
@@ -565,17 +569,17 @@ function extractModuleLevelDeclarations(code, parseAst3, handlerNames) {
|
|
|
565
569
|
}
|
|
566
570
|
return declarations;
|
|
567
571
|
}
|
|
568
|
-
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId,
|
|
569
|
-
const sites = findHandlerCalls(code, fnName,
|
|
572
|
+
function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst4) {
|
|
573
|
+
const sites = findHandlerCalls(code, fnName, parseAst4);
|
|
570
574
|
const inlineSites = sites.filter((site) => site.exportInfo === null);
|
|
571
575
|
if (inlineSites.length === 0) return false;
|
|
572
|
-
const imports = extractImportDeclarations(code,
|
|
573
|
-
const staticNames = getImportedLocalNames(code, "Static",
|
|
574
|
-
const prerenderNames = getImportedLocalNames(code, "Prerender",
|
|
576
|
+
const imports = extractImportDeclarations(code, parseAst4);
|
|
577
|
+
const staticNames = getImportedLocalNames(code, "Static", parseAst4);
|
|
578
|
+
const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst4);
|
|
575
579
|
const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
|
|
576
580
|
const declarations = extractModuleLevelDeclarations(
|
|
577
581
|
code,
|
|
578
|
-
|
|
582
|
+
parseAst4,
|
|
579
583
|
handlerNames
|
|
580
584
|
);
|
|
581
585
|
const lineCounts = /* @__PURE__ */ new Map();
|
|
@@ -600,7 +604,7 @@ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtu
|
|
|
600
604
|
}
|
|
601
605
|
if (importStatements.length > 0) {
|
|
602
606
|
const importBlock = importStatements.join("\n") + "\n";
|
|
603
|
-
const insertionPos = findImportInsertionPos(code,
|
|
607
|
+
const insertionPos = findImportInsertionPos(code, parseAst4);
|
|
604
608
|
if (insertionPos === 0) {
|
|
605
609
|
s.prepend(importBlock);
|
|
606
610
|
} else {
|
|
@@ -1101,6 +1105,7 @@ ${lazyImports.join(",\n")}
|
|
|
1101
1105
|
async buildStart() {
|
|
1102
1106
|
if (!isBuild) return;
|
|
1103
1107
|
const fs2 = await import("node:fs/promises");
|
|
1108
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage"]);
|
|
1104
1109
|
async function scanDir(dir) {
|
|
1105
1110
|
const results = [];
|
|
1106
1111
|
try {
|
|
@@ -1108,7 +1113,7 @@ ${lazyImports.join(",\n")}
|
|
|
1108
1113
|
for (const entry of entries) {
|
|
1109
1114
|
const fullPath = path4.join(dir, entry.name);
|
|
1110
1115
|
if (entry.isDirectory()) {
|
|
1111
|
-
if (entry.name
|
|
1116
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
1112
1117
|
results.push(...await scanDir(fullPath));
|
|
1113
1118
|
}
|
|
1114
1119
|
} else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) {
|
|
@@ -1120,8 +1125,7 @@ ${lazyImports.join(",\n")}
|
|
|
1120
1125
|
return results;
|
|
1121
1126
|
}
|
|
1122
1127
|
try {
|
|
1123
|
-
const
|
|
1124
|
-
const files = await scanDir(srcDir);
|
|
1128
|
+
const files = await scanDir(projectRoot);
|
|
1125
1129
|
for (const filePath of files) {
|
|
1126
1130
|
const content = await fs2.readFile(filePath, "utf-8");
|
|
1127
1131
|
if (!content.includes("createLoader")) continue;
|
|
@@ -1397,6 +1401,237 @@ ${lazyImports.join(",\n")}
|
|
|
1397
1401
|
};
|
|
1398
1402
|
}
|
|
1399
1403
|
|
|
1404
|
+
// src/vite/plugins/use-cache-transform.ts
|
|
1405
|
+
import path5 from "node:path";
|
|
1406
|
+
import MagicString5 from "magic-string";
|
|
1407
|
+
var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
|
|
1408
|
+
var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
|
|
1409
|
+
function useCacheTransform() {
|
|
1410
|
+
let projectRoot = "";
|
|
1411
|
+
let isBuild = false;
|
|
1412
|
+
let rscTransforms = null;
|
|
1413
|
+
return {
|
|
1414
|
+
name: "@rangojs/router:use-cache",
|
|
1415
|
+
enforce: "post",
|
|
1416
|
+
configResolved(config) {
|
|
1417
|
+
projectRoot = config.root;
|
|
1418
|
+
isBuild = config.command === "build";
|
|
1419
|
+
},
|
|
1420
|
+
async transform(code, id) {
|
|
1421
|
+
if (this.environment?.name !== "rsc") return;
|
|
1422
|
+
if (!code.includes("use cache")) return;
|
|
1423
|
+
if (id.includes("/node_modules/") || id.startsWith("\0")) return;
|
|
1424
|
+
if (!/\.(tsx?|jsx?|mjs)$/.test(id)) return;
|
|
1425
|
+
if (!rscTransforms) {
|
|
1426
|
+
try {
|
|
1427
|
+
rscTransforms = await import("@vitejs/plugin-rsc/transforms");
|
|
1428
|
+
} catch {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
const {
|
|
1433
|
+
hasDirective,
|
|
1434
|
+
transformWrapExport,
|
|
1435
|
+
transformHoistInlineDirective
|
|
1436
|
+
} = rscTransforms;
|
|
1437
|
+
let ast;
|
|
1438
|
+
try {
|
|
1439
|
+
const { parseAst: parseAst4 } = await import("vite");
|
|
1440
|
+
ast = parseAst4(code);
|
|
1441
|
+
} catch {
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const filePath = normalizePath(path5.relative(projectRoot, id));
|
|
1445
|
+
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
1446
|
+
if (hasDirective(ast.body, "use cache")) {
|
|
1447
|
+
return transformFileLevelUseCache(
|
|
1448
|
+
code,
|
|
1449
|
+
ast,
|
|
1450
|
+
filePath,
|
|
1451
|
+
id,
|
|
1452
|
+
isBuild,
|
|
1453
|
+
isLayoutOrTemplate,
|
|
1454
|
+
transformWrapExport
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
const functionResult = transformFunctionLevelUseCache(
|
|
1458
|
+
code,
|
|
1459
|
+
ast,
|
|
1460
|
+
filePath,
|
|
1461
|
+
id,
|
|
1462
|
+
isBuild,
|
|
1463
|
+
transformHoistInlineDirective
|
|
1464
|
+
);
|
|
1465
|
+
warnOnNearMissDirectives(ast, id, this.warn.bind(this));
|
|
1466
|
+
if (functionResult) return functionResult;
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
|
|
1471
|
+
const nonFunctionExports = [];
|
|
1472
|
+
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
1473
|
+
runtime: (value, name) => {
|
|
1474
|
+
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
1475
|
+
return `__rango_registerCachedFunction(${value}, ${JSON.stringify(funcId)}, "default")`;
|
|
1476
|
+
},
|
|
1477
|
+
rejectNonAsyncFunction: false,
|
|
1478
|
+
filter: (name, meta) => {
|
|
1479
|
+
if (name === "default" && isLayoutOrTemplate) return false;
|
|
1480
|
+
if (meta.isFunction === false) {
|
|
1481
|
+
nonFunctionExports.push(name);
|
|
1482
|
+
return false;
|
|
1483
|
+
}
|
|
1484
|
+
return true;
|
|
1485
|
+
}
|
|
1486
|
+
});
|
|
1487
|
+
if (nonFunctionExports.length > 0) {
|
|
1488
|
+
throw new Error(
|
|
1489
|
+
`[rango:use-cache] File-level "use cache" in ${sourceId} cannot wrap non-function export${nonFunctionExports.length > 1 ? "s" : ""}: ${nonFunctionExports.map((n) => `"${n}"`).join(", ")}. Only function exports can be cached. Either remove "use cache" from the file level and add it inside individual functions, or move the non-function exports to a separate module.`
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
if (exportNames.length === 0) {
|
|
1493
|
+
const s = new MagicString5(code);
|
|
1494
|
+
const directive2 = findFileLevelDirective(ast);
|
|
1495
|
+
if (directive2) {
|
|
1496
|
+
s.overwrite(
|
|
1497
|
+
directive2.start,
|
|
1498
|
+
directive2.end,
|
|
1499
|
+
`/* "use cache" -- wrapped by rango */`
|
|
1500
|
+
);
|
|
1501
|
+
return {
|
|
1502
|
+
code: s.toString(),
|
|
1503
|
+
map: s.generateMap({ source: sourceId, hires: "boundary" })
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
output.prepend(
|
|
1509
|
+
`import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};
|
|
1510
|
+
`
|
|
1511
|
+
);
|
|
1512
|
+
const directive = findFileLevelDirective(ast);
|
|
1513
|
+
if (directive) {
|
|
1514
|
+
output.overwrite(
|
|
1515
|
+
directive.start,
|
|
1516
|
+
directive.end,
|
|
1517
|
+
`/* "use cache" -- wrapped by rango */`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
return {
|
|
1521
|
+
code: output.toString(),
|
|
1522
|
+
map: output.generateMap({ source: sourceId, hires: "boundary" })
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild, transformHoistInlineDirective) {
|
|
1526
|
+
try {
|
|
1527
|
+
const { output, names } = transformHoistInlineDirective(code, ast, {
|
|
1528
|
+
directive: /^use cache(:\s*[\w-]+)?$/,
|
|
1529
|
+
runtime: (value, name, meta) => {
|
|
1530
|
+
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
1531
|
+
const profileMatch = meta.directiveMatch[1];
|
|
1532
|
+
const profileName = profileMatch ? profileMatch.replace(/^:\s*/, "").trim() : "default";
|
|
1533
|
+
return `__rango_registerCachedFunction(${value}, ${JSON.stringify(funcId)}, ${JSON.stringify(profileName)})`;
|
|
1534
|
+
},
|
|
1535
|
+
rejectNonAsyncFunction: false
|
|
1536
|
+
});
|
|
1537
|
+
if (names.length === 0) return;
|
|
1538
|
+
output.prepend(
|
|
1539
|
+
`import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};
|
|
1540
|
+
`
|
|
1541
|
+
);
|
|
1542
|
+
return {
|
|
1543
|
+
code: output.toString(),
|
|
1544
|
+
map: output.generateMap({ source: sourceId, hires: "boundary" })
|
|
1545
|
+
};
|
|
1546
|
+
} catch {
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function findFileLevelDirective(ast) {
|
|
1551
|
+
for (const node of ast.body ?? []) {
|
|
1552
|
+
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string" && node.expression.value.startsWith("use cache")) {
|
|
1553
|
+
return { start: node.start, end: node.end };
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
var VALID_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
|
|
1559
|
+
var NEAR_MISS_RE = /^use cache:\s*.+$/;
|
|
1560
|
+
function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
1561
|
+
const visit = (node) => {
|
|
1562
|
+
if (!node || typeof node !== "object") return;
|
|
1563
|
+
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
1564
|
+
const value = node.expression.value;
|
|
1565
|
+
if (value.startsWith("use cache") && NEAR_MISS_RE.test(value) && !VALID_DIRECTIVE_RE.test(value)) {
|
|
1566
|
+
const profilePart = value.slice("use cache:".length).trim();
|
|
1567
|
+
warn(
|
|
1568
|
+
`[rango:use-cache] "${value}" in ${fileId} has an invalid profile name "${profilePart}". Profile names must match [a-zA-Z0-9_-]+. This directive will be ignored.`
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
for (const key of Object.keys(node)) {
|
|
1573
|
+
const child = node[key];
|
|
1574
|
+
if (Array.isArray(child)) {
|
|
1575
|
+
for (const item of child) {
|
|
1576
|
+
visit(item);
|
|
1577
|
+
}
|
|
1578
|
+
} else if (child && typeof child === "object" && child.type) {
|
|
1579
|
+
visit(child);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
for (const node of ast.body ?? []) {
|
|
1584
|
+
visit(node);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/vite/plugins/client-ref-dedup.ts
|
|
1589
|
+
var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
|
|
1590
|
+
function extractPackageName(absolutePath) {
|
|
1591
|
+
const marker = "/node_modules/";
|
|
1592
|
+
const idx = absolutePath.lastIndexOf(marker);
|
|
1593
|
+
if (idx === -1) return null;
|
|
1594
|
+
const afterModules = absolutePath.slice(idx + marker.length);
|
|
1595
|
+
if (afterModules.startsWith("@")) {
|
|
1596
|
+
const parts = afterModules.split("/");
|
|
1597
|
+
if (parts.length < 2 || !parts[1]) return null;
|
|
1598
|
+
return `${parts[0]}/${parts[1]}`;
|
|
1599
|
+
}
|
|
1600
|
+
const name = afterModules.split("/")[0];
|
|
1601
|
+
return name || null;
|
|
1602
|
+
}
|
|
1603
|
+
function clientRefDedup() {
|
|
1604
|
+
let clientExclude = [];
|
|
1605
|
+
return {
|
|
1606
|
+
name: "@rangojs/router:client-ref-dedup",
|
|
1607
|
+
enforce: "pre",
|
|
1608
|
+
apply: "serve",
|
|
1609
|
+
configResolved(config) {
|
|
1610
|
+
const clientEnv = config.environments?.["client"];
|
|
1611
|
+
clientExclude = clientEnv?.optimizeDeps?.exclude ?? config.optimizeDeps?.exclude ?? [];
|
|
1612
|
+
},
|
|
1613
|
+
resolveId(source, importer, options) {
|
|
1614
|
+
if (this.environment?.name !== "client") return;
|
|
1615
|
+
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
1616
|
+
if (!source.includes("/node_modules/")) return;
|
|
1617
|
+
if (!importer) return;
|
|
1618
|
+
const packageName = extractPackageName(source);
|
|
1619
|
+
if (!packageName) return;
|
|
1620
|
+
if (clientExclude.includes(packageName)) return;
|
|
1621
|
+
return `\0rango:dedup/${packageName}`;
|
|
1622
|
+
},
|
|
1623
|
+
load(id) {
|
|
1624
|
+
if (!id.startsWith("\0rango:dedup/")) return;
|
|
1625
|
+
const packageName = id.slice("\0rango:dedup/".length);
|
|
1626
|
+
return [
|
|
1627
|
+
`export * from ${JSON.stringify(packageName)};`,
|
|
1628
|
+
`import * as __all__ from ${JSON.stringify(packageName)};`,
|
|
1629
|
+
`export default __all__.default;`
|
|
1630
|
+
].join("\n");
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1400
1635
|
// src/vite/plugins/virtual-entries.ts
|
|
1401
1636
|
var VIRTUAL_ENTRY_BROWSER = `
|
|
1402
1637
|
import {
|
|
@@ -1503,309 +1738,66 @@ function getVirtualVersionContent(version) {
|
|
|
1503
1738
|
return `export const VERSION = ${JSON.stringify(version)};`;
|
|
1504
1739
|
}
|
|
1505
1740
|
|
|
1506
|
-
// src/vite/
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1741
|
+
// src/vite/utils/package-resolution.ts
|
|
1742
|
+
import { existsSync } from "node:fs";
|
|
1743
|
+
import { resolve } from "node:path";
|
|
1744
|
+
|
|
1745
|
+
// package.json
|
|
1746
|
+
var package_default = {
|
|
1747
|
+
name: "@rangojs/router",
|
|
1748
|
+
version: "0.0.0-experimental.26",
|
|
1749
|
+
description: "Django-inspired RSC router with composable URL patterns",
|
|
1750
|
+
keywords: [
|
|
1751
|
+
"react",
|
|
1752
|
+
"react-server-components",
|
|
1753
|
+
"router",
|
|
1754
|
+
"rsc",
|
|
1755
|
+
"vite"
|
|
1756
|
+
],
|
|
1757
|
+
homepage: "https://github.com/ivogt/vite-rsc#readme",
|
|
1758
|
+
bugs: {
|
|
1759
|
+
url: "https://github.com/ivogt/vite-rsc/issues"
|
|
1760
|
+
},
|
|
1761
|
+
license: "MIT",
|
|
1762
|
+
author: "Ivo Todorov",
|
|
1763
|
+
repository: {
|
|
1764
|
+
type: "git",
|
|
1765
|
+
url: "git+https://github.com/ivogt/vite-rsc.git",
|
|
1766
|
+
directory: "packages/rangojs-router"
|
|
1767
|
+
},
|
|
1768
|
+
bin: {
|
|
1769
|
+
rango: "./dist/bin/rango.js"
|
|
1770
|
+
},
|
|
1771
|
+
files: [
|
|
1772
|
+
"src",
|
|
1773
|
+
"!src/**/__tests__",
|
|
1774
|
+
"!src/**/__mocks__",
|
|
1775
|
+
"!src/**/*.test.ts",
|
|
1776
|
+
"!src/**/*.test.tsx",
|
|
1777
|
+
"dist",
|
|
1778
|
+
"skills",
|
|
1779
|
+
"AGENTS.md",
|
|
1780
|
+
"README.md"
|
|
1781
|
+
],
|
|
1782
|
+
type: "module",
|
|
1783
|
+
exports: {
|
|
1784
|
+
".": {
|
|
1785
|
+
types: "./src/index.rsc.ts",
|
|
1786
|
+
"react-server": "./src/index.rsc.ts",
|
|
1787
|
+
default: "./src/index.ts"
|
|
1517
1788
|
},
|
|
1518
|
-
|
|
1519
|
-
server
|
|
1789
|
+
"./server": {
|
|
1790
|
+
types: "./src/server.ts",
|
|
1791
|
+
import: "./src/server.ts"
|
|
1520
1792
|
},
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
return null;
|
|
1793
|
+
"./client": {
|
|
1794
|
+
types: "./src/client.tsx",
|
|
1795
|
+
"react-server": "./src/client.rsc.tsx",
|
|
1796
|
+
default: "./src/client.tsx"
|
|
1526
1797
|
},
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
}
|
|
1531
|
-
return null;
|
|
1532
|
-
},
|
|
1533
|
-
// Track RSC module changes and update version
|
|
1534
|
-
hotUpdate(ctx) {
|
|
1535
|
-
if (!isDev) return;
|
|
1536
|
-
const isRscModule = this.environment?.name === "rsc";
|
|
1537
|
-
if (isRscModule && ctx.modules.length > 0) {
|
|
1538
|
-
currentVersion = Date.now().toString(16);
|
|
1539
|
-
console.log(
|
|
1540
|
-
`[rsc-router] RSC module changed, version updated: ${currentVersion}`
|
|
1541
|
-
);
|
|
1542
|
-
if (server) {
|
|
1543
|
-
const rscEnv = server.environments?.rsc;
|
|
1544
|
-
if (rscEnv?.moduleGraph) {
|
|
1545
|
-
const versionMod = rscEnv.moduleGraph.getModuleById(
|
|
1546
|
-
"\0" + VIRTUAL_IDS.version
|
|
1547
|
-
);
|
|
1548
|
-
if (versionMod) {
|
|
1549
|
-
rscEnv.moduleGraph.invalidateModule(versionMod);
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
// src/vite/plugins/virtual-stub-plugin.ts
|
|
1559
|
-
function createVirtualStubPlugin() {
|
|
1560
|
-
const STUB_PREFIXES = [
|
|
1561
|
-
"virtual:rsc-router/",
|
|
1562
|
-
"virtual:entry-",
|
|
1563
|
-
"virtual:vite-rsc/"
|
|
1564
|
-
];
|
|
1565
|
-
return {
|
|
1566
|
-
name: "@rangojs/router:virtual-stubs",
|
|
1567
|
-
resolveId(id) {
|
|
1568
|
-
if (STUB_PREFIXES.some((p) => id.startsWith(p))) {
|
|
1569
|
-
return "\0stub:" + id;
|
|
1570
|
-
}
|
|
1571
|
-
return null;
|
|
1572
|
-
},
|
|
1573
|
-
load(id) {
|
|
1574
|
-
if (id.startsWith("\0stub:")) {
|
|
1575
|
-
return "export default {}";
|
|
1576
|
-
}
|
|
1577
|
-
return null;
|
|
1578
|
-
}
|
|
1579
|
-
};
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// src/vite/plugins/client-ref-hashing.ts
|
|
1583
|
-
import { relative, posix } from "node:path";
|
|
1584
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
1585
|
-
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
1586
|
-
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
1587
|
-
var FS_PREFIX = "/@fs/";
|
|
1588
|
-
function computeProductionHash(projectRoot, refKey) {
|
|
1589
|
-
let toHash;
|
|
1590
|
-
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
1591
|
-
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
1592
|
-
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
1593
|
-
const absPath = decodeURIComponent(
|
|
1594
|
-
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
1595
|
-
);
|
|
1596
|
-
toHash = posix.normalize(relative(projectRoot, absPath));
|
|
1597
|
-
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
1598
|
-
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
1599
|
-
toHash = posix.normalize(relative(projectRoot, absPath));
|
|
1600
|
-
} else if (refKey.startsWith("/")) {
|
|
1601
|
-
toHash = refKey.slice(1);
|
|
1602
|
-
} else {
|
|
1603
|
-
return refKey;
|
|
1604
|
-
}
|
|
1605
|
-
return createHash2("sha256").update(toHash).digest("hex").slice(0, 12);
|
|
1606
|
-
}
|
|
1607
|
-
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
1608
|
-
function transformClientRefs(code, projectRoot) {
|
|
1609
|
-
if (!code.includes("registerClientReference")) return null;
|
|
1610
|
-
let hasReplacement = false;
|
|
1611
|
-
const result = code.replace(
|
|
1612
|
-
REGISTER_CLIENT_REF_RE,
|
|
1613
|
-
(match, refKey) => {
|
|
1614
|
-
const hash = computeProductionHash(projectRoot, refKey);
|
|
1615
|
-
if (hash === refKey) return match;
|
|
1616
|
-
hasReplacement = true;
|
|
1617
|
-
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
1618
|
-
}
|
|
1619
|
-
);
|
|
1620
|
-
return hasReplacement ? result : null;
|
|
1621
|
-
}
|
|
1622
|
-
function hashClientRefs(projectRoot) {
|
|
1623
|
-
return {
|
|
1624
|
-
name: "@rangojs/router:hash-client-refs",
|
|
1625
|
-
// Run after the RSC plugin's transform (default enforce is normal)
|
|
1626
|
-
enforce: "post",
|
|
1627
|
-
applyToEnvironment(env) {
|
|
1628
|
-
return env.name === "rsc";
|
|
1629
|
-
},
|
|
1630
|
-
transform(code, _id) {
|
|
1631
|
-
const result = transformClientRefs(code, projectRoot);
|
|
1632
|
-
if (result === null) return;
|
|
1633
|
-
return { code: result, map: null };
|
|
1634
|
-
}
|
|
1635
|
-
};
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
// src/vite/plugins/version-injector.ts
|
|
1639
|
-
import { resolve } from "node:path";
|
|
1640
|
-
import * as Vite from "vite";
|
|
1641
|
-
function createVersionInjectorPlugin(rscEntryPath) {
|
|
1642
|
-
let resolvedEntryPath = "";
|
|
1643
|
-
return {
|
|
1644
|
-
name: "@rangojs/router:version-injector",
|
|
1645
|
-
enforce: "pre",
|
|
1646
|
-
configResolved(config) {
|
|
1647
|
-
let entryPath = rscEntryPath;
|
|
1648
|
-
if (!entryPath) {
|
|
1649
|
-
const rscEnvConfig = config.environments?.["rsc"];
|
|
1650
|
-
const entries = rscEnvConfig?.optimizeDeps?.entries;
|
|
1651
|
-
if (typeof entries === "string") {
|
|
1652
|
-
entryPath = entries;
|
|
1653
|
-
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
1654
|
-
entryPath = entries[0];
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
if (entryPath) {
|
|
1658
|
-
resolvedEntryPath = resolve(config.root, entryPath);
|
|
1659
|
-
}
|
|
1660
|
-
},
|
|
1661
|
-
transform(code, id) {
|
|
1662
|
-
if (!resolvedEntryPath) return null;
|
|
1663
|
-
const normalizedId = Vite.normalizePath(id);
|
|
1664
|
-
const normalizedEntry = Vite.normalizePath(resolvedEntryPath);
|
|
1665
|
-
if (normalizedId !== normalizedEntry) {
|
|
1666
|
-
return null;
|
|
1667
|
-
}
|
|
1668
|
-
const prepend = [];
|
|
1669
|
-
let newCode = code;
|
|
1670
|
-
if (!code.includes("virtual:rsc-router/routes-manifest")) {
|
|
1671
|
-
prepend.push(`import "virtual:rsc-router/routes-manifest";`);
|
|
1672
|
-
}
|
|
1673
|
-
const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
|
|
1674
|
-
if (needsVersion) {
|
|
1675
|
-
prepend.push(`import { VERSION } from "@rangojs/router:version";`);
|
|
1676
|
-
newCode = newCode.replace(
|
|
1677
|
-
/createRSCHandler\s*\(\s*\{/,
|
|
1678
|
-
"createRSCHandler({\n version: VERSION,"
|
|
1679
|
-
);
|
|
1680
|
-
}
|
|
1681
|
-
if (prepend.length === 0 && newCode === code) return null;
|
|
1682
|
-
newCode = prepend.join("\n") + (prepend.length > 0 ? "\n" : "") + newCode;
|
|
1683
|
-
return {
|
|
1684
|
-
code: newCode,
|
|
1685
|
-
map: null
|
|
1686
|
-
};
|
|
1687
|
-
}
|
|
1688
|
-
};
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
// src/vite/plugins/cjs-to-esm.ts
|
|
1692
|
-
function createCjsToEsmPlugin() {
|
|
1693
|
-
return {
|
|
1694
|
-
name: "@rangojs/router:cjs-to-esm",
|
|
1695
|
-
enforce: "pre",
|
|
1696
|
-
transform(code, id) {
|
|
1697
|
-
const cleanId = id.split("?")[0];
|
|
1698
|
-
if (cleanId.includes("vendor/react-server-dom/client.browser.js") || cleanId.includes("vendor\\react-server-dom\\client.browser.js")) {
|
|
1699
|
-
const isProd = process.env.NODE_ENV === "production";
|
|
1700
|
-
const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
1701
|
-
return {
|
|
1702
|
-
code: `export * from "${cjsFile}";`,
|
|
1703
|
-
map: null
|
|
1704
|
-
};
|
|
1705
|
-
}
|
|
1706
|
-
if ((cleanId.includes("vendor/react-server-dom/cjs/") || cleanId.includes("vendor\\react-server-dom\\cjs\\")) && cleanId.includes("client.browser")) {
|
|
1707
|
-
let transformed = code;
|
|
1708
|
-
const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
|
|
1709
|
-
const license = licenseMatch ? licenseMatch[0] : "";
|
|
1710
|
-
if (license) {
|
|
1711
|
-
transformed = transformed.slice(license.length);
|
|
1712
|
-
}
|
|
1713
|
-
transformed = transformed.replace(/^\s*["']use strict["'];\s*/, "");
|
|
1714
|
-
transformed = transformed.replace(
|
|
1715
|
-
/^\s*["']production["']\s*!==\s*process\.env\.NODE_ENV\s*&&\s*\(function\s*\(\)\s*\{/,
|
|
1716
|
-
""
|
|
1717
|
-
);
|
|
1718
|
-
transformed = transformed.replace(/\}\)\(\);?\s*$/, "");
|
|
1719
|
-
transformed = transformed.replace(
|
|
1720
|
-
/var\s+React\s*=\s*require\s*\(\s*["']react["']\s*\)\s*,[\s\n]+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
1721
|
-
'import React from "react";\nimport ReactDOM from "react-dom";\nvar '
|
|
1722
|
-
);
|
|
1723
|
-
transformed = transformed.replace(
|
|
1724
|
-
/var\s+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
1725
|
-
'import ReactDOM from "react-dom";\nvar '
|
|
1726
|
-
);
|
|
1727
|
-
transformed = transformed.replace(
|
|
1728
|
-
/exports\.(\w+)\s*=\s*function\s*\(/g,
|
|
1729
|
-
"export function $1("
|
|
1730
|
-
);
|
|
1731
|
-
transformed = transformed.replace(
|
|
1732
|
-
/exports\.(\w+)\s*=/g,
|
|
1733
|
-
"export const $1 ="
|
|
1734
|
-
);
|
|
1735
|
-
transformed = license + "\n" + transformed;
|
|
1736
|
-
return {
|
|
1737
|
-
code: transformed,
|
|
1738
|
-
map: null
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
return null;
|
|
1742
|
-
}
|
|
1743
|
-
};
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
// src/vite/utils/shared-utils.ts
|
|
1747
|
-
import * as Vite2 from "vite";
|
|
1748
|
-
|
|
1749
|
-
// src/vite/utils/package-resolution.ts
|
|
1750
|
-
import { existsSync } from "node:fs";
|
|
1751
|
-
import { resolve as resolve2 } from "node:path";
|
|
1752
|
-
|
|
1753
|
-
// package.json
|
|
1754
|
-
var package_default = {
|
|
1755
|
-
name: "@rangojs/router",
|
|
1756
|
-
version: "0.0.0-experimental.259",
|
|
1757
|
-
description: "Django-inspired RSC router with composable URL patterns",
|
|
1758
|
-
keywords: [
|
|
1759
|
-
"react",
|
|
1760
|
-
"react-server-components",
|
|
1761
|
-
"router",
|
|
1762
|
-
"rsc",
|
|
1763
|
-
"vite"
|
|
1764
|
-
],
|
|
1765
|
-
homepage: "https://github.com/ivogt/vite-rsc#readme",
|
|
1766
|
-
bugs: {
|
|
1767
|
-
url: "https://github.com/ivogt/vite-rsc/issues"
|
|
1768
|
-
},
|
|
1769
|
-
license: "MIT",
|
|
1770
|
-
author: "Ivo Todorov",
|
|
1771
|
-
repository: {
|
|
1772
|
-
type: "git",
|
|
1773
|
-
url: "git+https://github.com/ivogt/vite-rsc.git",
|
|
1774
|
-
directory: "packages/rangojs-router"
|
|
1775
|
-
},
|
|
1776
|
-
bin: {
|
|
1777
|
-
rango: "./dist/bin/rango.js"
|
|
1778
|
-
},
|
|
1779
|
-
files: [
|
|
1780
|
-
"src",
|
|
1781
|
-
"!src/**/__tests__",
|
|
1782
|
-
"!src/**/__mocks__",
|
|
1783
|
-
"!src/**/*.test.ts",
|
|
1784
|
-
"!src/**/*.test.tsx",
|
|
1785
|
-
"dist",
|
|
1786
|
-
"skills",
|
|
1787
|
-
"CLAUDE.md",
|
|
1788
|
-
"README.md"
|
|
1789
|
-
],
|
|
1790
|
-
type: "module",
|
|
1791
|
-
exports: {
|
|
1792
|
-
".": {
|
|
1793
|
-
types: "./src/index.rsc.ts",
|
|
1794
|
-
"react-server": "./src/index.rsc.ts",
|
|
1795
|
-
default: "./src/index.ts"
|
|
1796
|
-
},
|
|
1797
|
-
"./server": {
|
|
1798
|
-
types: "./src/server.ts",
|
|
1799
|
-
import: "./src/server.ts"
|
|
1800
|
-
},
|
|
1801
|
-
"./client": {
|
|
1802
|
-
types: "./src/client.tsx",
|
|
1803
|
-
"react-server": "./src/client.rsc.tsx",
|
|
1804
|
-
default: "./src/client.tsx"
|
|
1805
|
-
},
|
|
1806
|
-
"./browser": {
|
|
1807
|
-
types: "./src/browser/index.ts",
|
|
1808
|
-
default: "./src/browser/index.ts"
|
|
1798
|
+
"./browser": {
|
|
1799
|
+
types: "./src/browser/index.ts",
|
|
1800
|
+
default: "./src/browser/index.ts"
|
|
1809
1801
|
},
|
|
1810
1802
|
"./ssr": {
|
|
1811
1803
|
types: "./src/ssr/index.tsx",
|
|
@@ -1914,7 +1906,7 @@ var package_default = {
|
|
|
1914
1906
|
vitest: "^4.0.0"
|
|
1915
1907
|
},
|
|
1916
1908
|
peerDependencies: {
|
|
1917
|
-
"@cloudflare/vite-plugin": "^1.25.
|
|
1909
|
+
"@cloudflare/vite-plugin": "^1.25.0",
|
|
1918
1910
|
"@vitejs/plugin-rsc": "^0.5.14",
|
|
1919
1911
|
react: "^18.0.0 || ^19.0.0",
|
|
1920
1912
|
vite: "^7.3.0"
|
|
@@ -1936,7 +1928,7 @@ function getPublishedPackageName() {
|
|
|
1936
1928
|
}
|
|
1937
1929
|
function isInstalledFromNpm() {
|
|
1938
1930
|
const packageName = getPublishedPackageName();
|
|
1939
|
-
return existsSync(
|
|
1931
|
+
return existsSync(resolve(process.cwd(), "node_modules", packageName));
|
|
1940
1932
|
}
|
|
1941
1933
|
function isWorkspaceDevelopment() {
|
|
1942
1934
|
return !isInstalledFromNpm();
|
|
@@ -1971,413 +1963,122 @@ function getPackageAliases() {
|
|
|
1971
1963
|
return aliases;
|
|
1972
1964
|
}
|
|
1973
1965
|
|
|
1974
|
-
// src/
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
}));
|
|
1982
|
-
build.onLoad(
|
|
1983
|
-
{ filter: /.*/, namespace: "@rangojs/router-virtual" },
|
|
1984
|
-
() => ({
|
|
1985
|
-
contents: `export const VERSION = "dev";`,
|
|
1986
|
-
loader: "js"
|
|
1987
|
-
})
|
|
1988
|
-
);
|
|
1989
|
-
}
|
|
1990
|
-
};
|
|
1991
|
-
var sharedEsbuildOptions = {
|
|
1992
|
-
plugins: [versionEsbuildPlugin]
|
|
1993
|
-
};
|
|
1994
|
-
function createVirtualEntriesPlugin(entries, routerPath) {
|
|
1995
|
-
const virtualModules = {};
|
|
1996
|
-
if (entries.client === VIRTUAL_IDS.browser) {
|
|
1997
|
-
virtualModules[VIRTUAL_IDS.browser] = VIRTUAL_ENTRY_BROWSER;
|
|
1998
|
-
}
|
|
1999
|
-
if (entries.ssr === VIRTUAL_IDS.ssr) {
|
|
2000
|
-
virtualModules[VIRTUAL_IDS.ssr] = VIRTUAL_ENTRY_SSR;
|
|
2001
|
-
}
|
|
2002
|
-
if (entries.rsc === VIRTUAL_IDS.rsc && routerPath) {
|
|
2003
|
-
const absoluteRouterPath = routerPath.startsWith(".") ? "/" + routerPath.slice(2) : routerPath;
|
|
2004
|
-
virtualModules[VIRTUAL_IDS.rsc] = getVirtualEntryRSC(absoluteRouterPath);
|
|
2005
|
-
}
|
|
2006
|
-
return {
|
|
2007
|
-
name: "@rangojs/router:virtual-entries",
|
|
2008
|
-
enforce: "pre",
|
|
2009
|
-
resolveId(id) {
|
|
2010
|
-
if (id in virtualModules) {
|
|
2011
|
-
return "\0" + id;
|
|
2012
|
-
}
|
|
2013
|
-
if (id.startsWith("\0") && id.slice(1) in virtualModules) {
|
|
2014
|
-
return id;
|
|
2015
|
-
}
|
|
2016
|
-
return null;
|
|
2017
|
-
},
|
|
2018
|
-
load(id) {
|
|
2019
|
-
if (id.startsWith("\0virtual:rsc-router/")) {
|
|
2020
|
-
const virtualId = id.slice(1);
|
|
2021
|
-
if (virtualId in virtualModules) {
|
|
2022
|
-
return virtualModules[virtualId];
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
return null;
|
|
2026
|
-
}
|
|
2027
|
-
};
|
|
2028
|
-
}
|
|
2029
|
-
function onwarn(warning, defaultHandler) {
|
|
2030
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE") {
|
|
2031
|
-
return;
|
|
2032
|
-
}
|
|
2033
|
-
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
2034
|
-
return;
|
|
2035
|
-
}
|
|
2036
|
-
if (warning.plugin === "vite:reporter" && warning.message?.includes(
|
|
2037
|
-
"dynamic import will not move module into another chunk"
|
|
2038
|
-
)) {
|
|
2039
|
-
return;
|
|
1966
|
+
// src/build/route-types/param-extraction.ts
|
|
1967
|
+
function extractParamsFromPattern(pattern) {
|
|
1968
|
+
const params = {};
|
|
1969
|
+
const regex = /:([a-zA-Z_$][\w$]*)(?:\([^)]+\))?(\?)?/g;
|
|
1970
|
+
let match;
|
|
1971
|
+
while ((match = regex.exec(pattern)) !== null) {
|
|
1972
|
+
params[match[1]] = match[2] ? "string?" : "string";
|
|
2040
1973
|
}
|
|
2041
|
-
|
|
1974
|
+
return Object.keys(params).length > 0 ? params : void 0;
|
|
2042
1975
|
}
|
|
2043
|
-
function
|
|
2044
|
-
const
|
|
2045
|
-
if (
|
|
2046
|
-
return "
|
|
2047
|
-
}
|
|
2048
|
-
const packageName = getPublishedPackageName();
|
|
2049
|
-
if (normalized.includes(`node_modules/${packageName}/`) || normalized.includes("packages/rsc-router/") || normalized.includes("packages/rangojs-router/")) {
|
|
2050
|
-
return "router";
|
|
1976
|
+
function formatRouteEntry(key, pattern, _params, search) {
|
|
1977
|
+
const hasSearch = search && Object.keys(search).length > 0;
|
|
1978
|
+
if (!hasSearch) {
|
|
1979
|
+
return ` ${key}: "${pattern}",`;
|
|
2051
1980
|
}
|
|
2052
|
-
|
|
1981
|
+
const searchBody = Object.entries(search).map(([k, v]) => `${k}: "${v}"`).join(", ");
|
|
1982
|
+
return ` ${key}: { path: "${pattern}", search: { ${searchBody} } },`;
|
|
2053
1983
|
}
|
|
2054
1984
|
|
|
2055
|
-
// src/
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
2067
|
-
} else {
|
|
2068
|
-
for (const child of Object.values(children)) {
|
|
2069
|
-
visit(child);
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
for (const node of Object.values(prefixTree)) {
|
|
2074
|
-
visit(node);
|
|
2075
|
-
}
|
|
1985
|
+
// src/build/route-types/ast-route-extraction.ts
|
|
1986
|
+
import ts2 from "typescript";
|
|
1987
|
+
|
|
1988
|
+
// src/build/route-types/ast-helpers.ts
|
|
1989
|
+
import ts from "typescript";
|
|
1990
|
+
function getStringValue(node) {
|
|
1991
|
+
if (ts.isStringLiteral(node)) return node.text;
|
|
1992
|
+
if (ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
1993
|
+
return null;
|
|
2076
1994
|
}
|
|
2077
|
-
function
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
for (const node of Object.values(prefixTree)) {
|
|
2088
|
-
visit(node);
|
|
1995
|
+
function extractObjectStringProperties(node) {
|
|
1996
|
+
const result = {};
|
|
1997
|
+
for (const prop of node.properties) {
|
|
1998
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
1999
|
+
const key = ts.isIdentifier(prop.name) ? prop.name.text : ts.isStringLiteral(prop.name) ? prop.name.text : null;
|
|
2000
|
+
if (!key) continue;
|
|
2001
|
+
const val = getStringValue(prop.initializer);
|
|
2002
|
+
if (val !== null) result[key] = val;
|
|
2089
2003
|
}
|
|
2090
|
-
|
|
2091
|
-
function jsonParseExpression(value) {
|
|
2092
|
-
const json = JSON.stringify(value);
|
|
2093
|
-
const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
2094
|
-
return `JSON.parse('${escaped}')`;
|
|
2004
|
+
return result;
|
|
2095
2005
|
}
|
|
2096
2006
|
|
|
2097
|
-
// src/
|
|
2098
|
-
function
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2007
|
+
// src/build/route-types/ast-route-extraction.ts
|
|
2008
|
+
function extractRoutesFromSource(code) {
|
|
2009
|
+
const sourceFile = ts2.createSourceFile(
|
|
2010
|
+
"input.tsx",
|
|
2011
|
+
code,
|
|
2012
|
+
ts2.ScriptTarget.Latest,
|
|
2013
|
+
true,
|
|
2014
|
+
ts2.ScriptKind.TSX
|
|
2015
|
+
);
|
|
2016
|
+
const routes = [];
|
|
2017
|
+
function visit(node) {
|
|
2018
|
+
if (ts2.isCallExpression(node)) {
|
|
2019
|
+
const callee = node.expression;
|
|
2020
|
+
const isPath = ts2.isIdentifier(callee) && callee.text === "path" || ts2.isPropertyAccessExpression(callee) && ts2.isIdentifier(callee.expression) && callee.expression.text === "path";
|
|
2021
|
+
if (isPath && node.arguments.length >= 1) {
|
|
2022
|
+
const route = extractRouteFromCallExpression(node);
|
|
2023
|
+
if (route) routes.push(route);
|
|
2024
|
+
}
|
|
2106
2025
|
}
|
|
2107
|
-
|
|
2108
|
-
else if (code[pos] === ")") depth--;
|
|
2109
|
-
pos++;
|
|
2026
|
+
ts2.forEachChild(node, visit);
|
|
2110
2027
|
}
|
|
2111
|
-
|
|
2028
|
+
visit(sourceFile);
|
|
2029
|
+
return routes;
|
|
2112
2030
|
}
|
|
2113
|
-
function
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
const callStart = callStartRe.exec(chunkCode);
|
|
2130
|
-
if (callStart) {
|
|
2131
|
-
const afterOpen = callStart.index + callStart[0].length;
|
|
2132
|
-
const closePos = findMatchingParenInBundle(chunkCode, afterOpen);
|
|
2133
|
-
if (closePos !== -1) {
|
|
2134
|
-
const callBody = chunkCode.slice(callStart.index, closePos);
|
|
2135
|
-
isPassthrough = /passthrough\s*:\s*(!0|true)/.test(callBody);
|
|
2136
|
-
}
|
|
2031
|
+
function extractRouteFromCallExpression(node) {
|
|
2032
|
+
const patternNode = node.arguments[0];
|
|
2033
|
+
const pattern = getStringValue(patternNode);
|
|
2034
|
+
if (pattern === null) return null;
|
|
2035
|
+
let name = null;
|
|
2036
|
+
let search;
|
|
2037
|
+
for (let i = 1; i < node.arguments.length; i++) {
|
|
2038
|
+
const arg = node.arguments[i];
|
|
2039
|
+
if (ts2.isObjectLiteralExpression(arg)) {
|
|
2040
|
+
for (const prop of arg.properties) {
|
|
2041
|
+
if (!ts2.isPropertyAssignment(prop)) continue;
|
|
2042
|
+
const propName = ts2.isIdentifier(prop.name) ? prop.name.text : null;
|
|
2043
|
+
if (propName === "name") {
|
|
2044
|
+
name = getStringValue(prop.initializer);
|
|
2045
|
+
} else if (propName === "search" && ts2.isObjectLiteralExpression(prop.initializer)) {
|
|
2046
|
+
search = extractObjectStringProperties(prop.initializer);
|
|
2137
2047
|
}
|
|
2138
2048
|
}
|
|
2139
|
-
handlers.push({ name, handlerId: match[1], passthrough: isPassthrough });
|
|
2140
2049
|
}
|
|
2141
2050
|
}
|
|
2142
|
-
return
|
|
2143
|
-
|
|
2144
|
-
function evictHandlerCode(code, exports, fnName, brand) {
|
|
2145
|
-
const originalSize = Buffer.byteLength(code);
|
|
2146
|
-
let modified = code;
|
|
2147
|
-
const eFnName = escapeRegExp(fnName);
|
|
2148
|
-
for (const { name, handlerId, passthrough } of exports) {
|
|
2149
|
-
if (passthrough) continue;
|
|
2150
|
-
const eName = escapeRegExp(name);
|
|
2151
|
-
const callStartRe = new RegExp(
|
|
2152
|
-
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
2153
|
-
);
|
|
2154
|
-
const startMatch = callStartRe.exec(modified);
|
|
2155
|
-
if (!startMatch) continue;
|
|
2156
|
-
const afterOpen = startMatch.index + startMatch[0].length;
|
|
2157
|
-
const closePos = findMatchingParenInBundle(modified, afterOpen);
|
|
2158
|
-
if (closePos === -1) continue;
|
|
2159
|
-
let rangeEnd = closePos;
|
|
2160
|
-
while (rangeEnd < modified.length && /\s/.test(modified[rangeEnd]))
|
|
2161
|
-
rangeEnd++;
|
|
2162
|
-
if (modified[rangeEnd] === ";") rangeEnd++;
|
|
2163
|
-
const matched = modified.slice(startMatch.index, rangeEnd);
|
|
2164
|
-
if (!matched.includes(handlerId)) continue;
|
|
2165
|
-
const stub = `const ${name} = { __brand: "${brand}", $$id: "${handlerId}" };`;
|
|
2166
|
-
modified = modified.slice(0, startMatch.index) + stub + modified.slice(rangeEnd);
|
|
2167
|
-
modified = modified.replace(
|
|
2168
|
-
new RegExp(`\\n${eName}\\.\\$\\$id\\s*=\\s*"[^"]+";`),
|
|
2169
|
-
""
|
|
2170
|
-
);
|
|
2171
|
-
}
|
|
2172
|
-
if (modified === code) return null;
|
|
2051
|
+
if (!name) return null;
|
|
2052
|
+
const params = extractParamsFromPattern(pattern);
|
|
2173
2053
|
return {
|
|
2174
|
-
|
|
2175
|
-
|
|
2054
|
+
name,
|
|
2055
|
+
pattern,
|
|
2056
|
+
...params ? { params } : {},
|
|
2057
|
+
...search && Object.keys(search).length > 0 ? { search } : {}
|
|
2176
2058
|
};
|
|
2177
2059
|
}
|
|
2178
2060
|
|
|
2179
|
-
// src/
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
}
|
|
2186
|
-
async function runWithConcurrency(items, concurrency, fn) {
|
|
2187
|
-
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
2188
|
-
if (limit <= 1) {
|
|
2189
|
-
for (const item of items) await fn(item);
|
|
2190
|
-
return;
|
|
2191
|
-
}
|
|
2192
|
-
let nextIndex = 0;
|
|
2193
|
-
async function worker() {
|
|
2194
|
-
while (nextIndex < items.length) {
|
|
2195
|
-
const idx = nextIndex++;
|
|
2196
|
-
await fn(items[idx]);
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
2200
|
-
}
|
|
2201
|
-
function groupByConcurrency(entries) {
|
|
2202
|
-
const map = /* @__PURE__ */ new Map();
|
|
2203
|
-
for (const entry of entries) {
|
|
2204
|
-
const key = entry.concurrency;
|
|
2205
|
-
let group = map.get(key);
|
|
2206
|
-
if (!group) {
|
|
2207
|
-
group = [];
|
|
2208
|
-
map.set(key, group);
|
|
2209
|
-
}
|
|
2210
|
-
group.push(entry);
|
|
2211
|
-
}
|
|
2212
|
-
return Array.from(map.entries(), ([concurrency, items]) => ({
|
|
2213
|
-
concurrency,
|
|
2214
|
-
entries: items
|
|
2215
|
-
}));
|
|
2216
|
-
}
|
|
2217
|
-
function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
|
|
2218
|
-
for (const [, routerInstance] of registry) {
|
|
2219
|
-
const onError = routerInstance.onError;
|
|
2220
|
-
if (!onError) continue;
|
|
2221
|
-
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
2222
|
-
const syntheticUrl = new URL("http://prerender" + (pathname || "/"));
|
|
2223
|
-
const context = {
|
|
2224
|
-
error: errorObj,
|
|
2225
|
-
phase,
|
|
2226
|
-
request: new Request(syntheticUrl),
|
|
2227
|
-
url: syntheticUrl,
|
|
2228
|
-
pathname: syntheticUrl.pathname,
|
|
2229
|
-
method: "GET",
|
|
2230
|
-
routeKey,
|
|
2231
|
-
metadata: skipped ? { skipped: true } : void 0
|
|
2232
|
-
};
|
|
2233
|
-
try {
|
|
2234
|
-
const result = onError(context);
|
|
2235
|
-
if (result instanceof Promise) {
|
|
2236
|
-
result.catch((cbErr) => {
|
|
2237
|
-
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
2238
|
-
});
|
|
2239
|
-
}
|
|
2240
|
-
} catch (cbErr) {
|
|
2241
|
-
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
2242
|
-
}
|
|
2243
|
-
break;
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
|
|
2247
|
-
// src/vite/utils/banner.ts
|
|
2248
|
-
var rangoVersion = package_default.version;
|
|
2249
|
-
var _bannerPrinted = false;
|
|
2250
|
-
function printBanner(mode, preset, version) {
|
|
2251
|
-
if (_bannerPrinted) return;
|
|
2252
|
-
_bannerPrinted = true;
|
|
2253
|
-
const dim = "\x1B[2m";
|
|
2254
|
-
const bold = "\x1B[1m";
|
|
2255
|
-
const reset = "\x1B[0m";
|
|
2256
|
-
const banner = `
|
|
2257
|
-
${dim} \u2726 \u2726 \u2727. . .${reset}
|
|
2258
|
-
${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
|
|
2259
|
-
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
2260
|
-
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
2261
|
-
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
|
|
2262
|
-
${dim} ${reset}${bold}\u2550\u2563\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
2263
|
-
${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
|
|
2264
|
-
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
2265
|
-
${dim} * ${reset}${bold}\u2551 \u2560\u2550${reset}${dim} * \u2727. \u2571${reset}
|
|
2266
|
-
${bold}\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
2267
|
-
|
|
2268
|
-
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
2269
|
-
`;
|
|
2270
|
-
console.log(banner);
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
// src/vite/router-discovery.ts
|
|
2274
|
-
import { createServer as createViteServer } from "vite";
|
|
2275
|
-
import { readFileSync as readFileSync6 } from "node:fs";
|
|
2276
|
-
|
|
2277
|
-
// src/build/route-types/param-extraction.ts
|
|
2278
|
-
function extractParamsFromPattern(pattern) {
|
|
2279
|
-
const params = {};
|
|
2280
|
-
const regex = /:([a-zA-Z_$][\w$]*)(?:\([^)]+\))?(\?)?/g;
|
|
2281
|
-
let match;
|
|
2282
|
-
while ((match = regex.exec(pattern)) !== null) {
|
|
2283
|
-
params[match[1]] = match[2] ? "string?" : "string";
|
|
2284
|
-
}
|
|
2285
|
-
return Object.keys(params).length > 0 ? params : void 0;
|
|
2286
|
-
}
|
|
2287
|
-
function formatRouteEntry(key, pattern, _params, search) {
|
|
2288
|
-
const hasSearch = search && Object.keys(search).length > 0;
|
|
2289
|
-
if (!hasSearch) {
|
|
2290
|
-
return ` ${key}: "${pattern}",`;
|
|
2291
|
-
}
|
|
2292
|
-
const searchBody = Object.entries(search).map(([k, v]) => `${k}: "${v}"`).join(", ");
|
|
2293
|
-
return ` ${key}: { path: "${pattern}", search: { ${searchBody} } },`;
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
// src/build/route-types/ast-route-extraction.ts
|
|
2297
|
-
import ts2 from "typescript";
|
|
2298
|
-
|
|
2299
|
-
// src/build/route-types/ast-helpers.ts
|
|
2300
|
-
import ts from "typescript";
|
|
2301
|
-
function getStringValue(node) {
|
|
2302
|
-
if (ts.isStringLiteral(node)) return node.text;
|
|
2303
|
-
if (ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
2304
|
-
return null;
|
|
2305
|
-
}
|
|
2306
|
-
function extractObjectStringProperties(node) {
|
|
2307
|
-
const result = {};
|
|
2308
|
-
for (const prop of node.properties) {
|
|
2309
|
-
if (!ts.isPropertyAssignment(prop)) continue;
|
|
2310
|
-
const key = ts.isIdentifier(prop.name) ? prop.name.text : ts.isStringLiteral(prop.name) ? prop.name.text : null;
|
|
2311
|
-
if (!key) continue;
|
|
2312
|
-
const val = getStringValue(prop.initializer);
|
|
2313
|
-
if (val !== null) result[key] = val;
|
|
2314
|
-
}
|
|
2315
|
-
return result;
|
|
2316
|
-
}
|
|
2317
|
-
|
|
2318
|
-
// src/build/route-types/ast-route-extraction.ts
|
|
2319
|
-
function extractRoutesFromSource(code) {
|
|
2320
|
-
const sourceFile = ts2.createSourceFile(
|
|
2321
|
-
"input.tsx",
|
|
2322
|
-
code,
|
|
2323
|
-
ts2.ScriptTarget.Latest,
|
|
2324
|
-
true,
|
|
2325
|
-
ts2.ScriptKind.TSX
|
|
2326
|
-
);
|
|
2327
|
-
const routes = [];
|
|
2328
|
-
function visit(node) {
|
|
2329
|
-
if (ts2.isCallExpression(node)) {
|
|
2330
|
-
const callee = node.expression;
|
|
2331
|
-
const isPath = ts2.isIdentifier(callee) && callee.text === "path" || ts2.isPropertyAccessExpression(callee) && ts2.isIdentifier(callee.expression) && callee.expression.text === "path";
|
|
2332
|
-
if (isPath && node.arguments.length >= 1) {
|
|
2333
|
-
const route = extractRouteFromCallExpression(node);
|
|
2334
|
-
if (route) routes.push(route);
|
|
2335
|
-
}
|
|
2336
|
-
}
|
|
2337
|
-
ts2.forEachChild(node, visit);
|
|
2338
|
-
}
|
|
2339
|
-
visit(sourceFile);
|
|
2340
|
-
return routes;
|
|
2341
|
-
}
|
|
2342
|
-
function extractRouteFromCallExpression(node) {
|
|
2343
|
-
const patternNode = node.arguments[0];
|
|
2344
|
-
const pattern = getStringValue(patternNode);
|
|
2345
|
-
if (pattern === null) return null;
|
|
2346
|
-
let name = null;
|
|
2347
|
-
let search;
|
|
2348
|
-
for (let i = 1; i < node.arguments.length; i++) {
|
|
2349
|
-
const arg = node.arguments[i];
|
|
2350
|
-
if (ts2.isObjectLiteralExpression(arg)) {
|
|
2351
|
-
for (const prop of arg.properties) {
|
|
2352
|
-
if (!ts2.isPropertyAssignment(prop)) continue;
|
|
2353
|
-
const propName = ts2.isIdentifier(prop.name) ? prop.name.text : null;
|
|
2354
|
-
if (propName === "name") {
|
|
2355
|
-
name = getStringValue(prop.initializer);
|
|
2356
|
-
} else if (propName === "search" && ts2.isObjectLiteralExpression(prop.initializer)) {
|
|
2357
|
-
search = extractObjectStringProperties(prop.initializer);
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
if (!name) return null;
|
|
2363
|
-
const params = extractParamsFromPattern(pattern);
|
|
2364
|
-
return {
|
|
2365
|
-
name,
|
|
2366
|
-
pattern,
|
|
2367
|
-
...params ? { params } : {},
|
|
2368
|
-
...search && Object.keys(search).length > 0 ? { search } : {}
|
|
2369
|
-
};
|
|
2061
|
+
// src/route-name.ts
|
|
2062
|
+
var AUTO_GENERATED_ROUTE_PREFIX = "$path_";
|
|
2063
|
+
var INTERNAL_INCLUDE_SCOPE_PREFIX = "$prefix_";
|
|
2064
|
+
function isAutoGeneratedRouteName(name) {
|
|
2065
|
+
return name.split(".").some((segment) => {
|
|
2066
|
+
return segment.startsWith(AUTO_GENERATED_ROUTE_PREFIX) || segment.startsWith(INTERNAL_INCLUDE_SCOPE_PREFIX);
|
|
2067
|
+
});
|
|
2370
2068
|
}
|
|
2371
2069
|
|
|
2372
2070
|
// src/build/route-types/codegen.ts
|
|
2373
2071
|
function generateRouteTypesSource(routeManifest, searchSchemas) {
|
|
2374
|
-
const entries = Object.entries(routeManifest).sort(
|
|
2375
|
-
|
|
2376
|
-
|
|
2072
|
+
const entries = Object.entries(routeManifest).filter(([name]) => !isAutoGeneratedRouteName(name)).sort(([a], [b]) => a.localeCompare(b));
|
|
2073
|
+
const filteredSearchSchemas = searchSchemas ? Object.fromEntries(
|
|
2074
|
+
Object.entries(searchSchemas).filter(
|
|
2075
|
+
([name]) => !isAutoGeneratedRouteName(name)
|
|
2076
|
+
)
|
|
2077
|
+
) : void 0;
|
|
2377
2078
|
const objectBody = entries.map(([name, pattern]) => {
|
|
2378
2079
|
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
|
|
2379
2080
|
const params = extractParamsFromPattern(pattern);
|
|
2380
|
-
const search =
|
|
2081
|
+
const search = filteredSearchSchemas?.[name];
|
|
2381
2082
|
return formatRouteEntry(key, pattern, params, search);
|
|
2382
2083
|
}).join("\n");
|
|
2383
2084
|
return `// Auto-generated by @rangojs/router - do not edit
|
|
@@ -2394,8 +2095,7 @@ declare global {
|
|
|
2394
2095
|
}
|
|
2395
2096
|
|
|
2396
2097
|
// src/build/route-types/scan-filter.ts
|
|
2397
|
-
import { join, relative
|
|
2398
|
-
import { readdirSync } from "node:fs";
|
|
2098
|
+
import { join, relative } from "node:path";
|
|
2399
2099
|
import picomatch from "picomatch";
|
|
2400
2100
|
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2401
2101
|
"**/__tests__/**",
|
|
@@ -2414,42 +2114,19 @@ function createScanFilter(root, opts) {
|
|
|
2414
2114
|
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2415
2115
|
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2416
2116
|
return (absolutePath) => {
|
|
2417
|
-
const rel =
|
|
2117
|
+
const rel = relative(root, absolutePath);
|
|
2418
2118
|
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2419
2119
|
if (includeMatcher) return includeMatcher(rel);
|
|
2420
2120
|
return true;
|
|
2421
2121
|
};
|
|
2422
2122
|
}
|
|
2423
|
-
function findTsFiles(dir, filter) {
|
|
2424
|
-
const results = [];
|
|
2425
|
-
let entries;
|
|
2426
|
-
try {
|
|
2427
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
2428
|
-
} catch (err) {
|
|
2429
|
-
console.warn(
|
|
2430
|
-
`[rsc-router] Failed to scan directory ${dir}: ${err.message}`
|
|
2431
|
-
);
|
|
2432
|
-
return results;
|
|
2433
|
-
}
|
|
2434
|
-
for (const entry of entries) {
|
|
2435
|
-
const fullPath = join(dir, entry.name);
|
|
2436
|
-
if (entry.isDirectory()) {
|
|
2437
|
-
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
2438
|
-
results.push(...findTsFiles(fullPath, filter));
|
|
2439
|
-
} else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
|
|
2440
|
-
if (filter && !filter(fullPath)) continue;
|
|
2441
|
-
results.push(fullPath);
|
|
2442
|
-
}
|
|
2443
|
-
}
|
|
2444
|
-
return results;
|
|
2445
|
-
}
|
|
2446
2123
|
|
|
2447
2124
|
// src/build/route-types/per-module-writer.ts
|
|
2448
2125
|
import ts4 from "typescript";
|
|
2449
2126
|
|
|
2450
2127
|
// src/build/route-types/include-resolution.ts
|
|
2451
2128
|
import { readFileSync, existsSync as existsSync2 } from "node:fs";
|
|
2452
|
-
import { dirname, resolve as
|
|
2129
|
+
import { dirname, resolve as resolve2 } from "node:path";
|
|
2453
2130
|
import ts3 from "typescript";
|
|
2454
2131
|
function extractNamePrefixFromInclude(node) {
|
|
2455
2132
|
if (node.arguments.length >= 3) {
|
|
@@ -2544,14 +2221,14 @@ function resolveImportPath(importSpec, fromFile) {
|
|
|
2544
2221
|
else if (base.endsWith(".mjs")) base = base.slice(0, -4);
|
|
2545
2222
|
else if (base.endsWith(".jsx")) base = base.slice(0, -4);
|
|
2546
2223
|
const candidates = [
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2224
|
+
resolve2(dir, base + ".ts"),
|
|
2225
|
+
resolve2(dir, base + ".tsx"),
|
|
2226
|
+
resolve2(dir, base + ".js"),
|
|
2227
|
+
resolve2(dir, base + ".jsx"),
|
|
2228
|
+
resolve2(dir, base + "/index.ts"),
|
|
2229
|
+
resolve2(dir, base + "/index.tsx"),
|
|
2230
|
+
resolve2(dir, base + "/index.js"),
|
|
2231
|
+
resolve2(dir, base + "/index.jsx")
|
|
2555
2232
|
];
|
|
2556
2233
|
for (const candidate of candidates) {
|
|
2557
2234
|
if (existsSync2(candidate)) return candidate;
|
|
@@ -2643,6 +2320,9 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2643
2320
|
diagnosticsOut
|
|
2644
2321
|
);
|
|
2645
2322
|
}
|
|
2323
|
+
if (namePrefix === null) {
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2646
2326
|
for (const [name, pattern] of Object.entries(childResult.routes)) {
|
|
2647
2327
|
const prefixedName = namePrefix ? `${namePrefix}.${name}` : name;
|
|
2648
2328
|
let prefixedPattern;
|
|
@@ -2663,7 +2343,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2663
2343
|
}
|
|
2664
2344
|
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut) {
|
|
2665
2345
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
2666
|
-
const realPath =
|
|
2346
|
+
const realPath = resolve2(filePath);
|
|
2667
2347
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
2668
2348
|
if (visited.has(key)) {
|
|
2669
2349
|
console.warn(`[rsc-router] Circular include detected, skipping: ${key}`);
|
|
@@ -2693,13 +2373,108 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2693
2373
|
searchSchemas,
|
|
2694
2374
|
diagnosticsOut
|
|
2695
2375
|
);
|
|
2376
|
+
visited.delete(key);
|
|
2696
2377
|
return { routes, searchSchemas };
|
|
2697
2378
|
}
|
|
2698
2379
|
|
|
2699
2380
|
// src/build/route-types/router-processing.ts
|
|
2700
|
-
import {
|
|
2701
|
-
|
|
2381
|
+
import {
|
|
2382
|
+
readFileSync as readFileSync2,
|
|
2383
|
+
writeFileSync,
|
|
2384
|
+
existsSync as existsSync3,
|
|
2385
|
+
unlinkSync,
|
|
2386
|
+
readdirSync
|
|
2387
|
+
} from "node:fs";
|
|
2388
|
+
import {
|
|
2389
|
+
join as join2,
|
|
2390
|
+
dirname as dirname2,
|
|
2391
|
+
resolve as resolve3,
|
|
2392
|
+
sep,
|
|
2393
|
+
basename as pathBasename
|
|
2394
|
+
} from "node:path";
|
|
2702
2395
|
import ts5 from "typescript";
|
|
2396
|
+
function countPublicRouteEntries(source) {
|
|
2397
|
+
const matches = source.matchAll(/^\s+(?:"([^"]+)"|([a-zA-Z_$][^:]*)):\s*["{]/gm) ?? [];
|
|
2398
|
+
let count = 0;
|
|
2399
|
+
for (const match of matches) {
|
|
2400
|
+
const routeName = match[1] || match[2];
|
|
2401
|
+
if (routeName && !isAutoGeneratedRouteName(routeName.trim())) {
|
|
2402
|
+
count++;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
return count;
|
|
2406
|
+
}
|
|
2407
|
+
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2408
|
+
function isRoutableSourceFile(name) {
|
|
2409
|
+
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.");
|
|
2410
|
+
}
|
|
2411
|
+
function findRouterFilesRecursive(dir, filter, results) {
|
|
2412
|
+
let entries;
|
|
2413
|
+
try {
|
|
2414
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
2415
|
+
} catch (err) {
|
|
2416
|
+
console.warn(
|
|
2417
|
+
`[rsc-router] Failed to scan directory ${dir}: ${err.message}`
|
|
2418
|
+
);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
const childDirs = [];
|
|
2422
|
+
const routerFilesInDir = [];
|
|
2423
|
+
for (const entry of entries) {
|
|
2424
|
+
const fullPath = join2(dir, entry.name);
|
|
2425
|
+
if (entry.isDirectory()) {
|
|
2426
|
+
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
2427
|
+
childDirs.push(fullPath);
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
if (!isRoutableSourceFile(entry.name)) continue;
|
|
2431
|
+
if (filter && !filter(fullPath)) continue;
|
|
2432
|
+
try {
|
|
2433
|
+
const source = readFileSync2(fullPath, "utf-8");
|
|
2434
|
+
if (ROUTER_CALL_PATTERN.test(source)) {
|
|
2435
|
+
routerFilesInDir.push(fullPath);
|
|
2436
|
+
}
|
|
2437
|
+
} catch {
|
|
2438
|
+
continue;
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
if (routerFilesInDir.length > 0) {
|
|
2442
|
+
results.push(...routerFilesInDir);
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
for (const childDir of childDirs) {
|
|
2446
|
+
findRouterFilesRecursive(childDir, filter, results);
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
function findNestedRouterConflict(routerFiles) {
|
|
2450
|
+
const routerDirs = [
|
|
2451
|
+
...new Set(routerFiles.map((filePath) => dirname2(resolve3(filePath))))
|
|
2452
|
+
].sort((a, b) => a.length - b.length);
|
|
2453
|
+
for (let i = 0; i < routerDirs.length; i++) {
|
|
2454
|
+
const ancestorDir = routerDirs[i];
|
|
2455
|
+
const prefix = ancestorDir.endsWith(sep) ? ancestorDir : `${ancestorDir}${sep}`;
|
|
2456
|
+
for (let j = i + 1; j < routerDirs.length; j++) {
|
|
2457
|
+
const nestedDir = routerDirs[j];
|
|
2458
|
+
if (!nestedDir.startsWith(prefix)) continue;
|
|
2459
|
+
const ancestorFile = routerFiles.find(
|
|
2460
|
+
(filePath) => dirname2(resolve3(filePath)) === ancestorDir
|
|
2461
|
+
);
|
|
2462
|
+
const nestedFile = routerFiles.find(
|
|
2463
|
+
(filePath) => dirname2(resolve3(filePath)) === nestedDir
|
|
2464
|
+
);
|
|
2465
|
+
if (ancestorFile && nestedFile) {
|
|
2466
|
+
return { ancestor: ancestorFile, nested: nestedFile };
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
return null;
|
|
2471
|
+
}
|
|
2472
|
+
function formatNestedRouterConflictError(conflict, prefix = "[rsc-router]") {
|
|
2473
|
+
return `${prefix} Nested router roots are not supported.
|
|
2474
|
+
Router root: ${conflict.ancestor}
|
|
2475
|
+
Nested router: ${conflict.nested}
|
|
2476
|
+
Move the nested router into a sibling directory or configure it as a separate app root.`;
|
|
2477
|
+
}
|
|
2703
2478
|
function extractUrlsVariableFromRouter(code) {
|
|
2704
2479
|
const sourceFile = ts5.createSourceFile(
|
|
2705
2480
|
"router.tsx",
|
|
@@ -2761,95 +2536,657 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2761
2536
|
if (!targetFile) {
|
|
2762
2537
|
return { routes: {}, searchSchemas: {} };
|
|
2763
2538
|
}
|
|
2764
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2765
|
-
}
|
|
2766
|
-
return buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2539
|
+
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2540
|
+
}
|
|
2541
|
+
return buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2542
|
+
}
|
|
2543
|
+
function findRouterFiles(root, filter) {
|
|
2544
|
+
const result = [];
|
|
2545
|
+
findRouterFilesRecursive(root, filter, result);
|
|
2546
|
+
return result;
|
|
2547
|
+
}
|
|
2548
|
+
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
2549
|
+
try {
|
|
2550
|
+
const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
|
|
2551
|
+
if (existsSync3(oldCombinedPath)) {
|
|
2552
|
+
unlinkSync(oldCombinedPath);
|
|
2553
|
+
console.log(
|
|
2554
|
+
`[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
} catch {
|
|
2558
|
+
}
|
|
2559
|
+
const routerFilePaths = knownRouterFiles ?? findRouterFiles(root);
|
|
2560
|
+
if (routerFilePaths.length === 0) return;
|
|
2561
|
+
const nestedRouterConflict = findNestedRouterConflict(routerFilePaths);
|
|
2562
|
+
if (nestedRouterConflict) {
|
|
2563
|
+
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
2564
|
+
}
|
|
2565
|
+
for (const routerFilePath of routerFilePaths) {
|
|
2566
|
+
let routerSource;
|
|
2567
|
+
try {
|
|
2568
|
+
routerSource = readFileSync2(routerFilePath, "utf-8");
|
|
2569
|
+
} catch {
|
|
2570
|
+
continue;
|
|
2571
|
+
}
|
|
2572
|
+
const urlsVarName = extractUrlsVariableFromRouter(routerSource);
|
|
2573
|
+
if (!urlsVarName) continue;
|
|
2574
|
+
let result;
|
|
2575
|
+
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
2576
|
+
if (imported) {
|
|
2577
|
+
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2578
|
+
if (!targetFile) continue;
|
|
2579
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2580
|
+
targetFile,
|
|
2581
|
+
imported.exportedName
|
|
2582
|
+
);
|
|
2583
|
+
} else {
|
|
2584
|
+
result = buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2585
|
+
}
|
|
2586
|
+
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2587
|
+
/\.(tsx?|jsx?)$/,
|
|
2588
|
+
""
|
|
2589
|
+
);
|
|
2590
|
+
const outPath = join2(
|
|
2591
|
+
dirname2(routerFilePath),
|
|
2592
|
+
`${routerBasename}.named-routes.gen.ts`
|
|
2593
|
+
);
|
|
2594
|
+
const existing = existsSync3(outPath) ? readFileSync2(outPath, "utf-8") : null;
|
|
2595
|
+
if (Object.keys(result.routes).length === 0) {
|
|
2596
|
+
if (!existing) {
|
|
2597
|
+
const emptySource = generateRouteTypesSource({});
|
|
2598
|
+
writeFileSync(outPath, emptySource);
|
|
2599
|
+
}
|
|
2600
|
+
continue;
|
|
2601
|
+
}
|
|
2602
|
+
const hasSearchSchemas = Object.keys(result.searchSchemas).length > 0;
|
|
2603
|
+
const source = generateRouteTypesSource(
|
|
2604
|
+
result.routes,
|
|
2605
|
+
hasSearchSchemas ? result.searchSchemas : void 0
|
|
2606
|
+
);
|
|
2607
|
+
if (existing !== source) {
|
|
2608
|
+
if (opts?.preserveIfLarger && existing) {
|
|
2609
|
+
const existingCount = countPublicRouteEntries(existing);
|
|
2610
|
+
const newCount = Object.keys(result.routes).filter(
|
|
2611
|
+
(name) => !isAutoGeneratedRouteName(name)
|
|
2612
|
+
).length;
|
|
2613
|
+
if (existingCount > newCount) {
|
|
2614
|
+
continue;
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
writeFileSync(outPath, source);
|
|
2618
|
+
console.log(
|
|
2619
|
+
`[rsc-router] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
// src/vite/plugins/version-plugin.ts
|
|
2626
|
+
import { parseAst as parseAst3 } from "vite";
|
|
2627
|
+
function isCodeModule(id) {
|
|
2628
|
+
return /\.(tsx?|jsx?)($|\?)/.test(id);
|
|
2629
|
+
}
|
|
2630
|
+
function normalizeModuleId(id) {
|
|
2631
|
+
return id.split("?", 1)[0];
|
|
2632
|
+
}
|
|
2633
|
+
function getClientModuleSignature(source) {
|
|
2634
|
+
let program;
|
|
2635
|
+
try {
|
|
2636
|
+
program = parseAst3(source, { jsx: true });
|
|
2637
|
+
} catch {
|
|
2638
|
+
return void 0;
|
|
2639
|
+
}
|
|
2640
|
+
let isUseClient = false;
|
|
2641
|
+
for (const node of program.body ?? []) {
|
|
2642
|
+
if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
|
|
2643
|
+
if (node.expression.value === "use client") {
|
|
2644
|
+
isUseClient = true;
|
|
2645
|
+
}
|
|
2646
|
+
continue;
|
|
2647
|
+
}
|
|
2648
|
+
break;
|
|
2649
|
+
}
|
|
2650
|
+
if (!isUseClient) return void 0;
|
|
2651
|
+
const exports = /* @__PURE__ */ new Set();
|
|
2652
|
+
let hasDefault = false;
|
|
2653
|
+
let hasExportAll = false;
|
|
2654
|
+
const collectBindingNames = (pattern) => {
|
|
2655
|
+
if (!pattern) return;
|
|
2656
|
+
if (pattern.type === "Identifier") {
|
|
2657
|
+
exports.add(pattern.name);
|
|
2658
|
+
} else if (pattern.type === "ObjectPattern") {
|
|
2659
|
+
for (const prop of pattern.properties ?? []) {
|
|
2660
|
+
if (prop?.type === "RestElement") {
|
|
2661
|
+
collectBindingNames(prop.argument);
|
|
2662
|
+
} else {
|
|
2663
|
+
collectBindingNames(prop?.value);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
} else if (pattern.type === "ArrayPattern") {
|
|
2667
|
+
for (const el of pattern.elements ?? []) {
|
|
2668
|
+
if (el?.type === "RestElement") {
|
|
2669
|
+
collectBindingNames(el.argument);
|
|
2670
|
+
} else {
|
|
2671
|
+
collectBindingNames(el);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
};
|
|
2676
|
+
const collectDeclarationNames = (declaration) => {
|
|
2677
|
+
if (!declaration) return;
|
|
2678
|
+
if (declaration.type === "VariableDeclaration") {
|
|
2679
|
+
for (const decl of declaration.declarations ?? []) {
|
|
2680
|
+
collectBindingNames(decl?.id);
|
|
2681
|
+
}
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
collectBindingNames(declaration.id);
|
|
2685
|
+
};
|
|
2686
|
+
for (const node of program.body ?? []) {
|
|
2687
|
+
if (node?.type === "ExportDefaultDeclaration") {
|
|
2688
|
+
hasDefault = true;
|
|
2689
|
+
continue;
|
|
2690
|
+
}
|
|
2691
|
+
if (node?.type === "ExportAllDeclaration") {
|
|
2692
|
+
hasExportAll = true;
|
|
2693
|
+
continue;
|
|
2694
|
+
}
|
|
2695
|
+
if (node?.type !== "ExportNamedDeclaration") continue;
|
|
2696
|
+
collectDeclarationNames(node.declaration);
|
|
2697
|
+
for (const specifier of node.specifiers ?? []) {
|
|
2698
|
+
const exportedName = specifier?.exported?.name ?? specifier?.exported?.value;
|
|
2699
|
+
if (exportedName === "default") {
|
|
2700
|
+
hasDefault = true;
|
|
2701
|
+
} else if (typeof exportedName === "string") {
|
|
2702
|
+
exports.add(exportedName);
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
return {
|
|
2707
|
+
key: JSON.stringify({
|
|
2708
|
+
default: hasDefault,
|
|
2709
|
+
exportAll: hasExportAll,
|
|
2710
|
+
exports: [...exports].sort()
|
|
2711
|
+
})
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
function createVersionPlugin() {
|
|
2715
|
+
const buildVersion = Date.now().toString(16);
|
|
2716
|
+
let currentVersion = buildVersion;
|
|
2717
|
+
let isDev = false;
|
|
2718
|
+
let server = null;
|
|
2719
|
+
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
2720
|
+
const bumpVersion = (reason) => {
|
|
2721
|
+
currentVersion = Date.now().toString(16);
|
|
2722
|
+
console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
|
|
2723
|
+
const rscEnv = server?.environments?.rsc;
|
|
2724
|
+
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
2725
|
+
"\0" + VIRTUAL_IDS.version
|
|
2726
|
+
);
|
|
2727
|
+
if (versionMod) {
|
|
2728
|
+
rscEnv.moduleGraph.invalidateModule(versionMod);
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
return {
|
|
2732
|
+
name: "@rangojs/router:version",
|
|
2733
|
+
enforce: "pre",
|
|
2734
|
+
configResolved(config) {
|
|
2735
|
+
isDev = config.command === "serve";
|
|
2736
|
+
},
|
|
2737
|
+
configureServer(devServer) {
|
|
2738
|
+
server = devServer;
|
|
2739
|
+
devServer.watcher.on("unlink", (filePath) => {
|
|
2740
|
+
if (!isDev) return;
|
|
2741
|
+
if (!clientModuleSignatures.has(filePath)) return;
|
|
2742
|
+
clientModuleSignatures.delete(filePath);
|
|
2743
|
+
bumpVersion("Client module removed");
|
|
2744
|
+
});
|
|
2745
|
+
},
|
|
2746
|
+
resolveId(id) {
|
|
2747
|
+
if (id === VIRTUAL_IDS.version) {
|
|
2748
|
+
return "\0" + id;
|
|
2749
|
+
}
|
|
2750
|
+
return null;
|
|
2751
|
+
},
|
|
2752
|
+
load(id) {
|
|
2753
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
2754
|
+
return getVirtualVersionContent(currentVersion);
|
|
2755
|
+
}
|
|
2756
|
+
return null;
|
|
2757
|
+
},
|
|
2758
|
+
transform(code, id) {
|
|
2759
|
+
if (!isDev || !isCodeModule(id)) return null;
|
|
2760
|
+
const normalizedId = normalizeModuleId(id);
|
|
2761
|
+
if (!code.includes("use client") && !clientModuleSignatures.has(normalizedId)) {
|
|
2762
|
+
return null;
|
|
2763
|
+
}
|
|
2764
|
+
const signature = getClientModuleSignature(code);
|
|
2765
|
+
if (signature) {
|
|
2766
|
+
clientModuleSignatures.set(normalizedId, signature);
|
|
2767
|
+
} else {
|
|
2768
|
+
clientModuleSignatures.delete(normalizedId);
|
|
2769
|
+
}
|
|
2770
|
+
return null;
|
|
2771
|
+
},
|
|
2772
|
+
// Track RSC module changes and update version
|
|
2773
|
+
async hotUpdate(ctx) {
|
|
2774
|
+
if (!isDev) return;
|
|
2775
|
+
const isRscModule = this.environment?.name === "rsc";
|
|
2776
|
+
if (!isRscModule) return;
|
|
2777
|
+
if (isCodeModule(ctx.file)) {
|
|
2778
|
+
const filePath = normalizeModuleId(ctx.file);
|
|
2779
|
+
const previousSignature = clientModuleSignatures.get(filePath);
|
|
2780
|
+
try {
|
|
2781
|
+
const source = await ctx.read();
|
|
2782
|
+
const nextSignature = getClientModuleSignature(source);
|
|
2783
|
+
if (nextSignature) {
|
|
2784
|
+
clientModuleSignatures.set(filePath, nextSignature);
|
|
2785
|
+
if (previousSignature && previousSignature.key === nextSignature.key) {
|
|
2786
|
+
return;
|
|
2787
|
+
}
|
|
2788
|
+
} else {
|
|
2789
|
+
clientModuleSignatures.delete(filePath);
|
|
2790
|
+
if (!previousSignature) {
|
|
2791
|
+
if (ctx.modules.length === 0) return;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
} catch {
|
|
2795
|
+
}
|
|
2796
|
+
} else {
|
|
2797
|
+
if (ctx.modules.length === 0) return;
|
|
2798
|
+
}
|
|
2799
|
+
bumpVersion("RSC module changed");
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
// src/vite/utils/shared-utils.ts
|
|
2805
|
+
import * as Vite from "vite";
|
|
2806
|
+
var versionEsbuildPlugin = {
|
|
2807
|
+
name: "@rangojs/router-version",
|
|
2808
|
+
setup(build) {
|
|
2809
|
+
build.onResolve({ filter: /^rsc-router:version$/ }, (args) => ({
|
|
2810
|
+
path: args.path,
|
|
2811
|
+
namespace: "@rangojs/router-virtual"
|
|
2812
|
+
}));
|
|
2813
|
+
build.onLoad(
|
|
2814
|
+
{ filter: /.*/, namespace: "@rangojs/router-virtual" },
|
|
2815
|
+
() => ({
|
|
2816
|
+
contents: `export const VERSION = "dev";`,
|
|
2817
|
+
loader: "js"
|
|
2818
|
+
})
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
var sharedEsbuildOptions = {
|
|
2823
|
+
plugins: [versionEsbuildPlugin]
|
|
2824
|
+
};
|
|
2825
|
+
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
2826
|
+
const virtualModules = {};
|
|
2827
|
+
if (entries.client === VIRTUAL_IDS.browser) {
|
|
2828
|
+
virtualModules[VIRTUAL_IDS.browser] = VIRTUAL_ENTRY_BROWSER;
|
|
2829
|
+
}
|
|
2830
|
+
if (entries.ssr === VIRTUAL_IDS.ssr) {
|
|
2831
|
+
virtualModules[VIRTUAL_IDS.ssr] = VIRTUAL_ENTRY_SSR;
|
|
2832
|
+
}
|
|
2833
|
+
const knownIds = new Set(Object.keys(virtualModules));
|
|
2834
|
+
if (entries.rsc === VIRTUAL_IDS.rsc) {
|
|
2835
|
+
knownIds.add(VIRTUAL_IDS.rsc);
|
|
2836
|
+
}
|
|
2837
|
+
return {
|
|
2838
|
+
name: "@rangojs/router:virtual-entries",
|
|
2839
|
+
enforce: "pre",
|
|
2840
|
+
resolveId(id) {
|
|
2841
|
+
if (knownIds.has(id)) {
|
|
2842
|
+
return "\0" + id;
|
|
2843
|
+
}
|
|
2844
|
+
if (id.startsWith("\0") && knownIds.has(id.slice(1))) {
|
|
2845
|
+
return id;
|
|
2846
|
+
}
|
|
2847
|
+
return null;
|
|
2848
|
+
},
|
|
2849
|
+
load(id) {
|
|
2850
|
+
if (id.startsWith("\0virtual:rsc-router/")) {
|
|
2851
|
+
const virtualId = id.slice(1);
|
|
2852
|
+
if (virtualId in virtualModules) {
|
|
2853
|
+
return virtualModules[virtualId];
|
|
2854
|
+
}
|
|
2855
|
+
if (virtualId === VIRTUAL_IDS.rsc && routerPathRef?.path) {
|
|
2856
|
+
const raw = routerPathRef.path.startsWith(".") ? "/" + routerPathRef.path.slice(2) : routerPathRef.path;
|
|
2857
|
+
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
2858
|
+
return getVirtualEntryRSC(absoluteRouterPath);
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
return null;
|
|
2862
|
+
}
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
function onwarn(warning, defaultHandler) {
|
|
2866
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.code === "SOURCEMAP_ERROR" || warning.code === "EMPTY_BUNDLE") {
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
if (warning.plugin === "vite:reporter" && warning.message?.includes(
|
|
2873
|
+
"dynamic import will not move module into another chunk"
|
|
2874
|
+
)) {
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
defaultHandler(warning);
|
|
2878
|
+
}
|
|
2879
|
+
function getManualChunks(id) {
|
|
2880
|
+
const normalized = Vite.normalizePath(id);
|
|
2881
|
+
if (normalized.includes("node_modules/react/") || normalized.includes("node_modules/react-dom/") || normalized.includes("node_modules/react-server-dom-webpack/") || normalized.includes("node_modules/@vitejs/plugin-rsc/")) {
|
|
2882
|
+
return "react";
|
|
2883
|
+
}
|
|
2884
|
+
const packageName = getPublishedPackageName();
|
|
2885
|
+
if (normalized.includes(`node_modules/${packageName}/`) || normalized.includes("packages/rsc-router/") || normalized.includes("packages/rangojs-router/")) {
|
|
2886
|
+
return "router";
|
|
2887
|
+
}
|
|
2888
|
+
return void 0;
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
// src/vite/utils/banner.ts
|
|
2892
|
+
var rangoVersion = package_default.version;
|
|
2893
|
+
var _bannerPrinted = false;
|
|
2894
|
+
function printBanner(mode, preset, version) {
|
|
2895
|
+
if (_bannerPrinted) return;
|
|
2896
|
+
_bannerPrinted = true;
|
|
2897
|
+
const dim = "\x1B[2m";
|
|
2898
|
+
const bold = "\x1B[1m";
|
|
2899
|
+
const reset = "\x1B[0m";
|
|
2900
|
+
const banner = `
|
|
2901
|
+
${dim} \u2726 \u2726 \u2727. . .${reset}
|
|
2902
|
+
${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2571 \u2726 *${reset}
|
|
2903
|
+
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
2904
|
+
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
2905
|
+
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
|
|
2906
|
+
${dim} ${reset}${bold}\u2550\u2563\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
2907
|
+
${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
|
|
2908
|
+
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
2909
|
+
${dim} * ${reset}${bold}\u2551 \u2560\u2550${reset}${dim} * \u2727. \u2571${reset}
|
|
2910
|
+
${bold}\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
2911
|
+
|
|
2912
|
+
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
2913
|
+
`;
|
|
2914
|
+
console.log(banner);
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
// src/vite/plugins/version-injector.ts
|
|
2918
|
+
import { resolve as resolve4 } from "node:path";
|
|
2919
|
+
import * as Vite2 from "vite";
|
|
2920
|
+
function createVersionInjectorPlugin(rscEntryPath) {
|
|
2921
|
+
let resolvedEntryPath = "";
|
|
2922
|
+
return {
|
|
2923
|
+
name: "@rangojs/router:version-injector",
|
|
2924
|
+
enforce: "pre",
|
|
2925
|
+
configResolved(config) {
|
|
2926
|
+
let entryPath = rscEntryPath;
|
|
2927
|
+
if (!entryPath) {
|
|
2928
|
+
const rscEnvConfig = config.environments?.["rsc"];
|
|
2929
|
+
const entries = rscEnvConfig?.optimizeDeps?.entries;
|
|
2930
|
+
if (typeof entries === "string") {
|
|
2931
|
+
entryPath = entries;
|
|
2932
|
+
} else if (Array.isArray(entries) && entries.length > 0) {
|
|
2933
|
+
entryPath = entries[0];
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
if (entryPath) {
|
|
2937
|
+
resolvedEntryPath = resolve4(config.root, entryPath);
|
|
2938
|
+
}
|
|
2939
|
+
},
|
|
2940
|
+
transform(code, id) {
|
|
2941
|
+
if (!resolvedEntryPath) return null;
|
|
2942
|
+
const normalizedId = Vite2.normalizePath(id);
|
|
2943
|
+
const normalizedEntry = Vite2.normalizePath(resolvedEntryPath);
|
|
2944
|
+
if (normalizedId !== normalizedEntry) {
|
|
2945
|
+
return null;
|
|
2946
|
+
}
|
|
2947
|
+
const prepend = [];
|
|
2948
|
+
let newCode = code;
|
|
2949
|
+
if (!code.includes("virtual:rsc-router/routes-manifest")) {
|
|
2950
|
+
prepend.push(`import "virtual:rsc-router/routes-manifest";`);
|
|
2951
|
+
}
|
|
2952
|
+
const needsVersion = code.includes("createRSCHandler") && !code.includes("@rangojs/router:version") && /createRSCHandler\s*\(\s*\{/.test(code);
|
|
2953
|
+
if (needsVersion) {
|
|
2954
|
+
prepend.push(`import { VERSION } from "@rangojs/router:version";`);
|
|
2955
|
+
newCode = newCode.replace(
|
|
2956
|
+
/createRSCHandler\s*\(\s*\{/,
|
|
2957
|
+
"createRSCHandler({\n version: VERSION,"
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
if (prepend.length === 0 && newCode === code) return null;
|
|
2961
|
+
newCode = prepend.join("\n") + (prepend.length > 0 ? "\n" : "") + newCode;
|
|
2962
|
+
return {
|
|
2963
|
+
code: newCode,
|
|
2964
|
+
map: null
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
// src/vite/plugins/cjs-to-esm.ts
|
|
2971
|
+
function createCjsToEsmPlugin() {
|
|
2972
|
+
return {
|
|
2973
|
+
name: "@rangojs/router:cjs-to-esm",
|
|
2974
|
+
enforce: "pre",
|
|
2975
|
+
transform(code, id) {
|
|
2976
|
+
const cleanId = id.split("?")[0];
|
|
2977
|
+
if (cleanId.includes("vendor/react-server-dom/client.browser.js") || cleanId.includes("vendor\\react-server-dom\\client.browser.js")) {
|
|
2978
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
2979
|
+
const cjsFile = isProd ? "./cjs/react-server-dom-webpack-client.browser.production.js" : "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
2980
|
+
return {
|
|
2981
|
+
code: `export * from "${cjsFile}";`,
|
|
2982
|
+
map: null
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
if ((cleanId.includes("vendor/react-server-dom/cjs/") || cleanId.includes("vendor\\react-server-dom\\cjs\\")) && cleanId.includes("client.browser")) {
|
|
2986
|
+
let transformed = code;
|
|
2987
|
+
const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
|
|
2988
|
+
const license = licenseMatch ? licenseMatch[0] : "";
|
|
2989
|
+
if (license) {
|
|
2990
|
+
transformed = transformed.slice(license.length);
|
|
2991
|
+
}
|
|
2992
|
+
transformed = transformed.replace(/^\s*["']use strict["'];\s*/, "");
|
|
2993
|
+
transformed = transformed.replace(
|
|
2994
|
+
/^\s*["']production["']\s*!==\s*process\.env\.NODE_ENV\s*&&\s*\(function\s*\(\)\s*\{/,
|
|
2995
|
+
""
|
|
2996
|
+
);
|
|
2997
|
+
transformed = transformed.replace(/\}\)\(\);?\s*$/, "");
|
|
2998
|
+
transformed = transformed.replace(
|
|
2999
|
+
/var\s+React\s*=\s*require\s*\(\s*["']react["']\s*\)\s*,[\s\n]+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
3000
|
+
'import React from "react";\nimport ReactDOM from "react-dom";\nvar '
|
|
3001
|
+
);
|
|
3002
|
+
transformed = transformed.replace(
|
|
3003
|
+
/var\s+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
3004
|
+
'import ReactDOM from "react-dom";\nvar '
|
|
3005
|
+
);
|
|
3006
|
+
transformed = transformed.replace(
|
|
3007
|
+
/exports\.(\w+)\s*=\s*function\s*\(/g,
|
|
3008
|
+
"export function $1("
|
|
3009
|
+
);
|
|
3010
|
+
transformed = transformed.replace(
|
|
3011
|
+
/exports\.(\w+)\s*=/g,
|
|
3012
|
+
"export const $1 ="
|
|
3013
|
+
);
|
|
3014
|
+
transformed = license + "\n" + transformed;
|
|
3015
|
+
return {
|
|
3016
|
+
code: transformed,
|
|
3017
|
+
map: null
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
return null;
|
|
3021
|
+
}
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
// src/vite/router-discovery.ts
|
|
3026
|
+
import { createServer as createViteServer } from "vite";
|
|
3027
|
+
import { resolve as resolve8 } from "node:path";
|
|
3028
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3029
|
+
|
|
3030
|
+
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3031
|
+
function createVirtualStubPlugin() {
|
|
3032
|
+
const STUB_PREFIXES = [
|
|
3033
|
+
"virtual:rsc-router/",
|
|
3034
|
+
"virtual:entry-",
|
|
3035
|
+
"virtual:vite-rsc/"
|
|
3036
|
+
];
|
|
3037
|
+
return {
|
|
3038
|
+
name: "@rangojs/router:virtual-stubs",
|
|
3039
|
+
resolveId(id) {
|
|
3040
|
+
if (STUB_PREFIXES.some((p) => id.startsWith(p))) {
|
|
3041
|
+
return "\0stub:" + id;
|
|
3042
|
+
}
|
|
3043
|
+
return null;
|
|
3044
|
+
},
|
|
3045
|
+
load(id) {
|
|
3046
|
+
if (id.startsWith("\0stub:")) {
|
|
3047
|
+
return "export default {}";
|
|
3048
|
+
}
|
|
3049
|
+
return null;
|
|
3050
|
+
}
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
// src/vite/plugins/client-ref-hashing.ts
|
|
3055
|
+
import { relative as relative2 } from "node:path";
|
|
3056
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3057
|
+
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3058
|
+
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
3059
|
+
var FS_PREFIX = "/@fs/";
|
|
3060
|
+
function computeProductionHash(projectRoot, refKey) {
|
|
3061
|
+
let toHash;
|
|
3062
|
+
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
3063
|
+
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
3064
|
+
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
3065
|
+
const absPath = decodeURIComponent(
|
|
3066
|
+
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3067
|
+
);
|
|
3068
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3069
|
+
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3070
|
+
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3071
|
+
toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
|
|
3072
|
+
} else if (refKey.startsWith("/")) {
|
|
3073
|
+
toHash = refKey.slice(1);
|
|
3074
|
+
} else {
|
|
3075
|
+
return refKey;
|
|
3076
|
+
}
|
|
3077
|
+
return createHash2("sha256").update(toHash).digest("hex").slice(0, 12);
|
|
3078
|
+
}
|
|
3079
|
+
var REGISTER_CLIENT_REF_RE = /registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
3080
|
+
function transformClientRefs(code, projectRoot) {
|
|
3081
|
+
if (!code.includes("registerClientReference")) return null;
|
|
3082
|
+
let hasReplacement = false;
|
|
3083
|
+
const result = code.replace(
|
|
3084
|
+
REGISTER_CLIENT_REF_RE,
|
|
3085
|
+
(match, refKey) => {
|
|
3086
|
+
const hash = computeProductionHash(projectRoot, refKey);
|
|
3087
|
+
if (hash === refKey) return match;
|
|
3088
|
+
hasReplacement = true;
|
|
3089
|
+
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
3090
|
+
}
|
|
3091
|
+
);
|
|
3092
|
+
return hasReplacement ? result : null;
|
|
3093
|
+
}
|
|
3094
|
+
function hashClientRefs(projectRoot) {
|
|
3095
|
+
return {
|
|
3096
|
+
name: "@rangojs/router:hash-client-refs",
|
|
3097
|
+
// Run after the RSC plugin's transform (default enforce is normal)
|
|
3098
|
+
enforce: "post",
|
|
3099
|
+
applyToEnvironment(env) {
|
|
3100
|
+
return env.name === "rsc";
|
|
3101
|
+
},
|
|
3102
|
+
transform(code, _id) {
|
|
3103
|
+
const result = transformClientRefs(code, projectRoot);
|
|
3104
|
+
if (result === null) return;
|
|
3105
|
+
return { code: result, map: null };
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
2767
3108
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
}
|
|
2778
|
-
} catch {
|
|
3109
|
+
|
|
3110
|
+
// src/vite/utils/bundle-analysis.ts
|
|
3111
|
+
function findMatchingParenInBundle(code, openParenPos) {
|
|
3112
|
+
let depth = 1;
|
|
3113
|
+
let pos = openParenPos;
|
|
3114
|
+
while (pos < code.length && depth > 0) {
|
|
3115
|
+
const skipped = skipStringOrComment(code, pos);
|
|
3116
|
+
if (skipped > pos) {
|
|
3117
|
+
pos = skipped;
|
|
2779
3118
|
continue;
|
|
2780
3119
|
}
|
|
3120
|
+
if (code[pos] === "(") depth++;
|
|
3121
|
+
else if (code[pos] === ")") depth--;
|
|
3122
|
+
pos++;
|
|
2781
3123
|
}
|
|
2782
|
-
return
|
|
3124
|
+
return depth === 0 ? pos : -1;
|
|
2783
3125
|
}
|
|
2784
|
-
function
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
`[
|
|
3126
|
+
function extractHandlerExportsFromChunk(chunkCode, handlerModules, fnName, detectPassthrough) {
|
|
3127
|
+
const handlers = [];
|
|
3128
|
+
for (const [, handlerNames] of handlerModules) {
|
|
3129
|
+
for (const name of handlerNames) {
|
|
3130
|
+
const eName = escapeRegExp(name);
|
|
3131
|
+
const idPattern = new RegExp(
|
|
3132
|
+
`(?<![a-zA-Z0-9_])${eName}\\.\\$\\$id\\s*=\\s*"([^"]+)"`
|
|
2791
3133
|
);
|
|
3134
|
+
const match = chunkCode.match(idPattern);
|
|
3135
|
+
if (!match) continue;
|
|
3136
|
+
let isPassthrough = false;
|
|
3137
|
+
if (detectPassthrough) {
|
|
3138
|
+
const eFnName = escapeRegExp(fnName);
|
|
3139
|
+
const callStartRe = new RegExp(
|
|
3140
|
+
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
3141
|
+
);
|
|
3142
|
+
const callStart = callStartRe.exec(chunkCode);
|
|
3143
|
+
if (callStart) {
|
|
3144
|
+
const afterOpen = callStart.index + callStart[0].length;
|
|
3145
|
+
const closePos = findMatchingParenInBundle(chunkCode, afterOpen);
|
|
3146
|
+
if (closePos !== -1) {
|
|
3147
|
+
const callBody = chunkCode.slice(callStart.index, closePos);
|
|
3148
|
+
isPassthrough = /passthrough\s*:\s*(!0|true)/.test(callBody);
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
handlers.push({ name, handlerId: match[1], passthrough: isPassthrough });
|
|
2792
3153
|
}
|
|
2793
|
-
} catch {
|
|
2794
3154
|
}
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
const
|
|
2805
|
-
|
|
2806
|
-
let result;
|
|
2807
|
-
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
2808
|
-
if (imported) {
|
|
2809
|
-
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2810
|
-
if (!targetFile) continue;
|
|
2811
|
-
result = buildCombinedRouteMapWithSearch(
|
|
2812
|
-
targetFile,
|
|
2813
|
-
imported.exportedName
|
|
2814
|
-
);
|
|
2815
|
-
} else {
|
|
2816
|
-
result = buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2817
|
-
}
|
|
2818
|
-
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2819
|
-
/\.(tsx?|jsx?)$/,
|
|
2820
|
-
""
|
|
2821
|
-
);
|
|
2822
|
-
const outPath = join2(
|
|
2823
|
-
dirname2(routerFilePath),
|
|
2824
|
-
`${routerBasename}.named-routes.gen.ts`
|
|
3155
|
+
return handlers;
|
|
3156
|
+
}
|
|
3157
|
+
function evictHandlerCode(code, exports, fnName, brand) {
|
|
3158
|
+
const originalSize = Buffer.byteLength(code);
|
|
3159
|
+
let modified = code;
|
|
3160
|
+
const eFnName = escapeRegExp(fnName);
|
|
3161
|
+
for (const { name, handlerId, passthrough } of exports) {
|
|
3162
|
+
if (passthrough) continue;
|
|
3163
|
+
const eName = escapeRegExp(name);
|
|
3164
|
+
const callStartRe = new RegExp(
|
|
3165
|
+
`const\\s+${eName}\\s*=\\s*${eFnName}\\s*(?:<[^>]*>)?\\s*\\(`
|
|
2825
3166
|
);
|
|
2826
|
-
const
|
|
2827
|
-
if (
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
const
|
|
2836
|
-
|
|
2837
|
-
|
|
3167
|
+
const startMatch = callStartRe.exec(modified);
|
|
3168
|
+
if (!startMatch) continue;
|
|
3169
|
+
const afterOpen = startMatch.index + startMatch[0].length;
|
|
3170
|
+
const closePos = findMatchingParenInBundle(modified, afterOpen);
|
|
3171
|
+
if (closePos === -1) continue;
|
|
3172
|
+
let rangeEnd = closePos;
|
|
3173
|
+
while (rangeEnd < modified.length && /\s/.test(modified[rangeEnd]))
|
|
3174
|
+
rangeEnd++;
|
|
3175
|
+
if (modified[rangeEnd] === ";") rangeEnd++;
|
|
3176
|
+
const matched = modified.slice(startMatch.index, rangeEnd);
|
|
3177
|
+
if (!matched.includes(handlerId)) continue;
|
|
3178
|
+
const stub = `const ${name} = { __brand: "${brand}", $$id: "${handlerId}" };`;
|
|
3179
|
+
modified = modified.slice(0, startMatch.index) + stub + modified.slice(rangeEnd);
|
|
3180
|
+
modified = modified.replace(
|
|
3181
|
+
new RegExp(`\\n${eName}\\.\\$\\$id\\s*=\\s*"[^"]+";`),
|
|
3182
|
+
""
|
|
2838
3183
|
);
|
|
2839
|
-
if (existing !== source) {
|
|
2840
|
-
if (opts?.preserveIfLarger && existing) {
|
|
2841
|
-
const existingCount = (existing.match(/^\s+["a-zA-Z_$][^:]*:\s*["{]/gm) || []).length;
|
|
2842
|
-
const newCount = Object.keys(result.routes).length;
|
|
2843
|
-
if (existingCount > newCount) {
|
|
2844
|
-
continue;
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
writeFileSync(outPath, source);
|
|
2848
|
-
console.log(
|
|
2849
|
-
`[rsc-router] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
|
|
2850
|
-
);
|
|
2851
|
-
}
|
|
2852
3184
|
}
|
|
3185
|
+
if (modified === code) return null;
|
|
3186
|
+
return {
|
|
3187
|
+
code: modified,
|
|
3188
|
+
savedBytes: originalSize - Buffer.byteLength(modified)
|
|
3189
|
+
};
|
|
2853
3190
|
}
|
|
2854
3191
|
|
|
2855
3192
|
// src/vite/discovery/state.ts
|
|
@@ -2870,8 +3207,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
2870
3207
|
perRouterTrieMap: /* @__PURE__ */ new Map(),
|
|
2871
3208
|
perRouterPrecomputedMap: /* @__PURE__ */ new Map(),
|
|
2872
3209
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
2873
|
-
|
|
2874
|
-
|
|
3210
|
+
prerenderManifestEntries: null,
|
|
3211
|
+
staticManifestEntries: null,
|
|
2875
3212
|
handlerChunkInfo: null,
|
|
2876
3213
|
staticHandlerChunkInfo: null,
|
|
2877
3214
|
rscEntryFileName: null,
|
|
@@ -2913,6 +3250,48 @@ function consumeSelfGenWrite(state, filePath) {
|
|
|
2913
3250
|
}
|
|
2914
3251
|
}
|
|
2915
3252
|
|
|
3253
|
+
// src/vite/utils/manifest-utils.ts
|
|
3254
|
+
function flattenLeafEntries(prefixTree, routeManifest, result) {
|
|
3255
|
+
function visit(node) {
|
|
3256
|
+
const children = node.children || {};
|
|
3257
|
+
if (Object.keys(children).length === 0 && node.routes && node.routes.length > 0) {
|
|
3258
|
+
const routes = {};
|
|
3259
|
+
for (const name of node.routes) {
|
|
3260
|
+
if (name in routeManifest) {
|
|
3261
|
+
routes[name] = routeManifest[name];
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
3265
|
+
} else {
|
|
3266
|
+
for (const child of Object.values(children)) {
|
|
3267
|
+
visit(child);
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
for (const node of Object.values(prefixTree)) {
|
|
3272
|
+
visit(node);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
function buildRouteToStaticPrefix(prefixTree, result) {
|
|
3276
|
+
function visit(node) {
|
|
3277
|
+
const sp = node.staticPrefix || "";
|
|
3278
|
+
for (const name of node.routes || []) {
|
|
3279
|
+
result[name] = sp;
|
|
3280
|
+
}
|
|
3281
|
+
for (const child of Object.values(node.children || {})) {
|
|
3282
|
+
visit(child);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
for (const node of Object.values(prefixTree)) {
|
|
3286
|
+
visit(node);
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
function jsonParseExpression(value) {
|
|
3290
|
+
const json = JSON.stringify(value);
|
|
3291
|
+
const escaped = json.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
3292
|
+
return `JSON.parse('${escaped}')`;
|
|
3293
|
+
}
|
|
3294
|
+
|
|
2916
3295
|
// src/context-var.ts
|
|
2917
3296
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2918
3297
|
function contextSet(variables, keyOrVar, value) {
|
|
@@ -2922,11 +3301,132 @@ function contextSet(variables, keyOrVar, value) {
|
|
|
2922
3301
|
`ctx.set(): "${keyOrVar}" is a reserved key and cannot be used as a variable name.`
|
|
2923
3302
|
);
|
|
2924
3303
|
}
|
|
2925
|
-
variables[keyOrVar] = value;
|
|
2926
|
-
} else {
|
|
2927
|
-
variables[keyOrVar.key] = value;
|
|
3304
|
+
variables[keyOrVar] = value;
|
|
3305
|
+
} else {
|
|
3306
|
+
variables[keyOrVar.key] = value;
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
// src/vite/utils/prerender-utils.ts
|
|
3311
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
3312
|
+
import {
|
|
3313
|
+
copyFileSync,
|
|
3314
|
+
existsSync as existsSync4,
|
|
3315
|
+
mkdirSync,
|
|
3316
|
+
rmSync,
|
|
3317
|
+
statSync,
|
|
3318
|
+
writeFileSync as writeFileSync2
|
|
3319
|
+
} from "node:fs";
|
|
3320
|
+
import { resolve as resolve5 } from "node:path";
|
|
3321
|
+
function escapeRegExp2(str) {
|
|
3322
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3323
|
+
}
|
|
3324
|
+
function encodePathParam(value) {
|
|
3325
|
+
return String(value).split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
3326
|
+
}
|
|
3327
|
+
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3328
|
+
let result = pattern;
|
|
3329
|
+
for (const [key, value] of Object.entries(params)) {
|
|
3330
|
+
const escaped = escapeRegExp2(key);
|
|
3331
|
+
result = result.replace(
|
|
3332
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
3333
|
+
encode(value)
|
|
3334
|
+
);
|
|
3335
|
+
result = result.replace(`*${key}`, encode(value));
|
|
3336
|
+
}
|
|
3337
|
+
return result;
|
|
3338
|
+
}
|
|
3339
|
+
async function runWithConcurrency(items, concurrency, fn) {
|
|
3340
|
+
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
3341
|
+
if (limit <= 1) {
|
|
3342
|
+
for (const item of items) await fn(item);
|
|
3343
|
+
return;
|
|
3344
|
+
}
|
|
3345
|
+
let nextIndex = 0;
|
|
3346
|
+
async function worker() {
|
|
3347
|
+
while (nextIndex < items.length) {
|
|
3348
|
+
const idx = nextIndex++;
|
|
3349
|
+
await fn(items[idx]);
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
3353
|
+
}
|
|
3354
|
+
function groupByConcurrency(entries) {
|
|
3355
|
+
const map = /* @__PURE__ */ new Map();
|
|
3356
|
+
for (const entry of entries) {
|
|
3357
|
+
const key = entry.concurrency;
|
|
3358
|
+
let group = map.get(key);
|
|
3359
|
+
if (!group) {
|
|
3360
|
+
group = [];
|
|
3361
|
+
map.set(key, group);
|
|
3362
|
+
}
|
|
3363
|
+
group.push(entry);
|
|
3364
|
+
}
|
|
3365
|
+
return Array.from(map.entries(), ([concurrency, items]) => ({
|
|
3366
|
+
concurrency,
|
|
3367
|
+
entries: items
|
|
3368
|
+
}));
|
|
3369
|
+
}
|
|
3370
|
+
function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
|
|
3371
|
+
for (const [, routerInstance] of registry) {
|
|
3372
|
+
const onError = routerInstance.onError;
|
|
3373
|
+
if (!onError) continue;
|
|
3374
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
3375
|
+
const syntheticUrl = new URL("http://prerender" + (pathname || "/"));
|
|
3376
|
+
const context = {
|
|
3377
|
+
error: errorObj,
|
|
3378
|
+
phase,
|
|
3379
|
+
request: new Request(syntheticUrl),
|
|
3380
|
+
url: syntheticUrl,
|
|
3381
|
+
pathname: syntheticUrl.pathname,
|
|
3382
|
+
method: "GET",
|
|
3383
|
+
routeKey,
|
|
3384
|
+
metadata: skipped ? { skipped: true } : void 0
|
|
3385
|
+
};
|
|
3386
|
+
try {
|
|
3387
|
+
const result = onError(context);
|
|
3388
|
+
if (result instanceof Promise) {
|
|
3389
|
+
result.catch((cbErr) => {
|
|
3390
|
+
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
} catch (cbErr) {
|
|
3394
|
+
console.error(`[Build.onError] Callback error:`, cbErr);
|
|
3395
|
+
}
|
|
3396
|
+
break;
|
|
2928
3397
|
}
|
|
2929
3398
|
}
|
|
3399
|
+
function getStagedAssetDir(projectRoot) {
|
|
3400
|
+
return resolve5(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
3401
|
+
}
|
|
3402
|
+
function resetStagedBuildAssets(projectRoot) {
|
|
3403
|
+
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
3404
|
+
}
|
|
3405
|
+
function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
3406
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
3407
|
+
mkdirSync(stagedDir, { recursive: true });
|
|
3408
|
+
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
3409
|
+
const fileName = `${prefix}-${contentHash}.js`;
|
|
3410
|
+
const filePath = resolve5(stagedDir, fileName);
|
|
3411
|
+
if (!existsSync4(filePath)) {
|
|
3412
|
+
writeFileSync2(filePath, `export default ${exportValue};
|
|
3413
|
+
`);
|
|
3414
|
+
}
|
|
3415
|
+
return fileName;
|
|
3416
|
+
}
|
|
3417
|
+
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
3418
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
3419
|
+
const distAssetsDir = resolve5(projectRoot, "dist/rsc/assets");
|
|
3420
|
+
mkdirSync(distAssetsDir, { recursive: true });
|
|
3421
|
+
let totalBytes = 0;
|
|
3422
|
+
for (const fileName of new Set(fileNames)) {
|
|
3423
|
+
const stagedPath = resolve5(stagedDir, fileName);
|
|
3424
|
+
const distPath = resolve5(distAssetsDir, fileName);
|
|
3425
|
+
copyFileSync(stagedPath, distPath);
|
|
3426
|
+
totalBytes += statSync(stagedPath).size;
|
|
3427
|
+
}
|
|
3428
|
+
return totalBytes;
|
|
3429
|
+
}
|
|
2930
3430
|
|
|
2931
3431
|
// src/vite/discovery/prerender-collection.ts
|
|
2932
3432
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
@@ -2939,18 +3439,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
2939
3439
|
const getParamsReverse = (name, params) => {
|
|
2940
3440
|
const pattern = allRoutes[name];
|
|
2941
3441
|
if (!pattern) throw new Error(`Unknown route: "${name}"`);
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
for (const [key, value] of Object.entries(params)) {
|
|
2945
|
-
const escaped = escapeRegExp2(key);
|
|
2946
|
-
result = result.replace(
|
|
2947
|
-
new RegExp(`:${escaped}(\\([^)]*\\))?`),
|
|
2948
|
-
encodeURIComponent(value)
|
|
2949
|
-
);
|
|
2950
|
-
result = result.replace(`*${key}`, encodeURIComponent(value));
|
|
2951
|
-
}
|
|
2952
|
-
}
|
|
2953
|
-
return result;
|
|
3442
|
+
if (!params) return pattern;
|
|
3443
|
+
return substituteRouteParams(pattern, params);
|
|
2954
3444
|
};
|
|
2955
3445
|
for (const { manifest } of allManifests) {
|
|
2956
3446
|
if (!manifest.prerenderRoutes) continue;
|
|
@@ -2958,15 +3448,17 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
2958
3448
|
for (const routeName of manifest.prerenderRoutes) {
|
|
2959
3449
|
const pattern = manifest.routeManifest[routeName];
|
|
2960
3450
|
if (!pattern) continue;
|
|
3451
|
+
const def = defs[routeName];
|
|
3452
|
+
const isPassthroughRoute = !!def?.options?.passthrough;
|
|
2961
3453
|
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
2962
3454
|
if (!hasDynamic) {
|
|
2963
3455
|
entries.push({
|
|
2964
3456
|
urlPath: pattern.replace(/\/$/, "") || "/",
|
|
2965
3457
|
routeName,
|
|
2966
|
-
concurrency: 1
|
|
3458
|
+
concurrency: 1,
|
|
3459
|
+
isPassthroughRoute
|
|
2967
3460
|
});
|
|
2968
3461
|
} else {
|
|
2969
|
-
const def = defs[routeName];
|
|
2970
3462
|
if (def?.getParams) {
|
|
2971
3463
|
try {
|
|
2972
3464
|
const buildVars = {};
|
|
@@ -2981,18 +3473,11 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
2981
3473
|
const concurrency = def.options?.concurrency ?? 1;
|
|
2982
3474
|
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
2983
3475
|
for (const params of paramsList) {
|
|
2984
|
-
let url =
|
|
2985
|
-
|
|
2986
|
-
params
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
const escaped = escapeRegExp2(key);
|
|
2990
|
-
url = url.replace(
|
|
2991
|
-
new RegExp(`:${escaped}(\\([^)]*\\))?`),
|
|
2992
|
-
encoded
|
|
2993
|
-
);
|
|
2994
|
-
url = url.replace(`*${key}`, encoded);
|
|
2995
|
-
}
|
|
3476
|
+
let url = substituteRouteParams(
|
|
3477
|
+
pattern,
|
|
3478
|
+
params,
|
|
3479
|
+
encodePathParam
|
|
3480
|
+
);
|
|
2996
3481
|
if (url.includes("*")) {
|
|
2997
3482
|
const wildcardValue = params["*"] ?? params.splat;
|
|
2998
3483
|
if (wildcardValue !== void 0) {
|
|
@@ -3003,7 +3488,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3003
3488
|
urlPath: url.replace(/\/$/, "") || "/",
|
|
3004
3489
|
routeName,
|
|
3005
3490
|
concurrency,
|
|
3006
|
-
...hasBuildVars ? { buildVars } : {}
|
|
3491
|
+
...hasBuildVars ? { buildVars } : {},
|
|
3492
|
+
isPassthroughRoute
|
|
3007
3493
|
});
|
|
3008
3494
|
}
|
|
3009
3495
|
} catch (err) {
|
|
@@ -3042,7 +3528,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3042
3528
|
`[rsc-router] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
|
|
3043
3529
|
);
|
|
3044
3530
|
const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
|
|
3045
|
-
const
|
|
3531
|
+
const manifestEntries = {};
|
|
3046
3532
|
let doneCount = 0;
|
|
3047
3533
|
let skipCount = 0;
|
|
3048
3534
|
const startTotal = performance.now();
|
|
@@ -3059,22 +3545,43 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3059
3545
|
const result = await routerInstance.matchForPrerender(
|
|
3060
3546
|
entry.urlPath,
|
|
3061
3547
|
{},
|
|
3062
|
-
entry.buildVars
|
|
3548
|
+
entry.buildVars,
|
|
3549
|
+
entry.isPassthroughRoute
|
|
3063
3550
|
);
|
|
3064
3551
|
if (!result) continue;
|
|
3552
|
+
if (result.passthrough) {
|
|
3553
|
+
const elapsed2 = (performance.now() - startUrl).toFixed(0);
|
|
3554
|
+
console.log(
|
|
3555
|
+
`[rsc-router] PASS ${entry.urlPath.padEnd(40)} (${elapsed2}ms) - live fallback`
|
|
3556
|
+
);
|
|
3557
|
+
doneCount++;
|
|
3558
|
+
break;
|
|
3559
|
+
}
|
|
3065
3560
|
const paramHash = hashParams(result.params || {});
|
|
3066
|
-
|
|
3561
|
+
const mainKey = `${result.routeName}/${paramHash}`;
|
|
3562
|
+
const mainValue = JSON.stringify({
|
|
3067
3563
|
segments: result.segments,
|
|
3068
3564
|
handles: result.handles
|
|
3069
|
-
};
|
|
3565
|
+
});
|
|
3566
|
+
manifestEntries[mainKey] = stageBuildAssetModule(
|
|
3567
|
+
state.projectRoot,
|
|
3568
|
+
"__pr",
|
|
3569
|
+
mainValue
|
|
3570
|
+
);
|
|
3070
3571
|
if (result.interceptSegments?.length) {
|
|
3071
|
-
|
|
3572
|
+
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
3573
|
+
const interceptValue = JSON.stringify({
|
|
3072
3574
|
segments: [...result.segments, ...result.interceptSegments],
|
|
3073
3575
|
handles: {
|
|
3074
3576
|
...result.handles,
|
|
3075
3577
|
...result.interceptHandles || {}
|
|
3076
3578
|
}
|
|
3077
|
-
};
|
|
3579
|
+
});
|
|
3580
|
+
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
3581
|
+
state.projectRoot,
|
|
3582
|
+
"__pr",
|
|
3583
|
+
interceptValue
|
|
3584
|
+
);
|
|
3078
3585
|
}
|
|
3079
3586
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3080
3587
|
console.log(
|
|
@@ -3118,7 +3625,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3118
3625
|
}
|
|
3119
3626
|
const totalElapsed = (performance.now() - startTotal).toFixed(0);
|
|
3120
3627
|
if (doneCount > 0) {
|
|
3121
|
-
state.
|
|
3628
|
+
state.prerenderManifestEntries = manifestEntries;
|
|
3122
3629
|
}
|
|
3123
3630
|
const parts = [`${doneCount} done`];
|
|
3124
3631
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
@@ -3129,7 +3636,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3129
3636
|
async function renderStaticHandlers(state, rscEnv, registry) {
|
|
3130
3637
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode || !state.resolvedStaticModules?.size)
|
|
3131
3638
|
return;
|
|
3132
|
-
const
|
|
3639
|
+
const manifestEntries = {};
|
|
3133
3640
|
let staticDone = 0;
|
|
3134
3641
|
let staticSkip = 0;
|
|
3135
3642
|
let totalStaticCount = 0;
|
|
@@ -3166,7 +3673,13 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3166
3673
|
def.$$routePrefix
|
|
3167
3674
|
);
|
|
3168
3675
|
if (result) {
|
|
3169
|
-
|
|
3676
|
+
const hasHandles = Object.keys(result.handles).length > 0;
|
|
3677
|
+
const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
|
|
3678
|
+
manifestEntries[def.$$id] = stageBuildAssetModule(
|
|
3679
|
+
state.projectRoot,
|
|
3680
|
+
"__st",
|
|
3681
|
+
exportValue
|
|
3682
|
+
);
|
|
3170
3683
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
3171
3684
|
console.log(
|
|
3172
3685
|
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
|
|
@@ -3203,7 +3716,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3203
3716
|
}
|
|
3204
3717
|
const totalStaticElapsed = (performance.now() - startStatic).toFixed(0);
|
|
3205
3718
|
if (staticDone > 0) {
|
|
3206
|
-
state.
|
|
3719
|
+
state.staticManifestEntries = manifestEntries;
|
|
3207
3720
|
}
|
|
3208
3721
|
const staticParts = [`${staticDone} done`];
|
|
3209
3722
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
@@ -3220,8 +3733,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3220
3733
|
let registry = serverMod.RouterRegistry;
|
|
3221
3734
|
if (!registry || registry.size === 0) {
|
|
3222
3735
|
try {
|
|
3223
|
-
const
|
|
3224
|
-
const hostRegistry = hostMod.HostRouterRegistry;
|
|
3736
|
+
const hostRegistry = serverMod.HostRouterRegistry;
|
|
3225
3737
|
if (hostRegistry && hostRegistry.size > 0) {
|
|
3226
3738
|
console.log(
|
|
3227
3739
|
`[rsc-router] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
|
|
@@ -3260,22 +3772,30 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3260
3772
|
}
|
|
3261
3773
|
}
|
|
3262
3774
|
const buildMod = await rscEnv.runner.import("@rangojs/router/build");
|
|
3263
|
-
const
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3775
|
+
const generateManifestFull = buildMod.generateManifestFull;
|
|
3776
|
+
const nestedRouterConflict = findNestedRouterConflict(
|
|
3777
|
+
[...registry.values()].map((router) => router.__sourceFile).filter(
|
|
3778
|
+
(sourceFile) => typeof sourceFile === "string"
|
|
3779
|
+
)
|
|
3780
|
+
);
|
|
3781
|
+
if (nestedRouterConflict) {
|
|
3782
|
+
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
3783
|
+
}
|
|
3784
|
+
const newMergedRouteManifest = {};
|
|
3785
|
+
const newMergedPrecomputedEntries = [];
|
|
3786
|
+
const newPerRouterManifests = [];
|
|
3787
|
+
const newPerRouterManifestDataMap = /* @__PURE__ */ new Map();
|
|
3788
|
+
const newPerRouterPrecomputedMap = /* @__PURE__ */ new Map();
|
|
3789
|
+
const newPerRouterTrieMap = /* @__PURE__ */ new Map();
|
|
3270
3790
|
let mergedRouteAncestry = {};
|
|
3271
3791
|
let mergedRouteTrailingSlash = {};
|
|
3272
3792
|
let routerMountIndex = 0;
|
|
3273
3793
|
const allManifests = [];
|
|
3274
3794
|
for (const [id, router] of registry) {
|
|
3275
|
-
if (!router.urlpatterns || !
|
|
3795
|
+
if (!router.urlpatterns || !generateManifestFull) {
|
|
3276
3796
|
continue;
|
|
3277
3797
|
}
|
|
3278
|
-
const manifest =
|
|
3798
|
+
const manifest = generateManifestFull(router.urlpatterns, routerMountIndex);
|
|
3279
3799
|
routerMountIndex++;
|
|
3280
3800
|
allManifests.push({ id, manifest });
|
|
3281
3801
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
@@ -3283,7 +3803,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3283
3803
|
(p) => !p.includes(":") && !p.includes("*")
|
|
3284
3804
|
).length;
|
|
3285
3805
|
const dynamicRoutes = routeCount - staticRoutes;
|
|
3286
|
-
Object.assign(
|
|
3806
|
+
Object.assign(newMergedRouteManifest, manifest.routeManifest);
|
|
3287
3807
|
let factoryOnlyPrefixes;
|
|
3288
3808
|
if (router.__sourceFile) {
|
|
3289
3809
|
const staticParsed = buildCombinedRouteMapForRouterFile(
|
|
@@ -3301,7 +3821,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3301
3821
|
}
|
|
3302
3822
|
if (factoryOnlyPrefixes.size === 0) factoryOnlyPrefixes = void 0;
|
|
3303
3823
|
}
|
|
3304
|
-
|
|
3824
|
+
newPerRouterManifests.push({
|
|
3305
3825
|
id,
|
|
3306
3826
|
routeManifest: manifest.routeManifest,
|
|
3307
3827
|
routeSearchSchemas: manifest.routeSearchSchemas,
|
|
@@ -3317,16 +3837,16 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3317
3837
|
flattenLeafEntries(
|
|
3318
3838
|
manifest.prefixTree,
|
|
3319
3839
|
manifest.routeManifest,
|
|
3320
|
-
|
|
3840
|
+
newMergedPrecomputedEntries
|
|
3321
3841
|
);
|
|
3322
|
-
|
|
3842
|
+
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
3323
3843
|
const routerPrecomputed = [];
|
|
3324
3844
|
flattenLeafEntries(
|
|
3325
3845
|
manifest.prefixTree,
|
|
3326
3846
|
manifest.routeManifest,
|
|
3327
3847
|
routerPrecomputed
|
|
3328
3848
|
);
|
|
3329
|
-
|
|
3849
|
+
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
3330
3850
|
console.log(
|
|
3331
3851
|
`[rsc-router] Router "${id}" -> ${routeCount} routes (${staticRoutes} static, ${dynamicRoutes} dynamic)`
|
|
3332
3852
|
);
|
|
@@ -3341,7 +3861,8 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3341
3861
|
);
|
|
3342
3862
|
}
|
|
3343
3863
|
}
|
|
3344
|
-
|
|
3864
|
+
let newMergedRouteTrie = null;
|
|
3865
|
+
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
3345
3866
|
const buildRouteTrie = buildMod.buildRouteTrie;
|
|
3346
3867
|
if (buildRouteTrie && mergedRouteAncestry) {
|
|
3347
3868
|
const routeToStaticPrefix = {};
|
|
@@ -3371,8 +3892,8 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3371
3892
|
Object.assign(mergedResponseTypeRoutes, manifest.responseTypeRoutes);
|
|
3372
3893
|
}
|
|
3373
3894
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3895
|
+
newMergedRouteTrie = buildRouteTrie(
|
|
3896
|
+
newMergedRouteManifest,
|
|
3376
3897
|
mergedRouteAncestry,
|
|
3377
3898
|
routeToStaticPrefix,
|
|
3378
3899
|
Object.keys(mergedRouteTrailingSlash).length > 0 ? mergedRouteTrailingSlash : void 0,
|
|
@@ -3399,22 +3920,29 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3399
3920
|
perRouterPassthroughNames && perRouterPassthroughNames.size > 0 ? perRouterPassthroughNames : void 0,
|
|
3400
3921
|
manifest.responseTypeRoutes && Object.keys(manifest.responseTypeRoutes).length > 0 ? manifest.responseTypeRoutes : void 0
|
|
3401
3922
|
);
|
|
3402
|
-
|
|
3923
|
+
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
3403
3924
|
}
|
|
3404
3925
|
}
|
|
3405
3926
|
}
|
|
3927
|
+
state.mergedRouteManifest = newMergedRouteManifest;
|
|
3928
|
+
state.mergedPrecomputedEntries = newMergedPrecomputedEntries;
|
|
3929
|
+
state.perRouterManifests = newPerRouterManifests;
|
|
3930
|
+
state.perRouterManifestDataMap = newPerRouterManifestDataMap;
|
|
3931
|
+
state.perRouterPrecomputedMap = newPerRouterPrecomputedMap;
|
|
3932
|
+
state.perRouterTrieMap = newPerRouterTrieMap;
|
|
3933
|
+
state.mergedRouteTrie = newMergedRouteTrie;
|
|
3406
3934
|
await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
|
|
3407
3935
|
await renderStaticHandlers(state, rscEnv, registry);
|
|
3408
3936
|
return serverMod;
|
|
3409
3937
|
}
|
|
3410
3938
|
|
|
3411
3939
|
// src/vite/discovery/route-types-writer.ts
|
|
3412
|
-
import { dirname as dirname3, basename, join as join3, resolve as
|
|
3413
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
3940
|
+
import { dirname as dirname3, basename, join as join3, resolve as resolve6 } from "node:path";
|
|
3941
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
3414
3942
|
function filterUserNamedRoutes(manifest) {
|
|
3415
3943
|
const filtered = {};
|
|
3416
3944
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
3417
|
-
if (!name
|
|
3945
|
+
if (!isAutoGeneratedRouteName(name)) {
|
|
3418
3946
|
filtered[name] = pattern;
|
|
3419
3947
|
}
|
|
3420
3948
|
}
|
|
@@ -3444,7 +3972,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3444
3972
|
""
|
|
3445
3973
|
);
|
|
3446
3974
|
const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3447
|
-
if (!
|
|
3975
|
+
if (!existsSync5(outPath)) continue;
|
|
3448
3976
|
try {
|
|
3449
3977
|
const content = readFileSync4(outPath, "utf-8");
|
|
3450
3978
|
if (content !== preContent.get(outPath)) {
|
|
@@ -3458,10 +3986,10 @@ function writeRouteTypesFiles(state) {
|
|
|
3458
3986
|
if (state.perRouterManifests.length === 0) return;
|
|
3459
3987
|
try {
|
|
3460
3988
|
const entryDir = dirname3(
|
|
3461
|
-
|
|
3989
|
+
resolve6(state.projectRoot, state.resolvedEntryPath)
|
|
3462
3990
|
);
|
|
3463
3991
|
const oldCombinedPath = join3(entryDir, "named-routes.gen.ts");
|
|
3464
|
-
if (
|
|
3992
|
+
if (existsSync5(oldCombinedPath)) {
|
|
3465
3993
|
unlinkSync2(oldCombinedPath);
|
|
3466
3994
|
console.log(
|
|
3467
3995
|
`[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
|
|
@@ -3505,10 +4033,10 @@ Set an explicit \`id\` on createRouter() or check the call site.`
|
|
|
3505
4033
|
userRoutes,
|
|
3506
4034
|
effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
|
|
3507
4035
|
);
|
|
3508
|
-
const existing =
|
|
4036
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
3509
4037
|
if (existing !== source) {
|
|
3510
4038
|
markSelfGenWrite(state, outPath, source);
|
|
3511
|
-
|
|
4039
|
+
writeFileSync3(outPath, source);
|
|
3512
4040
|
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
3513
4041
|
}
|
|
3514
4042
|
}
|
|
@@ -3537,7 +4065,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
3537
4065
|
...staticParsed.searchSchemas
|
|
3538
4066
|
};
|
|
3539
4067
|
for (const [name, pattern] of Object.entries(routeManifest)) {
|
|
3540
|
-
if (name
|
|
4068
|
+
if (isAutoGeneratedRouteName(name)) continue;
|
|
3541
4069
|
const dotIdx = name.indexOf(".");
|
|
3542
4070
|
if (dotIdx <= 0) continue;
|
|
3543
4071
|
const prefix = name.substring(0, dotIdx + 1);
|
|
@@ -3555,10 +4083,10 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
3555
4083
|
mergedRoutes,
|
|
3556
4084
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
3557
4085
|
);
|
|
3558
|
-
const existing =
|
|
4086
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
3559
4087
|
if (existing !== source) {
|
|
3560
4088
|
markSelfGenWrite(state, outPath, source);
|
|
3561
|
-
|
|
4089
|
+
writeFileSync3(outPath, source);
|
|
3562
4090
|
}
|
|
3563
4091
|
}
|
|
3564
4092
|
}
|
|
@@ -3582,7 +4110,7 @@ function generateRoutesManifestModule(state) {
|
|
|
3582
4110
|
const genPath = join4(
|
|
3583
4111
|
routerDir,
|
|
3584
4112
|
`${routerBasename}.named-routes.gen.js`
|
|
3585
|
-
);
|
|
4113
|
+
).replaceAll("\\", "/");
|
|
3586
4114
|
const varName = `_r${varIdx++}`;
|
|
3587
4115
|
genFileImports.push(
|
|
3588
4116
|
`import { NamedRoutes as ${varName} } from ${JSON.stringify(genPath)};`
|
|
@@ -3676,7 +4204,10 @@ function generatePerRouterModule(state, routerId) {
|
|
|
3676
4204
|
/\.(tsx?|jsx?)$/,
|
|
3677
4205
|
""
|
|
3678
4206
|
);
|
|
3679
|
-
const genPath = join4(
|
|
4207
|
+
const genPath = join4(
|
|
4208
|
+
routerDir,
|
|
4209
|
+
`${routerBasename}.named-routes.gen.js`
|
|
4210
|
+
).replaceAll("\\", "/");
|
|
3680
4211
|
lines.push(`import { NamedRoutes as _r } from ${JSON.stringify(genPath)};`);
|
|
3681
4212
|
lines.push(
|
|
3682
4213
|
`function __flat(r) { const o = {}; for (const [k, v] of Object.entries(r)) o[k] = typeof v === "string" ? v : v.path; return o; }`
|
|
@@ -3700,14 +4231,13 @@ function generatePerRouterModule(state, routerId) {
|
|
|
3700
4231
|
}
|
|
3701
4232
|
|
|
3702
4233
|
// src/vite/discovery/bundle-postprocess.ts
|
|
3703
|
-
import { resolve as
|
|
3704
|
-
import {
|
|
3705
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync } from "node:fs";
|
|
4234
|
+
import { resolve as resolve7 } from "node:path";
|
|
4235
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6 } from "node:fs";
|
|
3706
4236
|
function postprocessBundle(state) {
|
|
3707
|
-
const hasPrerenderData = state.
|
|
3708
|
-
const hasStaticData = state.
|
|
4237
|
+
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
4238
|
+
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
3709
4239
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
3710
|
-
const rscEntryPath =
|
|
4240
|
+
const rscEntryPath = resolve7(
|
|
3711
4241
|
state.projectRoot,
|
|
3712
4242
|
"dist/rsc",
|
|
3713
4243
|
state.rscEntryFileName ?? "index.js"
|
|
@@ -3728,7 +4258,7 @@ function postprocessBundle(state) {
|
|
|
3728
4258
|
];
|
|
3729
4259
|
for (const target of evictionTargets) {
|
|
3730
4260
|
if (!target.info) continue;
|
|
3731
|
-
const chunkPath =
|
|
4261
|
+
const chunkPath = resolve7(
|
|
3732
4262
|
state.projectRoot,
|
|
3733
4263
|
"dist/rsc",
|
|
3734
4264
|
target.info.fileName
|
|
@@ -3742,7 +4272,7 @@ function postprocessBundle(state) {
|
|
|
3742
4272
|
target.brand
|
|
3743
4273
|
);
|
|
3744
4274
|
if (result) {
|
|
3745
|
-
|
|
4275
|
+
writeFileSync4(chunkPath, result.code);
|
|
3746
4276
|
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
3747
4277
|
console.log(
|
|
3748
4278
|
`[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${target.info.fileName}`
|
|
@@ -3756,44 +4286,38 @@ function postprocessBundle(state) {
|
|
|
3756
4286
|
}
|
|
3757
4287
|
state.handlerChunkInfo = null;
|
|
3758
4288
|
state.staticHandlerChunkInfo = null;
|
|
3759
|
-
if (hasPrerenderData &&
|
|
4289
|
+
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
3760
4290
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
3761
|
-
if (!rscCode.includes("
|
|
4291
|
+
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
3762
4292
|
try {
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
4293
|
+
let totalBytes = copyStagedBuildAssets(
|
|
4294
|
+
state.projectRoot,
|
|
4295
|
+
Object.values(state.prerenderManifestEntries)
|
|
4296
|
+
);
|
|
4297
|
+
const manifestMap = {};
|
|
4298
|
+
for (const [key, assetFileName] of Object.entries(
|
|
4299
|
+
state.prerenderManifestEntries
|
|
3769
4300
|
)) {
|
|
3770
|
-
|
|
3771
|
-
const contentHash = createHash4("sha256").update(entryJson).digest("hex").slice(0, 8);
|
|
3772
|
-
const assetFileName = `__pr-${contentHash}.js`;
|
|
3773
|
-
const assetPath = resolve6(assetsDir, assetFileName);
|
|
3774
|
-
const assetCode = `export default ${entryJson};
|
|
3775
|
-
`;
|
|
3776
|
-
writeFileSync3(assetPath, assetCode);
|
|
3777
|
-
totalBytes += Buffer.byteLength(assetCode);
|
|
3778
|
-
manifestEntries.push(
|
|
3779
|
-
`${JSON.stringify(key)}:()=>import("./assets/${assetFileName}")`
|
|
3780
|
-
);
|
|
4301
|
+
manifestMap[key] = `./assets/${assetFileName}`;
|
|
3781
4302
|
}
|
|
3782
|
-
const manifestCode =
|
|
3783
|
-
|
|
3784
|
-
|
|
4303
|
+
const manifestCode = [
|
|
4304
|
+
`const m=JSON.parse('${JSON.stringify(manifestMap).replace(/'/g, "\\'")}');`,
|
|
4305
|
+
`export function loadPrerenderAsset(s){return import(s)}`,
|
|
4306
|
+
`export default m;`,
|
|
4307
|
+
""
|
|
4308
|
+
].join("\n");
|
|
4309
|
+
const manifestPath = resolve7(
|
|
3785
4310
|
state.projectRoot,
|
|
3786
4311
|
"dist/rsc/__prerender-manifest.js"
|
|
3787
4312
|
);
|
|
3788
|
-
|
|
4313
|
+
writeFileSync4(manifestPath, manifestCode);
|
|
3789
4314
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
3790
|
-
const injection = `
|
|
3791
|
-
globalThis.__PRERENDER_MANIFEST = __pm;
|
|
4315
|
+
const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
|
|
3792
4316
|
`;
|
|
3793
|
-
|
|
4317
|
+
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
3794
4318
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
3795
4319
|
console.log(
|
|
3796
|
-
`[rsc-router] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.
|
|
4320
|
+
`[rsc-router] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
3797
4321
|
);
|
|
3798
4322
|
} catch (err) {
|
|
3799
4323
|
throw new Error(
|
|
@@ -3802,44 +4326,36 @@ globalThis.__PRERENDER_MANIFEST = __pm;
|
|
|
3802
4326
|
}
|
|
3803
4327
|
}
|
|
3804
4328
|
}
|
|
3805
|
-
if (hasStaticData &&
|
|
4329
|
+
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
3806
4330
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
3807
4331
|
if (!rscCode.includes("__STATIC_MANIFEST")) {
|
|
3808
4332
|
try {
|
|
3809
|
-
const assetsDir = resolve6(state.projectRoot, "dist/rsc/assets");
|
|
3810
|
-
mkdirSync(assetsDir, { recursive: true });
|
|
3811
4333
|
const manifestEntries = [];
|
|
3812
|
-
let totalBytes =
|
|
3813
|
-
|
|
3814
|
-
state.
|
|
4334
|
+
let totalBytes = copyStagedBuildAssets(
|
|
4335
|
+
state.projectRoot,
|
|
4336
|
+
Object.values(state.staticManifestEntries)
|
|
4337
|
+
);
|
|
4338
|
+
for (const [handlerId, assetFileName] of Object.entries(
|
|
4339
|
+
state.staticManifestEntries
|
|
3815
4340
|
)) {
|
|
3816
|
-
const contentHash = createHash4("sha256").update(encoded).digest("hex").slice(0, 8);
|
|
3817
|
-
const assetFileName = `__st-${contentHash}.js`;
|
|
3818
|
-
const assetPath = resolve6(assetsDir, assetFileName);
|
|
3819
|
-
const hasHandles = Object.keys(handles).length > 0;
|
|
3820
|
-
const exportValue = hasHandles ? JSON.stringify({ encoded, handles }) : JSON.stringify(encoded);
|
|
3821
|
-
const assetCode = `export default ${exportValue};
|
|
3822
|
-
`;
|
|
3823
|
-
writeFileSync3(assetPath, assetCode);
|
|
3824
|
-
totalBytes += Buffer.byteLength(assetCode);
|
|
3825
4341
|
manifestEntries.push(
|
|
3826
4342
|
`${JSON.stringify(handlerId)}:()=>import("./assets/${assetFileName}")`
|
|
3827
4343
|
);
|
|
3828
4344
|
}
|
|
3829
4345
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
3830
4346
|
`;
|
|
3831
|
-
const manifestPath =
|
|
4347
|
+
const manifestPath = resolve7(
|
|
3832
4348
|
state.projectRoot,
|
|
3833
4349
|
"dist/rsc/__static-manifest.js"
|
|
3834
4350
|
);
|
|
3835
|
-
|
|
4351
|
+
writeFileSync4(manifestPath, manifestCode);
|
|
3836
4352
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
3837
4353
|
const injection = `import "./__static-manifest.js";
|
|
3838
4354
|
`;
|
|
3839
|
-
|
|
4355
|
+
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
3840
4356
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
3841
4357
|
console.log(
|
|
3842
|
-
`[rsc-router] Wrote static assets (${totalKB} KB total, ${Object.keys(state.
|
|
4358
|
+
`[rsc-router] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
3843
4359
|
);
|
|
3844
4360
|
} catch (err) {
|
|
3845
4361
|
throw new Error(
|
|
@@ -3851,6 +4367,36 @@ globalThis.__PRERENDER_MANIFEST = __pm;
|
|
|
3851
4367
|
}
|
|
3852
4368
|
|
|
3853
4369
|
// src/vite/router-discovery.ts
|
|
4370
|
+
async function createTempRscServer(state, options = {}) {
|
|
4371
|
+
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
4372
|
+
return createViteServer({
|
|
4373
|
+
root: state.projectRoot,
|
|
4374
|
+
configFile: false,
|
|
4375
|
+
server: { middlewareMode: true },
|
|
4376
|
+
appType: "custom",
|
|
4377
|
+
logLevel: "silent",
|
|
4378
|
+
resolve: { alias: state.userResolveAlias },
|
|
4379
|
+
esbuild: { jsx: "automatic", jsxImportSource: "react" },
|
|
4380
|
+
...options.cacheDir && { cacheDir: options.cacheDir },
|
|
4381
|
+
plugins: [
|
|
4382
|
+
rsc({
|
|
4383
|
+
entries: {
|
|
4384
|
+
client: "virtual:entry-client",
|
|
4385
|
+
ssr: "virtual:entry-ssr",
|
|
4386
|
+
rsc: state.resolvedEntryPath
|
|
4387
|
+
}
|
|
4388
|
+
}),
|
|
4389
|
+
// hashClientRefs only in build mode — production bundles need hashed refs
|
|
4390
|
+
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
4391
|
+
createVersionPlugin(),
|
|
4392
|
+
createVirtualStubPlugin(),
|
|
4393
|
+
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
4394
|
+
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
4395
|
+
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
4396
|
+
exposeRouterId()
|
|
4397
|
+
]
|
|
4398
|
+
});
|
|
4399
|
+
}
|
|
3854
4400
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
3855
4401
|
const s = createDiscoveryState(entryPath, opts);
|
|
3856
4402
|
return {
|
|
@@ -3887,6 +4433,9 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
3887
4433
|
s.projectRoot = config.root;
|
|
3888
4434
|
s.isBuildMode = config.command === "build";
|
|
3889
4435
|
s.userResolveAlias = config.resolve.alias;
|
|
4436
|
+
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4437
|
+
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
4438
|
+
}
|
|
3890
4439
|
if (!s.resolvedEntryPath) {
|
|
3891
4440
|
const rscEnvConfig = config.environments?.["rsc"];
|
|
3892
4441
|
const entries = rscEnvConfig?.optimizeDeps?.entries;
|
|
@@ -3921,8 +4470,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
3921
4470
|
if (globalThis.__rscRouterDiscoveryActive) return;
|
|
3922
4471
|
s.devServer = server;
|
|
3923
4472
|
let resolveDiscovery;
|
|
3924
|
-
const discoveryPromise = new Promise((
|
|
3925
|
-
resolveDiscovery =
|
|
4473
|
+
const discoveryPromise = new Promise((resolve10) => {
|
|
4474
|
+
resolveDiscovery = resolve10;
|
|
3926
4475
|
});
|
|
3927
4476
|
const getDevServerOrigin = () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || `http://localhost:${server.config.server.port || 5173}`;
|
|
3928
4477
|
let prerenderTempServer = null;
|
|
@@ -3939,32 +4488,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
3939
4488
|
return prerenderTempServer.environments?.rsc ?? null;
|
|
3940
4489
|
}
|
|
3941
4490
|
try {
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
root: s.projectRoot,
|
|
3945
|
-
configFile: false,
|
|
3946
|
-
server: { middlewareMode: true },
|
|
3947
|
-
appType: "custom",
|
|
3948
|
-
logLevel: "silent",
|
|
3949
|
-
cacheDir: "node_modules/.vite_prerender",
|
|
3950
|
-
resolve: { alias: s.userResolveAlias },
|
|
3951
|
-
esbuild: { jsx: "automatic", jsxImportSource: "react" },
|
|
3952
|
-
plugins: [
|
|
3953
|
-
rsc({
|
|
3954
|
-
entries: {
|
|
3955
|
-
client: "virtual:entry-client",
|
|
3956
|
-
ssr: "virtual:entry-ssr",
|
|
3957
|
-
rsc: s.resolvedEntryPath
|
|
3958
|
-
}
|
|
3959
|
-
}),
|
|
3960
|
-
createVersionPlugin(),
|
|
3961
|
-
createVirtualStubPlugin(),
|
|
3962
|
-
// Dev prerender must use dev-mode IDs (path-based) to match the
|
|
3963
|
-
// workerd runtime. forceBuild would produce hashed IDs causing
|
|
3964
|
-
// handle data key mismatches when replayed into the runtime store.
|
|
3965
|
-
exposeInternalIds(),
|
|
3966
|
-
exposeRouterId()
|
|
3967
|
-
]
|
|
4491
|
+
prerenderTempServer = await createTempRscServer(s, {
|
|
4492
|
+
cacheDir: "node_modules/.vite_prerender"
|
|
3968
4493
|
});
|
|
3969
4494
|
const tempRscEnv = prerenderTempServer.environments?.rsc;
|
|
3970
4495
|
if (tempRscEnv?.runner) {
|
|
@@ -4008,34 +4533,10 @@ ${err.stack}`
|
|
|
4008
4533
|
if (serverMod?.setManifestReadyPromise) {
|
|
4009
4534
|
serverMod.setManifestReadyPromise(discoveryPromise);
|
|
4010
4535
|
}
|
|
4011
|
-
|
|
4012
|
-
mainRegistry = serverModAfterDiscovery?.RouterRegistry ?? null;
|
|
4536
|
+
await discoverRouters(s, rscEnv);
|
|
4013
4537
|
s.devServerOrigin = getDevServerOrigin();
|
|
4014
4538
|
writeRouteTypesFiles(s);
|
|
4015
|
-
|
|
4016
|
-
serverMod.setCachedManifest(s.mergedRouteManifest);
|
|
4017
|
-
}
|
|
4018
|
-
if (s.mergedPrecomputedEntries && s.mergedPrecomputedEntries.length > 0 && serverMod?.setPrecomputedEntries) {
|
|
4019
|
-
serverMod.setPrecomputedEntries(s.mergedPrecomputedEntries);
|
|
4020
|
-
}
|
|
4021
|
-
if (s.mergedRouteTrie && serverMod?.setRouteTrie) {
|
|
4022
|
-
serverMod.setRouteTrie(s.mergedRouteTrie);
|
|
4023
|
-
}
|
|
4024
|
-
if (serverMod?.setRouterManifest) {
|
|
4025
|
-
for (const [routerId, manifest] of s.perRouterManifestDataMap) {
|
|
4026
|
-
serverMod.setRouterManifest(routerId, manifest);
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
4029
|
-
if (serverMod?.setRouterTrie) {
|
|
4030
|
-
for (const [routerId, trie] of s.perRouterTrieMap) {
|
|
4031
|
-
serverMod.setRouterTrie(routerId, trie);
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
if (serverMod?.setRouterPrecomputedEntries) {
|
|
4035
|
-
for (const [routerId, entries] of s.perRouterPrecomputedMap) {
|
|
4036
|
-
serverMod.setRouterPrecomputedEntries(routerId, entries);
|
|
4037
|
-
}
|
|
4038
|
-
}
|
|
4539
|
+
await propagateDiscoveryState(rscEnv);
|
|
4039
4540
|
} catch (err) {
|
|
4040
4541
|
console.warn(
|
|
4041
4542
|
`[rsc-router] Router discovery failed: ${err.message}
|
|
@@ -4045,10 +4546,42 @@ ${err.stack}`
|
|
|
4045
4546
|
resolveDiscovery();
|
|
4046
4547
|
}
|
|
4047
4548
|
};
|
|
4048
|
-
s.discoveryDone = new Promise((
|
|
4049
|
-
setTimeout(() => discover().then(
|
|
4549
|
+
s.discoveryDone = new Promise((resolve10) => {
|
|
4550
|
+
setTimeout(() => discover().then(resolve10, resolve10), 0);
|
|
4050
4551
|
});
|
|
4051
4552
|
let mainRegistry = null;
|
|
4553
|
+
const propagateDiscoveryState = async (rscEnv) => {
|
|
4554
|
+
const serverMod = await rscEnv.runner.import("@rangojs/router/server");
|
|
4555
|
+
if (!serverMod) return;
|
|
4556
|
+
if (serverMod.clearAllRouterData) {
|
|
4557
|
+
serverMod.clearAllRouterData();
|
|
4558
|
+
}
|
|
4559
|
+
mainRegistry = serverMod.RouterRegistry ?? null;
|
|
4560
|
+
if (s.mergedRouteManifest && serverMod.setCachedManifest) {
|
|
4561
|
+
serverMod.setCachedManifest(s.mergedRouteManifest);
|
|
4562
|
+
}
|
|
4563
|
+
if (s.mergedPrecomputedEntries && s.mergedPrecomputedEntries.length > 0 && serverMod.setPrecomputedEntries) {
|
|
4564
|
+
serverMod.setPrecomputedEntries(s.mergedPrecomputedEntries);
|
|
4565
|
+
}
|
|
4566
|
+
if (s.mergedRouteTrie && serverMod.setRouteTrie) {
|
|
4567
|
+
serverMod.setRouteTrie(s.mergedRouteTrie);
|
|
4568
|
+
}
|
|
4569
|
+
if (serverMod.setRouterManifest) {
|
|
4570
|
+
for (const [routerId, manifest] of s.perRouterManifestDataMap) {
|
|
4571
|
+
serverMod.setRouterManifest(routerId, manifest);
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
if (serverMod.setRouterTrie) {
|
|
4575
|
+
for (const [routerId, trie] of s.perRouterTrieMap) {
|
|
4576
|
+
serverMod.setRouterTrie(routerId, trie);
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
if (serverMod.setRouterPrecomputedEntries) {
|
|
4580
|
+
for (const [routerId, entries] of s.perRouterPrecomputedMap) {
|
|
4581
|
+
serverMod.setRouterPrecomputedEntries(routerId, entries);
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
};
|
|
4052
4585
|
server.middlewares.use("/__rsc_prerender", async (req, res) => {
|
|
4053
4586
|
if (s.discoveryDone) await s.discoveryDone;
|
|
4054
4587
|
const url = new URL(req.url || "/", "http://localhost");
|
|
@@ -4071,11 +4604,20 @@ ${err.stack}`
|
|
|
4071
4604
|
return;
|
|
4072
4605
|
}
|
|
4073
4606
|
const wantIntercept = url.searchParams.get("intercept") === "1";
|
|
4607
|
+
const wantRouteName = url.searchParams.get("routeName");
|
|
4608
|
+
const wantPassthrough = url.searchParams.get("passthrough") === "1";
|
|
4074
4609
|
for (const [, routerInstance] of registry) {
|
|
4075
4610
|
if (!routerInstance.matchForPrerender) continue;
|
|
4076
4611
|
try {
|
|
4077
|
-
const result = await routerInstance.matchForPrerender(
|
|
4612
|
+
const result = await routerInstance.matchForPrerender(
|
|
4613
|
+
pathname,
|
|
4614
|
+
{},
|
|
4615
|
+
void 0,
|
|
4616
|
+
wantPassthrough
|
|
4617
|
+
);
|
|
4078
4618
|
if (!result) continue;
|
|
4619
|
+
if (result.passthrough) continue;
|
|
4620
|
+
if (wantRouteName && result.routeName !== wantRouteName) continue;
|
|
4079
4621
|
res.setHeader("content-type", "application/json");
|
|
4080
4622
|
let payload;
|
|
4081
4623
|
if (wantIntercept && result.interceptSegments?.length) {
|
|
@@ -4112,10 +4654,29 @@ ${err.stack}`
|
|
|
4112
4654
|
const maybeHandleGeneratedRouteFileMutation = (filePath) => {
|
|
4113
4655
|
if (!isGeneratedRouteFile(filePath)) return false;
|
|
4114
4656
|
if (consumeSelfGenWrite(s, filePath)) return true;
|
|
4657
|
+
const hasRunner = !!server.environments?.rsc?.runner;
|
|
4658
|
+
if (!hasRunner) return true;
|
|
4115
4659
|
regenerateGeneratedRouteFiles();
|
|
4116
4660
|
return true;
|
|
4117
4661
|
};
|
|
4118
4662
|
let routeChangeTimer;
|
|
4663
|
+
let runtimeRediscoveryInProgress = false;
|
|
4664
|
+
const refreshRuntimeDiscovery = async () => {
|
|
4665
|
+
const rscEnv = server.environments?.rsc;
|
|
4666
|
+
if (!rscEnv?.runner || runtimeRediscoveryInProgress) return;
|
|
4667
|
+
runtimeRediscoveryInProgress = true;
|
|
4668
|
+
try {
|
|
4669
|
+
await discoverRouters(s, rscEnv);
|
|
4670
|
+
writeRouteTypesFiles(s);
|
|
4671
|
+
await propagateDiscoveryState(rscEnv);
|
|
4672
|
+
} catch (err) {
|
|
4673
|
+
console.warn(
|
|
4674
|
+
`[rsc-router] Runtime re-discovery failed: ${err.message}`
|
|
4675
|
+
);
|
|
4676
|
+
} finally {
|
|
4677
|
+
runtimeRediscoveryInProgress = false;
|
|
4678
|
+
}
|
|
4679
|
+
};
|
|
4119
4680
|
const scheduleRouteRegeneration = () => {
|
|
4120
4681
|
clearTimeout(routeChangeTimer);
|
|
4121
4682
|
routeChangeTimer = setTimeout(() => {
|
|
@@ -4130,6 +4691,13 @@ ${err.stack}`
|
|
|
4130
4691
|
`[rsc-router] Route regeneration error: ${err.message}`
|
|
4131
4692
|
);
|
|
4132
4693
|
}
|
|
4694
|
+
if (s.perRouterManifests.length > 0) {
|
|
4695
|
+
refreshRuntimeDiscovery().catch((err) => {
|
|
4696
|
+
console.warn(
|
|
4697
|
+
`[rsc-router] Runtime re-discovery error: ${err.message}`
|
|
4698
|
+
);
|
|
4699
|
+
});
|
|
4700
|
+
}
|
|
4133
4701
|
}, 100);
|
|
4134
4702
|
};
|
|
4135
4703
|
const handleRouteFileChange = (filePath) => {
|
|
@@ -4146,6 +4714,16 @@ ${err.stack}`
|
|
|
4146
4714
|
const hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
|
|
4147
4715
|
if (!hasUrls && !hasCreateRouter) return;
|
|
4148
4716
|
if (hasCreateRouter) {
|
|
4717
|
+
const nestedRouterConflict = findNestedRouterConflict([
|
|
4718
|
+
...s.cachedRouterFiles ?? [],
|
|
4719
|
+
resolve8(filePath)
|
|
4720
|
+
]);
|
|
4721
|
+
if (nestedRouterConflict) {
|
|
4722
|
+
server.config.logger.error(
|
|
4723
|
+
formatNestedRouterConflictError(nestedRouterConflict)
|
|
4724
|
+
);
|
|
4725
|
+
return;
|
|
4726
|
+
}
|
|
4149
4727
|
s.cachedRouterFiles = void 0;
|
|
4150
4728
|
}
|
|
4151
4729
|
scheduleRouteRegeneration();
|
|
@@ -4156,6 +4734,8 @@ ${err.stack}`
|
|
|
4156
4734
|
server.watcher.on("change", handleRouteFileChange);
|
|
4157
4735
|
server.watcher.on("unlink", (filePath) => {
|
|
4158
4736
|
if (!isGeneratedRouteFile(filePath)) return;
|
|
4737
|
+
const hasRunner = !!server.environments?.rsc?.runner;
|
|
4738
|
+
if (!hasRunner) return;
|
|
4159
4739
|
regenerateGeneratedRouteFiles();
|
|
4160
4740
|
});
|
|
4161
4741
|
}
|
|
@@ -4166,43 +4746,13 @@ ${err.stack}`
|
|
|
4166
4746
|
async buildStart() {
|
|
4167
4747
|
if (!s.isBuildMode) return;
|
|
4168
4748
|
if (s.mergedRouteManifest !== null) return;
|
|
4749
|
+
resetStagedBuildAssets(s.projectRoot);
|
|
4750
|
+
s.prerenderManifestEntries = null;
|
|
4751
|
+
s.staticManifestEntries = null;
|
|
4169
4752
|
let tempServer = null;
|
|
4170
4753
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4171
4754
|
try {
|
|
4172
|
-
|
|
4173
|
-
tempServer = await createViteServer({
|
|
4174
|
-
root: s.projectRoot,
|
|
4175
|
-
configFile: false,
|
|
4176
|
-
server: { middlewareMode: true },
|
|
4177
|
-
appType: "custom",
|
|
4178
|
-
logLevel: "silent",
|
|
4179
|
-
// Use the resolved aliases from the real config (includes user's path aliases
|
|
4180
|
-
// like @/ -> src/ AND package aliases from rsc-router)
|
|
4181
|
-
resolve: { alias: s.userResolveAlias },
|
|
4182
|
-
// Enable automatic JSX runtime so .tsx files don't need `import React`.
|
|
4183
|
-
// Without this, esbuild defaults to classic mode (React.createElement)
|
|
4184
|
-
// which fails when lazy host-router handlers load sub-app modules with JSX.
|
|
4185
|
-
esbuild: { jsx: "automatic", jsxImportSource: "react" },
|
|
4186
|
-
plugins: [
|
|
4187
|
-
rsc({
|
|
4188
|
-
entries: {
|
|
4189
|
-
client: "virtual:entry-client",
|
|
4190
|
-
ssr: "virtual:entry-ssr",
|
|
4191
|
-
rsc: s.resolvedEntryPath
|
|
4192
|
-
}
|
|
4193
|
-
}),
|
|
4194
|
-
hashClientRefs(s.projectRoot),
|
|
4195
|
-
createVersionPlugin(),
|
|
4196
|
-
// Stub virtual modules that the RSC entry may import
|
|
4197
|
-
// (e.g., virtual:rsc-router/routes-manifest, virtual:rsc-router/loader-manifest)
|
|
4198
|
-
createVirtualStubPlugin(),
|
|
4199
|
-
// Inject handle + router IDs so prerender-collected handle data uses
|
|
4200
|
-
// the same hashed keys as the production client/SSR bundles, and
|
|
4201
|
-
// build-time router IDs match runtime IDs across environments.
|
|
4202
|
-
exposeInternalIds({ forceBuild: true }),
|
|
4203
|
-
exposeRouterId()
|
|
4204
|
-
]
|
|
4205
|
-
});
|
|
4755
|
+
tempServer = await createTempRscServer(s, { forceBuild: true });
|
|
4206
4756
|
const rscEnv = tempServer.environments?.rsc;
|
|
4207
4757
|
if (!rscEnv?.runner) {
|
|
4208
4758
|
console.warn(
|
|
@@ -4321,152 +4871,6 @@ ${details}`
|
|
|
4321
4871
|
};
|
|
4322
4872
|
}
|
|
4323
4873
|
|
|
4324
|
-
// src/vite/rango.ts
|
|
4325
|
-
import { readFileSync as readFileSync7 } from "node:fs";
|
|
4326
|
-
|
|
4327
|
-
// src/vite/plugins/use-cache-transform.ts
|
|
4328
|
-
import path5 from "node:path";
|
|
4329
|
-
import MagicString5 from "magic-string";
|
|
4330
|
-
var CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
|
|
4331
|
-
var LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
|
|
4332
|
-
function useCacheTransform() {
|
|
4333
|
-
let projectRoot = "";
|
|
4334
|
-
let isBuild = false;
|
|
4335
|
-
let rscTransforms = null;
|
|
4336
|
-
return {
|
|
4337
|
-
name: "@rangojs/router:use-cache",
|
|
4338
|
-
enforce: "post",
|
|
4339
|
-
configResolved(config) {
|
|
4340
|
-
projectRoot = config.root;
|
|
4341
|
-
isBuild = config.command === "build";
|
|
4342
|
-
},
|
|
4343
|
-
async transform(code, id) {
|
|
4344
|
-
if (this.environment?.name !== "rsc") return;
|
|
4345
|
-
if (!code.includes("use cache")) return;
|
|
4346
|
-
if (id.includes("/node_modules/") || id.startsWith("\0")) return;
|
|
4347
|
-
if (!/\.(tsx?|jsx?|mjs)$/.test(id)) return;
|
|
4348
|
-
if (!rscTransforms) {
|
|
4349
|
-
try {
|
|
4350
|
-
rscTransforms = await import("@vitejs/plugin-rsc/transforms");
|
|
4351
|
-
} catch {
|
|
4352
|
-
return;
|
|
4353
|
-
}
|
|
4354
|
-
}
|
|
4355
|
-
const {
|
|
4356
|
-
hasDirective,
|
|
4357
|
-
transformWrapExport,
|
|
4358
|
-
transformHoistInlineDirective
|
|
4359
|
-
} = rscTransforms;
|
|
4360
|
-
let ast;
|
|
4361
|
-
try {
|
|
4362
|
-
const { parseAst: parseAst3 } = await import("vite");
|
|
4363
|
-
ast = parseAst3(code);
|
|
4364
|
-
} catch {
|
|
4365
|
-
return;
|
|
4366
|
-
}
|
|
4367
|
-
const filePath = normalizePath(path5.relative(projectRoot, id));
|
|
4368
|
-
const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
|
|
4369
|
-
if (hasDirective(ast.body, "use cache")) {
|
|
4370
|
-
return transformFileLevelUseCache(
|
|
4371
|
-
code,
|
|
4372
|
-
ast,
|
|
4373
|
-
filePath,
|
|
4374
|
-
id,
|
|
4375
|
-
isBuild,
|
|
4376
|
-
isLayoutOrTemplate,
|
|
4377
|
-
transformWrapExport
|
|
4378
|
-
);
|
|
4379
|
-
}
|
|
4380
|
-
return transformFunctionLevelUseCache(
|
|
4381
|
-
code,
|
|
4382
|
-
ast,
|
|
4383
|
-
filePath,
|
|
4384
|
-
id,
|
|
4385
|
-
isBuild,
|
|
4386
|
-
transformHoistInlineDirective
|
|
4387
|
-
);
|
|
4388
|
-
}
|
|
4389
|
-
};
|
|
4390
|
-
}
|
|
4391
|
-
function transformFileLevelUseCache(code, ast, filePath, sourceId, isBuild, isLayoutOrTemplate, transformWrapExport) {
|
|
4392
|
-
const { exportNames, output } = transformWrapExport(code, ast, {
|
|
4393
|
-
runtime: (value, name) => {
|
|
4394
|
-
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
4395
|
-
return `__rango_registerCachedFunction(${value}, ${JSON.stringify(funcId)}, "default")`;
|
|
4396
|
-
},
|
|
4397
|
-
rejectNonAsyncFunction: false,
|
|
4398
|
-
filter: (name) => {
|
|
4399
|
-
if (name === "default" && isLayoutOrTemplate) return false;
|
|
4400
|
-
return true;
|
|
4401
|
-
}
|
|
4402
|
-
});
|
|
4403
|
-
if (exportNames.length === 0) {
|
|
4404
|
-
const s = new MagicString5(code);
|
|
4405
|
-
const directive2 = findFileLevelDirective(ast);
|
|
4406
|
-
if (directive2) {
|
|
4407
|
-
s.overwrite(
|
|
4408
|
-
directive2.start,
|
|
4409
|
-
directive2.end,
|
|
4410
|
-
`/* "use cache" -- wrapped by rango */`
|
|
4411
|
-
);
|
|
4412
|
-
return {
|
|
4413
|
-
code: s.toString(),
|
|
4414
|
-
map: s.generateMap({ source: sourceId, hires: "boundary" })
|
|
4415
|
-
};
|
|
4416
|
-
}
|
|
4417
|
-
return;
|
|
4418
|
-
}
|
|
4419
|
-
output.prepend(
|
|
4420
|
-
`import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};
|
|
4421
|
-
`
|
|
4422
|
-
);
|
|
4423
|
-
const directive = findFileLevelDirective(ast);
|
|
4424
|
-
if (directive) {
|
|
4425
|
-
output.overwrite(
|
|
4426
|
-
directive.start,
|
|
4427
|
-
directive.end,
|
|
4428
|
-
`/* "use cache" -- wrapped by rango */`
|
|
4429
|
-
);
|
|
4430
|
-
}
|
|
4431
|
-
return {
|
|
4432
|
-
code: output.toString(),
|
|
4433
|
-
map: output.generateMap({ source: sourceId, hires: "boundary" })
|
|
4434
|
-
};
|
|
4435
|
-
}
|
|
4436
|
-
function transformFunctionLevelUseCache(code, ast, filePath, sourceId, isBuild, transformHoistInlineDirective) {
|
|
4437
|
-
try {
|
|
4438
|
-
const { output, names } = transformHoistInlineDirective(code, ast, {
|
|
4439
|
-
directive: /^use cache(:\s*\w+)?$/,
|
|
4440
|
-
runtime: (value, name, meta) => {
|
|
4441
|
-
const funcId = isBuild ? hashId(filePath, name) : `${filePath}#${name}`;
|
|
4442
|
-
const profileMatch = meta.directiveMatch[1];
|
|
4443
|
-
const profileName = profileMatch ? profileMatch.replace(/^:\s*/, "").trim() : "default";
|
|
4444
|
-
return `__rango_registerCachedFunction(${value}, ${JSON.stringify(funcId)}, ${JSON.stringify(profileName)})`;
|
|
4445
|
-
},
|
|
4446
|
-
rejectNonAsyncFunction: false
|
|
4447
|
-
});
|
|
4448
|
-
if (names.length === 0) return;
|
|
4449
|
-
output.prepend(
|
|
4450
|
-
`import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};
|
|
4451
|
-
`
|
|
4452
|
-
);
|
|
4453
|
-
return {
|
|
4454
|
-
code: output.toString(),
|
|
4455
|
-
map: output.generateMap({ source: sourceId, hires: "boundary" })
|
|
4456
|
-
};
|
|
4457
|
-
} catch {
|
|
4458
|
-
return;
|
|
4459
|
-
}
|
|
4460
|
-
}
|
|
4461
|
-
function findFileLevelDirective(ast) {
|
|
4462
|
-
for (const node of ast.body ?? []) {
|
|
4463
|
-
if (node.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string" && node.expression.value.startsWith("use cache")) {
|
|
4464
|
-
return { start: node.start, end: node.end };
|
|
4465
|
-
}
|
|
4466
|
-
}
|
|
4467
|
-
return null;
|
|
4468
|
-
}
|
|
4469
|
-
|
|
4470
4874
|
// src/vite/rango.ts
|
|
4471
4875
|
async function rango(options) {
|
|
4472
4876
|
const resolvedOptions = options ?? { preset: "node" };
|
|
@@ -4476,7 +4880,7 @@ async function rango(options) {
|
|
|
4476
4880
|
const rangoAliases = getPackageAliases();
|
|
4477
4881
|
const excludeDeps = getExcludeDeps();
|
|
4478
4882
|
let rscEntryPath = null;
|
|
4479
|
-
|
|
4883
|
+
const routerRef = { path: void 0 };
|
|
4480
4884
|
const prerenderEnabled = true;
|
|
4481
4885
|
if (preset === "cloudflare") {
|
|
4482
4886
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
@@ -4573,35 +4977,39 @@ async function rango(options) {
|
|
|
4573
4977
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
4574
4978
|
plugins.push(
|
|
4575
4979
|
rsc({
|
|
4576
|
-
|
|
4577
|
-
return finalEntries;
|
|
4578
|
-
},
|
|
4980
|
+
entries: finalEntries,
|
|
4579
4981
|
serverHandler: false
|
|
4580
4982
|
})
|
|
4581
4983
|
);
|
|
4984
|
+
plugins.push(clientRefDedup());
|
|
4582
4985
|
} else {
|
|
4583
4986
|
const nodeOptions = resolvedOptions;
|
|
4584
|
-
|
|
4585
|
-
if (!
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4987
|
+
routerRef.path = nodeOptions.router;
|
|
4988
|
+
if (!routerRef.path) {
|
|
4989
|
+
plugins.push({
|
|
4990
|
+
name: "@rangojs/router:auto-discover",
|
|
4991
|
+
config(userConfig) {
|
|
4992
|
+
if (routerRef.path) return;
|
|
4993
|
+
const root = userConfig.root ? resolve9(process.cwd(), userConfig.root) : process.cwd();
|
|
4994
|
+
const filter = createScanFilter(root, {
|
|
4995
|
+
include: resolvedOptions.include,
|
|
4996
|
+
exclude: resolvedOptions.exclude
|
|
4997
|
+
});
|
|
4998
|
+
const candidates = findRouterFiles(root, filter);
|
|
4999
|
+
if (candidates.length === 1) {
|
|
5000
|
+
const abs = candidates[0];
|
|
5001
|
+
routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
5002
|
+
} else if (candidates.length > 1) {
|
|
5003
|
+
const list = candidates.map(
|
|
5004
|
+
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5005
|
+
).join("\n");
|
|
5006
|
+
throw new Error(
|
|
5007
|
+
`[rsc-router] Multiple routers found. Specify \`router\` to choose one:
|
|
4602
5008
|
${list}`
|
|
4603
|
-
|
|
4604
|
-
|
|
5009
|
+
);
|
|
5010
|
+
}
|
|
5011
|
+
}
|
|
5012
|
+
});
|
|
4605
5013
|
}
|
|
4606
5014
|
const rscOption = nodeOptions.rsc ?? true;
|
|
4607
5015
|
if (rscOption !== false) {
|
|
@@ -4715,13 +5123,14 @@ ${list}`
|
|
|
4715
5123
|
}
|
|
4716
5124
|
}
|
|
4717
5125
|
});
|
|
4718
|
-
plugins.push(createVirtualEntriesPlugin(finalEntries,
|
|
5126
|
+
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
4719
5127
|
plugins.push(
|
|
4720
5128
|
rsc({
|
|
4721
5129
|
entries: finalEntries
|
|
4722
5130
|
})
|
|
4723
5131
|
);
|
|
4724
5132
|
}
|
|
5133
|
+
plugins.push(clientRefDedup());
|
|
4725
5134
|
}
|
|
4726
5135
|
plugins.push({
|
|
4727
5136
|
name: "@rangojs/router:client-component-hmr",
|
|
@@ -4746,7 +5155,8 @@ ${list}`
|
|
|
4746
5155
|
plugins.push(exposeInternalIds());
|
|
4747
5156
|
plugins.push(exposeRouterId());
|
|
4748
5157
|
plugins.push(createVersionPlugin());
|
|
4749
|
-
const discoveryEntryPath = preset !== "cloudflare" ?
|
|
5158
|
+
const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
|
|
5159
|
+
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
|
|
4750
5160
|
const injectorEntryPath = rscEntryPath ?? (preset === "cloudflare" ? void 0 : null);
|
|
4751
5161
|
if (injectorEntryPath !== null) {
|
|
4752
5162
|
plugins.push(createVersionInjectorPlugin(injectorEntryPath));
|
|
@@ -4754,6 +5164,7 @@ ${list}`
|
|
|
4754
5164
|
plugins.push(createCjsToEsmPlugin());
|
|
4755
5165
|
plugins.push(
|
|
4756
5166
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5167
|
+
routerPathRef: discoveryRouterRef,
|
|
4757
5168
|
enableBuildPrerender: prerenderEnabled,
|
|
4758
5169
|
staticRouteTypesGeneration: resolvedOptions.staticRouteTypesGeneration,
|
|
4759
5170
|
include: resolvedOptions.include,
|
|
@@ -4762,34 +5173,42 @@ ${list}`
|
|
|
4762
5173
|
);
|
|
4763
5174
|
return plugins;
|
|
4764
5175
|
}
|
|
5176
|
+
|
|
5177
|
+
// src/vite/plugins/refresh-cmd.ts
|
|
5178
|
+
function poke() {
|
|
5179
|
+
return {
|
|
5180
|
+
name: "vite-plugin-poke",
|
|
5181
|
+
apply: "serve",
|
|
5182
|
+
configureServer(server) {
|
|
5183
|
+
const stdin = process.stdin;
|
|
5184
|
+
const previousRawMode = stdin.isTTY ? stdin.isRaw : null;
|
|
5185
|
+
if (stdin.isTTY) {
|
|
5186
|
+
stdin.setRawMode(true);
|
|
5187
|
+
}
|
|
5188
|
+
const onData = (data) => {
|
|
5189
|
+
if (data.length !== 1) return;
|
|
5190
|
+
if (data[0] === 3) {
|
|
5191
|
+
process.emit("SIGINT", "SIGINT");
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
if (data[0] === 18) {
|
|
5195
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
5196
|
+
server.config.logger.info(" browser reload (ctrl+r)", {
|
|
5197
|
+
timestamp: true
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5200
|
+
};
|
|
5201
|
+
stdin.on("data", onData);
|
|
5202
|
+
server.httpServer?.on("close", () => {
|
|
5203
|
+
stdin.off("data", onData);
|
|
5204
|
+
if (stdin.isTTY && previousRawMode !== null) {
|
|
5205
|
+
stdin.setRawMode(previousRawMode);
|
|
5206
|
+
}
|
|
5207
|
+
});
|
|
5208
|
+
}
|
|
5209
|
+
};
|
|
5210
|
+
}
|
|
4765
5211
|
export {
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
computeProductionHash,
|
|
4769
|
-
createCjsToEsmPlugin,
|
|
4770
|
-
createRouterDiscoveryPlugin,
|
|
4771
|
-
createVersionInjectorPlugin,
|
|
4772
|
-
createVersionPlugin,
|
|
4773
|
-
createVirtualEntriesPlugin,
|
|
4774
|
-
createVirtualStubPlugin,
|
|
4775
|
-
encodePathParam,
|
|
4776
|
-
evictHandlerCode,
|
|
4777
|
-
exposeActionId,
|
|
4778
|
-
exposeInternalIds,
|
|
4779
|
-
exposeRouterId,
|
|
4780
|
-
extractHandlerExportsFromChunk,
|
|
4781
|
-
findMatchingParenInBundle,
|
|
4782
|
-
flattenLeafEntries,
|
|
4783
|
-
getManualChunks,
|
|
4784
|
-
groupByConcurrency,
|
|
4785
|
-
hashClientRefs,
|
|
4786
|
-
jsonParseExpression,
|
|
4787
|
-
notifyOnError,
|
|
4788
|
-
onwarn,
|
|
4789
|
-
printBanner,
|
|
4790
|
-
rango,
|
|
4791
|
-
rangoVersion,
|
|
4792
|
-
runWithConcurrency,
|
|
4793
|
-
sharedEsbuildOptions,
|
|
4794
|
-
transformClientRefs
|
|
5212
|
+
poke,
|
|
5213
|
+
rango
|
|
4795
5214
|
};
|