@rangojs/router 0.0.0-experimental.8a4d0430 → 0.0.0-experimental.8bcfea43
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/AGENTS.md +4 -0
- package/README.md +126 -38
- package/dist/bin/rango.js +138 -50
- package/dist/vite/index.js +1171 -461
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +19 -16
- package/skills/breadcrumbs/SKILL.md +3 -1
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +45 -4
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +28 -20
- package/skills/intercept/SKILL.md +20 -0
- package/skills/layout/SKILL.md +22 -0
- package/skills/links/SKILL.md +91 -17
- package/skills/loader/SKILL.md +88 -45
- package/skills/middleware/SKILL.md +34 -3
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +765 -0
- package/skills/parallel/SKILL.md +185 -0
- package/skills/prerender/SKILL.md +110 -68
- package/skills/rango/SKILL.md +24 -22
- package/skills/response-routes/SKILL.md +8 -0
- package/skills/route/SKILL.md +55 -0
- package/skills/router-setup/SKILL.md +87 -2
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +13 -1
- package/src/__internal.ts +1 -1
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/navigation-bridge.ts +90 -16
- package/src/browser/navigation-client.ts +167 -59
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/navigation-transaction.ts +11 -9
- package/src/browser/partial-update.ts +113 -17
- package/src/browser/prefetch/cache.ts +184 -16
- package/src/browser/prefetch/fetch.ts +180 -33
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +123 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +81 -9
- package/src/browser/react/NavigationProvider.tsx +89 -14
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +11 -1
- package/src/browser/react/use-router.ts +29 -9
- package/src/browser/rsc-router.tsx +168 -65
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/server-action-bridge.ts +8 -6
- package/src/browser/types.ts +49 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/route-trie.ts +50 -24
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +223 -74
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +48 -7
- package/src/cache/cf/cf-cache-store.ts +455 -15
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.tsx +84 -230
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/index.rsc.ts +6 -1
- package/src/index.ts +49 -6
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +138 -77
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +27 -2
- package/src/route-definition/dsl-helpers.ts +240 -40
- package/src/route-definition/helpers-types.ts +67 -19
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +101 -25
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +10 -7
- package/src/router/loader-resolution.ts +159 -21
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +31 -16
- package/src/router/match-api.ts +127 -192
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +94 -17
- package/src/router/match-middleware/cache-store.ts +53 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +104 -10
- package/src/router/metrics.ts +6 -1
- package/src/router/middleware-types.ts +8 -30
- package/src/router/middleware.ts +36 -10
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +60 -9
- package/src/router/prerender-match.ts +110 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +198 -20
- package/src/router/segment-resolution/helpers.ts +29 -24
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +438 -300
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/trie-matching.ts +10 -4
- package/src/router/types.ts +1 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +60 -8
- package/src/rsc/handler.ts +478 -374
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +16 -2
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +19 -1
- package/src/rsc/server-action.ts +10 -0
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +9 -1
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +109 -23
- package/src/server/context.ts +166 -17
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +194 -60
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +137 -65
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-entry.ts +19 -1
- package/src/types/segments.ts +2 -0
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +48 -13
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +18 -16
- package/src/use-loader.tsx +77 -5
- package/src/vite/debug.ts +55 -0
- package/src/vite/discovery/bundle-postprocess.ts +30 -33
- package/src/vite/discovery/discover-routers.ts +5 -1
- package/src/vite/discovery/prerender-collection.ts +128 -74
- package/src/vite/discovery/state.ts +13 -6
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/plugins/expose-action-id.ts +1 -3
- package/src/vite/plugins/expose-id-utils.ts +12 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +30 -0
- package/src/vite/plugins/expose-internal-ids.ts +257 -40
- package/src/vite/plugins/performance-tracks.ts +86 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +204 -217
- package/src/vite/router-discovery.ts +335 -64
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/package-resolution.ts +41 -1
- package/src/vite/utils/prerender-utils.ts +37 -5
- package/src/vite/utils/shared-utils.ts +3 -2
package/dist/vite/index.js
CHANGED
|
@@ -18,6 +18,9 @@ function hashId(filePath, exportName) {
|
|
|
18
18
|
const hash = crypto.createHash("sha256").update(input).digest("hex");
|
|
19
19
|
return `${hash.slice(0, 8)}#${exportName}`;
|
|
20
20
|
}
|
|
21
|
+
function makeStubId(filePath, exportName, isBuild) {
|
|
22
|
+
return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
|
|
23
|
+
}
|
|
21
24
|
function hashInlineId(filePath, lineNumber, index) {
|
|
22
25
|
const input = index !== void 0 && index > 0 ? `${filePath}:${lineNumber}:${index}` : `${filePath}:${lineNumber}`;
|
|
23
26
|
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
@@ -292,7 +295,7 @@ function exposeActionId() {
|
|
|
292
295
|
}
|
|
293
296
|
if (!rscPluginApi) {
|
|
294
297
|
throw new Error(
|
|
295
|
-
"[rsc-router] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin
|
|
298
|
+
"[rsc-router] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
|
|
296
299
|
);
|
|
297
300
|
}
|
|
298
301
|
if (!isBuild) return;
|
|
@@ -910,9 +913,7 @@ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
|
|
|
910
913
|
});
|
|
911
914
|
return { code: stubs.join("\n") + "\n", map: null };
|
|
912
915
|
}
|
|
913
|
-
function
|
|
914
|
-
if (bindings.length === 0) return null;
|
|
915
|
-
const s = new MagicString2(code);
|
|
916
|
+
function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
|
|
916
917
|
let hasChanges = false;
|
|
917
918
|
for (const binding of bindings) {
|
|
918
919
|
const exportName = binding.exportNames[0];
|
|
@@ -924,15 +925,7 @@ function generateExprStubs(cfg, bindings, code, filePath, sourceId, isBuild) {
|
|
|
924
925
|
);
|
|
925
926
|
hasChanges = true;
|
|
926
927
|
}
|
|
927
|
-
|
|
928
|
-
return {
|
|
929
|
-
code: s.toString(),
|
|
930
|
-
map: s.generateMap({
|
|
931
|
-
source: sourceId,
|
|
932
|
-
includeContent: true,
|
|
933
|
-
hires: "boundary"
|
|
934
|
-
})
|
|
935
|
-
};
|
|
928
|
+
return hasChanges;
|
|
936
929
|
}
|
|
937
930
|
function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
|
|
938
931
|
let hasChanges = false;
|
|
@@ -1269,15 +1262,6 @@ ${lazyImports.join(",\n")}
|
|
|
1269
1262
|
isBuild
|
|
1270
1263
|
);
|
|
1271
1264
|
if (wholeFile) return wholeFile;
|
|
1272
|
-
const exprStubs = generateExprStubs(
|
|
1273
|
-
PRERENDER_CONFIG,
|
|
1274
|
-
bindings,
|
|
1275
|
-
code,
|
|
1276
|
-
filePath,
|
|
1277
|
-
id,
|
|
1278
|
-
isBuild
|
|
1279
|
-
);
|
|
1280
|
-
if (exprStubs) return exprStubs;
|
|
1281
1265
|
}
|
|
1282
1266
|
if (hasPrerenderHandlerCode && isRscEnv && isBuild) {
|
|
1283
1267
|
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
@@ -1329,15 +1313,134 @@ ${lazyImports.join(",\n")}
|
|
|
1329
1313
|
isBuild
|
|
1330
1314
|
);
|
|
1331
1315
|
if (wholeFile) return wholeFile;
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1316
|
+
}
|
|
1317
|
+
if (!isRscEnv && (hasPrerenderHandlerCode || hasStaticHandlerCode)) {
|
|
1318
|
+
const prerenderFnNames = hasPrerenderHandlerCode ? getFnNames(PRERENDER_CONFIG.fnName) : [];
|
|
1319
|
+
const staticFnNames = hasStaticHandlerCode ? getFnNames(STATIC_CONFIG.fnName) : [];
|
|
1320
|
+
const loaderFnNames = hasLoaderCode ? getFnNames("createLoader") : [];
|
|
1321
|
+
const handleFnNames = hasHandleCode ? getFnNames("createHandle") : [];
|
|
1322
|
+
const lsFnNames = hasLocationStateCode ? getFnNames("createLocationState") : [];
|
|
1323
|
+
const allBindings = [];
|
|
1324
|
+
for (const fnNames of [
|
|
1325
|
+
prerenderFnNames,
|
|
1326
|
+
staticFnNames,
|
|
1327
|
+
loaderFnNames,
|
|
1328
|
+
handleFnNames,
|
|
1329
|
+
lsFnNames
|
|
1330
|
+
]) {
|
|
1331
|
+
if (fnNames.length > 0) {
|
|
1332
|
+
allBindings.push(...getBindings(code, fnNames));
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
let canStubWholeFile = allBindings.length > 0 && isExportOnlyFile(code, allBindings);
|
|
1336
|
+
if (canStubWholeFile && (handleFnNames.length > 0 || lsFnNames.length > 0)) {
|
|
1337
|
+
const exportedLocals = new Set(allBindings.map((b) => b.localName));
|
|
1338
|
+
const strippedBindings = [];
|
|
1339
|
+
const localDeclPattern = /(?:^|;|\n)\s*(?:const|let|var|function)\s+(\w+)/g;
|
|
1340
|
+
let declMatch;
|
|
1341
|
+
while ((declMatch = localDeclPattern.exec(code)) !== null) {
|
|
1342
|
+
const name = declMatch[1];
|
|
1343
|
+
if (!exportedLocals.has(name) && !/^_c\d*$/.test(name)) {
|
|
1344
|
+
strippedBindings.push(name);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
const importPattern = /import\s*\{([^}]*)\}\s*from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1348
|
+
let importMatch;
|
|
1349
|
+
while ((importMatch = importPattern.exec(code)) !== null) {
|
|
1350
|
+
for (const spec of importMatch[1].split(",")) {
|
|
1351
|
+
const m = spec.trim().match(/^[A-Za-z_$][\w$]*(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
|
|
1352
|
+
if (m) strippedBindings.push(m[1] || m[0].trim().split(/\s/)[0]);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
const defaultImportPattern = /import\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1356
|
+
while ((importMatch = defaultImportPattern.exec(code)) !== null) {
|
|
1357
|
+
strippedBindings.push(importMatch[1]);
|
|
1358
|
+
}
|
|
1359
|
+
const nsImportPattern = /import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
|
|
1360
|
+
while ((importMatch = nsImportPattern.exec(code)) !== null) {
|
|
1361
|
+
strippedBindings.push(importMatch[1]);
|
|
1362
|
+
}
|
|
1363
|
+
if (strippedBindings.length > 0) {
|
|
1364
|
+
const preservedBindings = allBindings.filter((b) => {
|
|
1365
|
+
const fc = code.slice(b.callExprStart, b.callOpenParenPos + 1);
|
|
1366
|
+
return handleFnNames.some((n) => fc.includes(n)) || lsFnNames.some((n) => fc.includes(n));
|
|
1367
|
+
});
|
|
1368
|
+
const strippedRe = new RegExp(
|
|
1369
|
+
`\\b(?:${strippedBindings.join("|")})\\b`
|
|
1370
|
+
);
|
|
1371
|
+
canStubWholeFile = !preservedBindings.some((b) => {
|
|
1372
|
+
const expr = code.slice(b.callExprStart, b.callCloseParenPos + 1);
|
|
1373
|
+
return strippedRe.test(expr);
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
if (canStubWholeFile) {
|
|
1378
|
+
const lines = [];
|
|
1379
|
+
const neededImports = [];
|
|
1380
|
+
if (handleFnNames.length > 0) neededImports.push("createHandle");
|
|
1381
|
+
if (lsFnNames.length > 0) neededImports.push("createLocationState");
|
|
1382
|
+
if (neededImports.length > 0) {
|
|
1383
|
+
lines.push(
|
|
1384
|
+
`import { ${neededImports.join(", ")} } from "@rangojs/router";`
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
for (const binding of allBindings) {
|
|
1388
|
+
const fnCall = code.slice(
|
|
1389
|
+
binding.callExprStart,
|
|
1390
|
+
binding.callOpenParenPos + 1
|
|
1391
|
+
);
|
|
1392
|
+
const isHandle = handleFnNames.some((n) => fnCall.includes(n));
|
|
1393
|
+
const isLocationState = lsFnNames.some((n) => fnCall.includes(n));
|
|
1394
|
+
const primaryName = binding.exportNames[0];
|
|
1395
|
+
const stubId = makeStubId(filePath, primaryName, isBuild);
|
|
1396
|
+
if (isHandle || isLocationState) {
|
|
1397
|
+
const rawArgs = code.slice(binding.callOpenParenPos + 1, binding.callCloseParenPos).replace(/\b_c\d*\s*=\s*/g, "");
|
|
1398
|
+
const canonicalName = isHandle ? "createHandle" : "createLocationState";
|
|
1399
|
+
const activeFnNames = isHandle ? handleFnNames : lsFnNames;
|
|
1400
|
+
let rawCallee = code.slice(
|
|
1401
|
+
binding.callExprStart,
|
|
1402
|
+
binding.callOpenParenPos
|
|
1403
|
+
);
|
|
1404
|
+
for (const alias of activeFnNames) {
|
|
1405
|
+
if (alias !== canonicalName && rawCallee.startsWith(alias)) {
|
|
1406
|
+
rawCallee = canonicalName + rawCallee.slice(alias.length);
|
|
1407
|
+
break;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
if (isHandle) {
|
|
1411
|
+
const idParam = binding.argCount === 0 ? `undefined, "${stubId}"` : `, "${stubId}"`;
|
|
1412
|
+
lines.push(
|
|
1413
|
+
`export const ${primaryName} = ${rawCallee}(${rawArgs}${idParam});`
|
|
1414
|
+
);
|
|
1415
|
+
lines.push(`${primaryName}.$$id = "${stubId}";`);
|
|
1416
|
+
} else {
|
|
1417
|
+
lines.push(
|
|
1418
|
+
`export const ${primaryName} = ${rawCallee}(${rawArgs});`
|
|
1419
|
+
);
|
|
1420
|
+
lines.push(
|
|
1421
|
+
`${primaryName}.__rsc_ls_key = "__rsc_ls_${stubId}";`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
for (const name of binding.exportNames.slice(1)) {
|
|
1425
|
+
lines.push(`export const ${name} = ${primaryName};`);
|
|
1426
|
+
}
|
|
1427
|
+
} else {
|
|
1428
|
+
let brand = "loader";
|
|
1429
|
+
if (prerenderFnNames.some((n) => fnCall.includes(n))) {
|
|
1430
|
+
brand = PRERENDER_CONFIG.brand;
|
|
1431
|
+
} else if (staticFnNames.some((n) => fnCall.includes(n))) {
|
|
1432
|
+
brand = STATIC_CONFIG.brand;
|
|
1433
|
+
}
|
|
1434
|
+
lines.push(
|
|
1435
|
+
`export const ${primaryName} = { __brand: "${brand}", $$id: "${stubId}" };`
|
|
1436
|
+
);
|
|
1437
|
+
for (const name of binding.exportNames.slice(1)) {
|
|
1438
|
+
lines.push(`export const ${name} = ${primaryName};`);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
return { code: lines.join("\n") + "\n", map: null };
|
|
1443
|
+
}
|
|
1341
1444
|
}
|
|
1342
1445
|
if (hasStaticHandlerCode && isRscEnv && isBuild) {
|
|
1343
1446
|
const fnNames = getFnNames(STATIC_CONFIG.fnName);
|
|
@@ -1372,25 +1475,41 @@ ${lazyImports.join(",\n")}
|
|
|
1372
1475
|
isBuild
|
|
1373
1476
|
) || changed;
|
|
1374
1477
|
}
|
|
1375
|
-
if (hasPrerenderHandlerCode
|
|
1478
|
+
if (hasPrerenderHandlerCode) {
|
|
1376
1479
|
const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1480
|
+
const bindings = getBindings(code, fnNames);
|
|
1481
|
+
if (isRscEnv) {
|
|
1482
|
+
changed = transformHandlerIds(
|
|
1483
|
+
PRERENDER_CONFIG,
|
|
1484
|
+
bindings,
|
|
1485
|
+
s,
|
|
1486
|
+
filePath,
|
|
1487
|
+
isBuild
|
|
1488
|
+
) || changed;
|
|
1489
|
+
} else {
|
|
1490
|
+
changed = stubHandlerExprs(
|
|
1491
|
+
PRERENDER_CONFIG,
|
|
1492
|
+
bindings,
|
|
1493
|
+
s,
|
|
1494
|
+
filePath,
|
|
1495
|
+
isBuild
|
|
1496
|
+
) || changed;
|
|
1497
|
+
}
|
|
1384
1498
|
}
|
|
1385
|
-
if (hasStaticHandlerCode
|
|
1499
|
+
if (hasStaticHandlerCode) {
|
|
1386
1500
|
const fnNames = getFnNames(STATIC_CONFIG.fnName);
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1501
|
+
const bindings = getBindings(code, fnNames);
|
|
1502
|
+
if (isRscEnv) {
|
|
1503
|
+
changed = transformHandlerIds(
|
|
1504
|
+
STATIC_CONFIG,
|
|
1505
|
+
bindings,
|
|
1506
|
+
s,
|
|
1507
|
+
filePath,
|
|
1508
|
+
isBuild
|
|
1509
|
+
) || changed;
|
|
1510
|
+
} else {
|
|
1511
|
+
changed = stubHandlerExprs(STATIC_CONFIG, bindings, s, filePath, isBuild) || changed;
|
|
1512
|
+
}
|
|
1394
1513
|
}
|
|
1395
1514
|
if (!changed) return;
|
|
1396
1515
|
return {
|
|
@@ -1740,12 +1859,13 @@ function getVirtualVersionContent(version) {
|
|
|
1740
1859
|
|
|
1741
1860
|
// src/vite/utils/package-resolution.ts
|
|
1742
1861
|
import { existsSync } from "node:fs";
|
|
1862
|
+
import { createRequire } from "node:module";
|
|
1743
1863
|
import { resolve } from "node:path";
|
|
1744
1864
|
|
|
1745
1865
|
// package.json
|
|
1746
1866
|
var package_default = {
|
|
1747
1867
|
name: "@rangojs/router",
|
|
1748
|
-
version: "0.0.0-experimental.
|
|
1868
|
+
version: "0.0.0-experimental.8bcfea43",
|
|
1749
1869
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1750
1870
|
keywords: [
|
|
1751
1871
|
"react",
|
|
@@ -1878,22 +1998,24 @@ var package_default = {
|
|
|
1878
1998
|
tag: "experimental"
|
|
1879
1999
|
},
|
|
1880
2000
|
scripts: {
|
|
1881
|
-
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
2001
|
+
build: "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
|
|
1882
2002
|
prepublishOnly: "pnpm build",
|
|
1883
|
-
typecheck: "tsc --noEmit",
|
|
2003
|
+
typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit",
|
|
1884
2004
|
test: "playwright test",
|
|
1885
2005
|
"test:ui": "playwright test --ui",
|
|
1886
2006
|
"test:unit": "vitest run",
|
|
1887
2007
|
"test:unit:watch": "vitest"
|
|
1888
2008
|
},
|
|
1889
2009
|
dependencies: {
|
|
1890
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2010
|
+
"@vitejs/plugin-rsc": "^0.5.23",
|
|
2011
|
+
debug: "^4.4.1",
|
|
1891
2012
|
"magic-string": "^0.30.17",
|
|
1892
2013
|
picomatch: "^4.0.3",
|
|
1893
2014
|
"rsc-html-stream": "^0.0.7"
|
|
1894
2015
|
},
|
|
1895
2016
|
devDependencies: {
|
|
1896
2017
|
"@playwright/test": "^1.49.1",
|
|
2018
|
+
"@types/debug": "^4.1.12",
|
|
1897
2019
|
"@types/node": "^24.10.1",
|
|
1898
2020
|
"@types/react": "catalog:",
|
|
1899
2021
|
"@types/react-dom": "catalog:",
|
|
@@ -1907,7 +2029,7 @@ var package_default = {
|
|
|
1907
2029
|
},
|
|
1908
2030
|
peerDependencies: {
|
|
1909
2031
|
"@cloudflare/vite-plugin": "^1.25.0",
|
|
1910
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2032
|
+
"@vitejs/plugin-rsc": "^0.5.23",
|
|
1911
2033
|
react: "^18.0.0 || ^19.0.0",
|
|
1912
2034
|
vite: "^7.3.0"
|
|
1913
2035
|
},
|
|
@@ -1922,6 +2044,7 @@ var package_default = {
|
|
|
1922
2044
|
};
|
|
1923
2045
|
|
|
1924
2046
|
// src/vite/utils/package-resolution.ts
|
|
2047
|
+
var require2 = createRequire(import.meta.url);
|
|
1925
2048
|
var VIRTUAL_PACKAGE_NAME = "@rangojs/router";
|
|
1926
2049
|
function getPublishedPackageName() {
|
|
1927
2050
|
return package_default.name;
|
|
@@ -1962,6 +2085,20 @@ function getPackageAliases() {
|
|
|
1962
2085
|
}
|
|
1963
2086
|
return aliases;
|
|
1964
2087
|
}
|
|
2088
|
+
function getVendorAliases() {
|
|
2089
|
+
const specs = [
|
|
2090
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
2091
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
2092
|
+
];
|
|
2093
|
+
const aliases = {};
|
|
2094
|
+
for (const spec of specs) {
|
|
2095
|
+
try {
|
|
2096
|
+
aliases[spec] = require2.resolve(spec);
|
|
2097
|
+
} catch {
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
return aliases;
|
|
2101
|
+
}
|
|
1965
2102
|
|
|
1966
2103
|
// src/build/route-types/param-extraction.ts
|
|
1967
2104
|
function extractParamsFromPattern(pattern) {
|
|
@@ -2095,31 +2232,7 @@ declare global {
|
|
|
2095
2232
|
}
|
|
2096
2233
|
|
|
2097
2234
|
// src/build/route-types/scan-filter.ts
|
|
2098
|
-
import { join, relative } from "node:path";
|
|
2099
2235
|
import picomatch from "picomatch";
|
|
2100
|
-
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2101
|
-
"**/__tests__/**",
|
|
2102
|
-
"**/__mocks__/**",
|
|
2103
|
-
"**/dist/**",
|
|
2104
|
-
"**/coverage/**",
|
|
2105
|
-
"**/*.test.{ts,tsx,js,jsx}",
|
|
2106
|
-
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2107
|
-
];
|
|
2108
|
-
function createScanFilter(root, opts) {
|
|
2109
|
-
const { include, exclude } = opts;
|
|
2110
|
-
const hasInclude = include && include.length > 0;
|
|
2111
|
-
const hasCustomExclude = exclude !== void 0;
|
|
2112
|
-
if (!hasInclude && !hasCustomExclude) return void 0;
|
|
2113
|
-
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
|
|
2114
|
-
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2115
|
-
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2116
|
-
return (absolutePath) => {
|
|
2117
|
-
const rel = relative(root, absolutePath);
|
|
2118
|
-
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2119
|
-
if (includeMatcher) return includeMatcher(rel);
|
|
2120
|
-
return true;
|
|
2121
|
-
};
|
|
2122
|
-
}
|
|
2123
2236
|
|
|
2124
2237
|
// src/build/route-types/per-module-writer.ts
|
|
2125
2238
|
import ts4 from "typescript";
|
|
@@ -2341,7 +2454,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2341
2454
|
}
|
|
2342
2455
|
return routeMap;
|
|
2343
2456
|
}
|
|
2344
|
-
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut) {
|
|
2457
|
+
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
|
|
2345
2458
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
2346
2459
|
const realPath = resolve2(filePath);
|
|
2347
2460
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
@@ -2357,7 +2470,9 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2357
2470
|
return { routes: {}, searchSchemas: {} };
|
|
2358
2471
|
}
|
|
2359
2472
|
let block;
|
|
2360
|
-
if (
|
|
2473
|
+
if (inlineBlock) {
|
|
2474
|
+
block = inlineBlock;
|
|
2475
|
+
} else if (variableName) {
|
|
2361
2476
|
const extracted = extractUrlsBlockForVariable(source, variableName);
|
|
2362
2477
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
2363
2478
|
block = extracted;
|
|
@@ -2386,7 +2501,7 @@ import {
|
|
|
2386
2501
|
readdirSync
|
|
2387
2502
|
} from "node:fs";
|
|
2388
2503
|
import {
|
|
2389
|
-
join
|
|
2504
|
+
join,
|
|
2390
2505
|
dirname as dirname2,
|
|
2391
2506
|
resolve as resolve3,
|
|
2392
2507
|
sep,
|
|
@@ -2406,7 +2521,7 @@ function countPublicRouteEntries(source) {
|
|
|
2406
2521
|
}
|
|
2407
2522
|
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2408
2523
|
function isRoutableSourceFile(name) {
|
|
2409
|
-
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.");
|
|
2524
|
+
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2410
2525
|
}
|
|
2411
2526
|
function findRouterFilesRecursive(dir, filter, results) {
|
|
2412
2527
|
let entries;
|
|
@@ -2421,9 +2536,10 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2421
2536
|
const childDirs = [];
|
|
2422
2537
|
const routerFilesInDir = [];
|
|
2423
2538
|
for (const entry of entries) {
|
|
2424
|
-
const fullPath =
|
|
2539
|
+
const fullPath = join(dir, entry.name);
|
|
2425
2540
|
if (entry.isDirectory()) {
|
|
2426
|
-
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
2541
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
|
|
2542
|
+
continue;
|
|
2427
2543
|
childDirs.push(fullPath);
|
|
2428
2544
|
continue;
|
|
2429
2545
|
}
|
|
@@ -2475,7 +2591,7 @@ Router root: ${conflict.ancestor}
|
|
|
2475
2591
|
Nested router: ${conflict.nested}
|
|
2476
2592
|
Move the nested router into a sibling directory or configure it as a separate app root.`;
|
|
2477
2593
|
}
|
|
2478
|
-
function
|
|
2594
|
+
function extractUrlsFromRouter(code) {
|
|
2479
2595
|
const sourceFile = ts5.createSourceFile(
|
|
2480
2596
|
"router.tsx",
|
|
2481
2597
|
code,
|
|
@@ -2489,24 +2605,70 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2489
2605
|
const callee = node.expression;
|
|
2490
2606
|
return ts5.isIdentifier(callee) && callee.text === "createRouter";
|
|
2491
2607
|
}
|
|
2608
|
+
function isInlineBuilder(node) {
|
|
2609
|
+
return ts5.isArrowFunction(node) || ts5.isFunctionExpression(node);
|
|
2610
|
+
}
|
|
2611
|
+
function isRoutesOnCreateRouter(node) {
|
|
2612
|
+
if (!ts5.isPropertyAccessExpression(node.expression) || node.expression.name.text !== "routes")
|
|
2613
|
+
return false;
|
|
2614
|
+
let inner = node.expression.expression;
|
|
2615
|
+
while (ts5.isCallExpression(inner) && ts5.isPropertyAccessExpression(inner.expression)) {
|
|
2616
|
+
inner = inner.expression.expression;
|
|
2617
|
+
}
|
|
2618
|
+
return isCreateRouterCall(inner);
|
|
2619
|
+
}
|
|
2492
2620
|
function visit(node) {
|
|
2493
2621
|
if (result) return;
|
|
2494
|
-
if (ts5.isCallExpression(node) &&
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
}
|
|
2499
|
-
|
|
2500
|
-
result = node.arguments[0].text;
|
|
2501
|
-
return;
|
|
2622
|
+
if (ts5.isCallExpression(node) && node.arguments.length >= 1 && isRoutesOnCreateRouter(node)) {
|
|
2623
|
+
const arg = node.arguments[0];
|
|
2624
|
+
if (ts5.isIdentifier(arg)) {
|
|
2625
|
+
result = { kind: "variable", name: arg.text };
|
|
2626
|
+
} else if (isInlineBuilder(arg)) {
|
|
2627
|
+
result = { kind: "inline", block: arg.getText(sourceFile) };
|
|
2502
2628
|
}
|
|
2629
|
+
return;
|
|
2503
2630
|
}
|
|
2504
2631
|
if (isCreateRouterCall(node)) {
|
|
2505
2632
|
const callExpr = node;
|
|
2506
|
-
for (const
|
|
2633
|
+
for (const callArg of callExpr.arguments) {
|
|
2634
|
+
if (ts5.isObjectLiteralExpression(callArg)) {
|
|
2635
|
+
for (const prop of callArg.properties) {
|
|
2636
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "urls") {
|
|
2637
|
+
if (ts5.isIdentifier(prop.initializer)) {
|
|
2638
|
+
result = { kind: "variable", name: prop.initializer.text };
|
|
2639
|
+
} else if (isInlineBuilder(prop.initializer)) {
|
|
2640
|
+
result = {
|
|
2641
|
+
kind: "inline",
|
|
2642
|
+
block: prop.initializer.getText(sourceFile)
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
return;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
ts5.forEachChild(node, visit);
|
|
2652
|
+
}
|
|
2653
|
+
visit(sourceFile);
|
|
2654
|
+
return result;
|
|
2655
|
+
}
|
|
2656
|
+
function extractBasenameFromRouter(code) {
|
|
2657
|
+
const sourceFile = ts5.createSourceFile(
|
|
2658
|
+
"router.tsx",
|
|
2659
|
+
code,
|
|
2660
|
+
ts5.ScriptTarget.Latest,
|
|
2661
|
+
true,
|
|
2662
|
+
ts5.ScriptKind.TSX
|
|
2663
|
+
);
|
|
2664
|
+
let result;
|
|
2665
|
+
function visit(node) {
|
|
2666
|
+
if (result !== void 0) return;
|
|
2667
|
+
if (ts5.isCallExpression(node) && ts5.isIdentifier(node.expression) && node.expression.text === "createRouter") {
|
|
2668
|
+
for (const arg of node.arguments) {
|
|
2507
2669
|
if (ts5.isObjectLiteralExpression(arg)) {
|
|
2508
2670
|
for (const prop of arg.properties) {
|
|
2509
|
-
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "
|
|
2671
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "basename" && ts5.isStringLiteral(prop.initializer)) {
|
|
2510
2672
|
result = prop.initializer.text;
|
|
2511
2673
|
return;
|
|
2512
2674
|
}
|
|
@@ -2519,6 +2681,19 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2519
2681
|
visit(sourceFile);
|
|
2520
2682
|
return result;
|
|
2521
2683
|
}
|
|
2684
|
+
function applyBasenameToRoutes(result, basename3) {
|
|
2685
|
+
const prefixed = {};
|
|
2686
|
+
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
2687
|
+
if (pattern === "/") {
|
|
2688
|
+
prefixed[name] = basename3;
|
|
2689
|
+
} else if (basename3.endsWith("/") && pattern.startsWith("/")) {
|
|
2690
|
+
prefixed[name] = basename3 + pattern.slice(1);
|
|
2691
|
+
} else {
|
|
2692
|
+
prefixed[name] = basename3 + pattern;
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
2696
|
+
}
|
|
2522
2697
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2523
2698
|
let routerSource;
|
|
2524
2699
|
try {
|
|
@@ -2526,19 +2701,40 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2526
2701
|
} catch {
|
|
2527
2702
|
return { routes: {}, searchSchemas: {} };
|
|
2528
2703
|
}
|
|
2529
|
-
const
|
|
2530
|
-
if (!
|
|
2704
|
+
const extraction = extractUrlsFromRouter(routerSource);
|
|
2705
|
+
if (!extraction) {
|
|
2531
2706
|
return { routes: {}, searchSchemas: {} };
|
|
2532
2707
|
}
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2708
|
+
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
2709
|
+
const basename3 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
|
|
2710
|
+
let result;
|
|
2711
|
+
if (extraction.kind === "inline") {
|
|
2712
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2713
|
+
routerFilePath,
|
|
2714
|
+
void 0,
|
|
2715
|
+
void 0,
|
|
2716
|
+
void 0,
|
|
2717
|
+
extraction.block
|
|
2718
|
+
);
|
|
2719
|
+
} else {
|
|
2720
|
+
const imported = resolveImportedVariable(routerSource, extraction.name);
|
|
2721
|
+
if (imported) {
|
|
2722
|
+
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2723
|
+
if (!targetFile) {
|
|
2724
|
+
return { routes: {}, searchSchemas: {} };
|
|
2725
|
+
}
|
|
2726
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2727
|
+
targetFile,
|
|
2728
|
+
imported.exportedName
|
|
2729
|
+
);
|
|
2730
|
+
} else {
|
|
2731
|
+
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
2538
2732
|
}
|
|
2539
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2540
2733
|
}
|
|
2541
|
-
|
|
2734
|
+
if (basename3) {
|
|
2735
|
+
result = applyBasenameToRoutes(result, basename3);
|
|
2736
|
+
}
|
|
2737
|
+
return result;
|
|
2542
2738
|
}
|
|
2543
2739
|
function findRouterFiles(root, filter) {
|
|
2544
2740
|
const result = [];
|
|
@@ -2547,7 +2743,7 @@ function findRouterFiles(root, filter) {
|
|
|
2547
2743
|
}
|
|
2548
2744
|
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
2549
2745
|
try {
|
|
2550
|
-
const oldCombinedPath =
|
|
2746
|
+
const oldCombinedPath = join(root, "src", "named-routes.gen.ts");
|
|
2551
2747
|
if (existsSync3(oldCombinedPath)) {
|
|
2552
2748
|
unlinkSync(oldCombinedPath);
|
|
2553
2749
|
console.log(
|
|
@@ -2563,31 +2759,21 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2563
2759
|
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
2564
2760
|
}
|
|
2565
2761
|
for (const routerFilePath of routerFilePaths) {
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
routerSource
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
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);
|
|
2762
|
+
const result = buildCombinedRouteMapForRouterFile(routerFilePath);
|
|
2763
|
+
if (Object.keys(result.routes).length === 0 && Object.keys(result.searchSchemas).length === 0) {
|
|
2764
|
+
let routerSource;
|
|
2765
|
+
try {
|
|
2766
|
+
routerSource = readFileSync2(routerFilePath, "utf-8");
|
|
2767
|
+
} catch {
|
|
2768
|
+
continue;
|
|
2769
|
+
}
|
|
2770
|
+
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
2585
2771
|
}
|
|
2586
2772
|
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2587
2773
|
/\.(tsx?|jsx?)$/,
|
|
2588
2774
|
""
|
|
2589
2775
|
);
|
|
2590
|
-
const outPath =
|
|
2776
|
+
const outPath = join(
|
|
2591
2777
|
dirname2(routerFilePath),
|
|
2592
2778
|
`${routerBasename}.named-routes.gen.ts`
|
|
2593
2779
|
);
|
|
@@ -2717,8 +2903,9 @@ function createVersionPlugin() {
|
|
|
2717
2903
|
let isDev = false;
|
|
2718
2904
|
let server = null;
|
|
2719
2905
|
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
2906
|
+
let versionCounter = 0;
|
|
2720
2907
|
const bumpVersion = (reason) => {
|
|
2721
|
-
currentVersion = Date.now().toString(16);
|
|
2908
|
+
currentVersion = Date.now().toString(16) + String(++versionCounter);
|
|
2722
2909
|
console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
|
|
2723
2910
|
const rscEnv = server?.environments?.rsc;
|
|
2724
2911
|
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
@@ -2774,6 +2961,9 @@ function createVersionPlugin() {
|
|
|
2774
2961
|
if (!isDev) return;
|
|
2775
2962
|
const isRscModule = this.environment?.name === "rsc";
|
|
2776
2963
|
if (!isRscModule) return;
|
|
2964
|
+
if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2777
2967
|
if (isCodeModule(ctx.file)) {
|
|
2778
2968
|
const filePath = normalizeModuleId(ctx.file);
|
|
2779
2969
|
const previousSignature = clientModuleSignatures.get(filePath);
|
|
@@ -2803,6 +2993,86 @@ function createVersionPlugin() {
|
|
|
2803
2993
|
|
|
2804
2994
|
// src/vite/utils/shared-utils.ts
|
|
2805
2995
|
import * as Vite from "vite";
|
|
2996
|
+
|
|
2997
|
+
// src/vite/plugins/performance-tracks.ts
|
|
2998
|
+
import { readFile } from "node:fs/promises";
|
|
2999
|
+
|
|
3000
|
+
// src/vite/debug.ts
|
|
3001
|
+
import debugFactory from "debug";
|
|
3002
|
+
if (process.env.INTERNAL_RANGO_DEBUG) {
|
|
3003
|
+
const existing = debugFactory.disable();
|
|
3004
|
+
debugFactory.enable(existing ? `${existing},rango:*` : "rango:*");
|
|
3005
|
+
}
|
|
3006
|
+
function createRangoDebugger(namespace) {
|
|
3007
|
+
const instance = debugFactory(namespace);
|
|
3008
|
+
return instance.enabled ? instance : void 0;
|
|
3009
|
+
}
|
|
3010
|
+
async function timed(debug2, label, fn) {
|
|
3011
|
+
if (!debug2) return await fn();
|
|
3012
|
+
const start = performance.now();
|
|
3013
|
+
try {
|
|
3014
|
+
return await fn();
|
|
3015
|
+
} finally {
|
|
3016
|
+
debug2("%s (%sms)", label, (performance.now() - start).toFixed(1));
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
// src/vite/plugins/performance-tracks.ts
|
|
3021
|
+
var debug = createRangoDebugger("rango:transform");
|
|
3022
|
+
var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
|
|
3023
|
+
function buildPatchReplacement(match, debugInfoVar) {
|
|
3024
|
+
return `${match}
|
|
3025
|
+
if (${debugInfoVar} && 0 === ${debugInfoVar}.length && "fulfilled" === root.status) {
|
|
3026
|
+
var _resolved = "function" === typeof resolveLazy ? resolveLazy(root.value) : root.value;
|
|
3027
|
+
if ("object" === typeof _resolved && null !== _resolved && isArrayImpl(_resolved._debugInfo)) {
|
|
3028
|
+
${debugInfoVar} = _resolved._debugInfo;
|
|
3029
|
+
}
|
|
3030
|
+
}`;
|
|
3031
|
+
}
|
|
3032
|
+
function patchRsdwClientDebugInfoRecovery(code) {
|
|
3033
|
+
const match = code.match(RSDW_PATCH_RE);
|
|
3034
|
+
if (!match) {
|
|
3035
|
+
return { code, debugInfoVar: null };
|
|
3036
|
+
}
|
|
3037
|
+
return {
|
|
3038
|
+
code: code.replace(match[1], buildPatchReplacement(match[1], match[2])),
|
|
3039
|
+
debugInfoVar: match[2]
|
|
3040
|
+
};
|
|
3041
|
+
}
|
|
3042
|
+
function performanceTracksOptimizeDepsPlugin() {
|
|
3043
|
+
return {
|
|
3044
|
+
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
3045
|
+
setup(build) {
|
|
3046
|
+
build.onLoad(
|
|
3047
|
+
{
|
|
3048
|
+
filter: /react-server-dom-webpack-client\.browser\.(development|production)\.js$/
|
|
3049
|
+
},
|
|
3050
|
+
async (args) => {
|
|
3051
|
+
const code = await readFile(args.path, "utf8");
|
|
3052
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3053
|
+
return {
|
|
3054
|
+
contents: patched.code,
|
|
3055
|
+
loader: "js"
|
|
3056
|
+
};
|
|
3057
|
+
}
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
};
|
|
3061
|
+
}
|
|
3062
|
+
function performanceTracksPlugin() {
|
|
3063
|
+
return {
|
|
3064
|
+
name: "@rangojs/router:performance-tracks",
|
|
3065
|
+
transform(code, id) {
|
|
3066
|
+
if (!id.includes("react-server-dom") || !id.includes("client")) return;
|
|
3067
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3068
|
+
if (!patched.debugInfoVar) return;
|
|
3069
|
+
debug?.("patched RSDW client (var: %s)", patched.debugInfoVar);
|
|
3070
|
+
return patched.code;
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
// src/vite/utils/shared-utils.ts
|
|
2806
3076
|
var versionEsbuildPlugin = {
|
|
2807
3077
|
name: "@rangojs/router-version",
|
|
2808
3078
|
setup(build) {
|
|
@@ -2820,7 +3090,7 @@ var versionEsbuildPlugin = {
|
|
|
2820
3090
|
}
|
|
2821
3091
|
};
|
|
2822
3092
|
var sharedEsbuildOptions = {
|
|
2823
|
-
plugins: [versionEsbuildPlugin]
|
|
3093
|
+
plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
2824
3094
|
};
|
|
2825
3095
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
2826
3096
|
const virtualModules = {};
|
|
@@ -2903,11 +3173,11 @@ ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2
|
|
|
2903
3173
|
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
2904
3174
|
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
2905
3175
|
${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}
|
|
3176
|
+
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
2907
3177
|
${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
3178
|
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
2909
|
-
${dim} * ${reset}${bold}\u2551 \
|
|
2910
|
-
${bold}\u2550\u2550\u2550\
|
|
3179
|
+
${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
|
|
3180
|
+
${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
2911
3181
|
|
|
2912
3182
|
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
2913
3183
|
`;
|
|
@@ -3026,6 +3296,8 @@ function createCjsToEsmPlugin() {
|
|
|
3026
3296
|
import { createServer as createViteServer } from "vite";
|
|
3027
3297
|
import { resolve as resolve8 } from "node:path";
|
|
3028
3298
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3299
|
+
import { createRequire as createRequire2, register } from "node:module";
|
|
3300
|
+
import { pathToFileURL } from "node:url";
|
|
3029
3301
|
|
|
3030
3302
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3031
3303
|
function createVirtualStubPlugin() {
|
|
@@ -3051,8 +3323,115 @@ function createVirtualStubPlugin() {
|
|
|
3051
3323
|
};
|
|
3052
3324
|
}
|
|
3053
3325
|
|
|
3326
|
+
// src/vite/plugins/cloudflare-protocol-stub.ts
|
|
3327
|
+
var VIRTUAL_PREFIX = "virtual:rango-cloudflare-stub-";
|
|
3328
|
+
var NULL_PREFIX = "\0" + VIRTUAL_PREFIX;
|
|
3329
|
+
var CF_PREFIX = "cloudflare:";
|
|
3330
|
+
var BUILD_ENV_GLOBAL_KEY = "__rango_build_env__";
|
|
3331
|
+
var SOURCE_EXT_RE = /\.[mc]?[jt]sx?$/;
|
|
3332
|
+
var IMPORT_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
3333
|
+
"ImportDeclaration",
|
|
3334
|
+
"ImportExpression",
|
|
3335
|
+
"ExportNamedDeclaration",
|
|
3336
|
+
"ExportAllDeclaration"
|
|
3337
|
+
]);
|
|
3338
|
+
var STUBS = {
|
|
3339
|
+
"cloudflare:workers": `
|
|
3340
|
+
export class DurableObject { constructor(_ctx, _env) {} }
|
|
3341
|
+
export class WorkerEntrypoint { constructor(_ctx, _env) {} }
|
|
3342
|
+
export class WorkflowEntrypoint { constructor(_ctx, _env) {} }
|
|
3343
|
+
export class RpcTarget {}
|
|
3344
|
+
export const env = globalThis[${JSON.stringify(BUILD_ENV_GLOBAL_KEY)}] ?? {};
|
|
3345
|
+
export default {};
|
|
3346
|
+
`,
|
|
3347
|
+
"cloudflare:email": `
|
|
3348
|
+
export class EmailMessage { constructor(_from, _to, _raw) {} }
|
|
3349
|
+
export default {};
|
|
3350
|
+
`,
|
|
3351
|
+
"cloudflare:sockets": `
|
|
3352
|
+
export function connect() { return {}; }
|
|
3353
|
+
export default {};
|
|
3354
|
+
`,
|
|
3355
|
+
"cloudflare:workflows": `
|
|
3356
|
+
export class NonRetryableError extends Error {
|
|
3357
|
+
constructor(message, name) { super(message); this.name = name ?? "NonRetryableError"; }
|
|
3358
|
+
}
|
|
3359
|
+
export default {};
|
|
3360
|
+
`
|
|
3361
|
+
};
|
|
3362
|
+
var FALLBACK_STUB = `export default {};
|
|
3363
|
+
`;
|
|
3364
|
+
function createCloudflareProtocolStubPlugin() {
|
|
3365
|
+
return {
|
|
3366
|
+
name: "@rangojs/router:cloudflare-protocol-stub",
|
|
3367
|
+
transform(code, id) {
|
|
3368
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
3369
|
+
if (!SOURCE_EXT_RE.test(cleanId)) return null;
|
|
3370
|
+
if (!code.includes(CF_PREFIX)) return null;
|
|
3371
|
+
let ast;
|
|
3372
|
+
try {
|
|
3373
|
+
ast = this.parse(code);
|
|
3374
|
+
} catch {
|
|
3375
|
+
return null;
|
|
3376
|
+
}
|
|
3377
|
+
const hits = [];
|
|
3378
|
+
walk(ast, (node) => {
|
|
3379
|
+
if (!IMPORT_NODE_TYPES.has(node.type)) return;
|
|
3380
|
+
const source = node.source;
|
|
3381
|
+
if (!source || source.type !== "Literal") return;
|
|
3382
|
+
if (typeof source.value !== "string") return;
|
|
3383
|
+
if (!source.value.startsWith(CF_PREFIX)) return;
|
|
3384
|
+
if (typeof source.start !== "number" || typeof source.end !== "number")
|
|
3385
|
+
return;
|
|
3386
|
+
hits.push({
|
|
3387
|
+
start: source.start,
|
|
3388
|
+
end: source.end,
|
|
3389
|
+
value: source.value
|
|
3390
|
+
});
|
|
3391
|
+
});
|
|
3392
|
+
if (hits.length === 0) return null;
|
|
3393
|
+
hits.sort((a, b) => b.start - a.start);
|
|
3394
|
+
let out = code;
|
|
3395
|
+
for (const hit of hits) {
|
|
3396
|
+
const submodule = hit.value.slice(CF_PREFIX.length);
|
|
3397
|
+
const quote = code[hit.start] === "'" ? "'" : '"';
|
|
3398
|
+
out = out.slice(0, hit.start) + quote + VIRTUAL_PREFIX + submodule + quote + out.slice(hit.end);
|
|
3399
|
+
}
|
|
3400
|
+
return { code: out, map: null };
|
|
3401
|
+
},
|
|
3402
|
+
resolveId(id) {
|
|
3403
|
+
if (id.startsWith(VIRTUAL_PREFIX)) {
|
|
3404
|
+
return "\0" + id;
|
|
3405
|
+
}
|
|
3406
|
+
return null;
|
|
3407
|
+
},
|
|
3408
|
+
load(id) {
|
|
3409
|
+
if (!id.startsWith(NULL_PREFIX)) return null;
|
|
3410
|
+
const submodule = id.slice(NULL_PREFIX.length);
|
|
3411
|
+
const specifier = CF_PREFIX + submodule;
|
|
3412
|
+
return STUBS[specifier] ?? FALLBACK_STUB;
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
function walk(node, visit) {
|
|
3417
|
+
if (!node || typeof node !== "object") return;
|
|
3418
|
+
if (Array.isArray(node)) {
|
|
3419
|
+
for (const child of node) walk(child, visit);
|
|
3420
|
+
return;
|
|
3421
|
+
}
|
|
3422
|
+
const n = node;
|
|
3423
|
+
if (typeof n.type !== "string") return;
|
|
3424
|
+
visit(n);
|
|
3425
|
+
for (const key in n) {
|
|
3426
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") {
|
|
3427
|
+
continue;
|
|
3428
|
+
}
|
|
3429
|
+
walk(n[key], visit);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3054
3433
|
// src/vite/plugins/client-ref-hashing.ts
|
|
3055
|
-
import { relative
|
|
3434
|
+
import { relative } from "node:path";
|
|
3056
3435
|
import { createHash as createHash2 } from "node:crypto";
|
|
3057
3436
|
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3058
3437
|
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
@@ -3065,10 +3444,10 @@ function computeProductionHash(projectRoot, refKey) {
|
|
|
3065
3444
|
const absPath = decodeURIComponent(
|
|
3066
3445
|
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3067
3446
|
);
|
|
3068
|
-
toHash =
|
|
3447
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3069
3448
|
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3070
3449
|
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3071
|
-
toHash =
|
|
3450
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3072
3451
|
} else if (refKey.startsWith("/")) {
|
|
3073
3452
|
toHash = refKey.slice(1);
|
|
3074
3453
|
} else {
|
|
@@ -3209,8 +3588,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3209
3588
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
3210
3589
|
prerenderManifestEntries: null,
|
|
3211
3590
|
staticManifestEntries: null,
|
|
3212
|
-
|
|
3213
|
-
|
|
3591
|
+
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3592
|
+
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3214
3593
|
rscEntryFileName: null,
|
|
3215
3594
|
resolvedPrerenderModules: void 0,
|
|
3216
3595
|
resolvedStaticModules: void 0,
|
|
@@ -3293,8 +3672,17 @@ function jsonParseExpression(value) {
|
|
|
3293
3672
|
}
|
|
3294
3673
|
|
|
3295
3674
|
// src/context-var.ts
|
|
3675
|
+
var NON_CACHEABLE_KEYS = /* @__PURE__ */ Symbol.for(
|
|
3676
|
+
"rango:non-cacheable-keys"
|
|
3677
|
+
);
|
|
3678
|
+
function getNonCacheableKeys(variables) {
|
|
3679
|
+
if (!variables[NON_CACHEABLE_KEYS]) {
|
|
3680
|
+
variables[NON_CACHEABLE_KEYS] = /* @__PURE__ */ new Set();
|
|
3681
|
+
}
|
|
3682
|
+
return variables[NON_CACHEABLE_KEYS];
|
|
3683
|
+
}
|
|
3296
3684
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3297
|
-
function contextSet(variables, keyOrVar, value) {
|
|
3685
|
+
function contextSet(variables, keyOrVar, value, options) {
|
|
3298
3686
|
if (typeof keyOrVar === "string") {
|
|
3299
3687
|
if (FORBIDDEN_KEYS.has(keyOrVar)) {
|
|
3300
3688
|
throw new Error(
|
|
@@ -3302,8 +3690,14 @@ function contextSet(variables, keyOrVar, value) {
|
|
|
3302
3690
|
);
|
|
3303
3691
|
}
|
|
3304
3692
|
variables[keyOrVar] = value;
|
|
3693
|
+
if (options?.cache === false) {
|
|
3694
|
+
getNonCacheableKeys(variables).add(keyOrVar);
|
|
3695
|
+
}
|
|
3305
3696
|
} else {
|
|
3306
3697
|
variables[keyOrVar.key] = value;
|
|
3698
|
+
if (options?.cache === false) {
|
|
3699
|
+
getNonCacheableKeys(variables).add(keyOrVar.key);
|
|
3700
|
+
}
|
|
3307
3701
|
}
|
|
3308
3702
|
}
|
|
3309
3703
|
|
|
@@ -3326,13 +3720,31 @@ function encodePathParam(value) {
|
|
|
3326
3720
|
}
|
|
3327
3721
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3328
3722
|
let result = pattern;
|
|
3723
|
+
let hadOmittedOptional = false;
|
|
3329
3724
|
for (const [key, value] of Object.entries(params)) {
|
|
3330
3725
|
const escaped = escapeRegExp2(key);
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3726
|
+
if (value === "") {
|
|
3727
|
+
result = result.replace(
|
|
3728
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
3729
|
+
""
|
|
3730
|
+
);
|
|
3731
|
+
result = result.replace(`*${key}`, "");
|
|
3732
|
+
} else {
|
|
3733
|
+
result = result.replace(
|
|
3734
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
3735
|
+
encode(value)
|
|
3736
|
+
);
|
|
3737
|
+
result = result.replace(`*${key}`, encode(value));
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
3741
|
+
hadOmittedOptional = true;
|
|
3742
|
+
return "";
|
|
3743
|
+
});
|
|
3744
|
+
if (hadOmittedOptional) {
|
|
3745
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
3746
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3747
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
3336
3748
|
}
|
|
3337
3749
|
return result;
|
|
3338
3750
|
}
|
|
@@ -3442,84 +3854,126 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3442
3854
|
if (!params) return pattern;
|
|
3443
3855
|
return substituteRouteParams(pattern, params);
|
|
3444
3856
|
};
|
|
3857
|
+
let resolvedRoutes = 0;
|
|
3858
|
+
let totalDynamic = 0;
|
|
3445
3859
|
for (const { manifest } of allManifests) {
|
|
3446
3860
|
if (!manifest.prerenderRoutes) continue;
|
|
3447
|
-
const defs = manifest._prerenderDefs || {};
|
|
3448
3861
|
for (const routeName of manifest.prerenderRoutes) {
|
|
3449
3862
|
const pattern = manifest.routeManifest[routeName];
|
|
3450
|
-
if (
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3863
|
+
if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
|
|
3864
|
+
totalDynamic++;
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
const paramsStart = performance.now();
|
|
3869
|
+
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
3870
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3871
|
+
console.log(
|
|
3872
|
+
`[rsc-router] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3873
|
+
);
|
|
3874
|
+
}, 5e3) : void 0;
|
|
3875
|
+
try {
|
|
3876
|
+
for (const { manifest } of allManifests) {
|
|
3877
|
+
if (!manifest.prerenderRoutes) continue;
|
|
3878
|
+
const defs = manifest._prerenderDefs || {};
|
|
3879
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
3880
|
+
for (const routeName of manifest.prerenderRoutes) {
|
|
3881
|
+
const pattern = manifest.routeManifest[routeName];
|
|
3882
|
+
if (!pattern) continue;
|
|
3883
|
+
const def = defs[routeName];
|
|
3884
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
3885
|
+
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
3886
|
+
if (!hasDynamic) {
|
|
3887
|
+
entries.push({
|
|
3888
|
+
urlPath: pattern.replace(/\/$/, "") || "/",
|
|
3889
|
+
routeName,
|
|
3890
|
+
concurrency: 1,
|
|
3891
|
+
isPassthroughRoute
|
|
3892
|
+
});
|
|
3893
|
+
} else {
|
|
3894
|
+
if (def?.getParams) {
|
|
3895
|
+
try {
|
|
3896
|
+
const buildVars = {};
|
|
3897
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
3898
|
+
const getParamsCtx = {
|
|
3899
|
+
build: true,
|
|
3900
|
+
dev: !state.isBuildMode,
|
|
3901
|
+
set: ((keyOrVar, value) => {
|
|
3902
|
+
contextSet(buildVars, keyOrVar, value);
|
|
3903
|
+
}),
|
|
3904
|
+
reverse: getParamsReverse,
|
|
3905
|
+
get env() {
|
|
3906
|
+
if (buildEnv !== void 0) return buildEnv;
|
|
3907
|
+
throw new Error(
|
|
3908
|
+
"[rsc-router] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3909
|
+
);
|
|
3910
|
+
}
|
|
3911
|
+
};
|
|
3912
|
+
const paramsList = await def.getParams(getParamsCtx);
|
|
3913
|
+
const concurrency = def.options?.concurrency ?? 1;
|
|
3914
|
+
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
3915
|
+
for (const params of paramsList) {
|
|
3916
|
+
let url = substituteRouteParams(
|
|
3917
|
+
pattern,
|
|
3918
|
+
params,
|
|
3919
|
+
encodePathParam
|
|
3920
|
+
);
|
|
3921
|
+
if (url.includes("*")) {
|
|
3922
|
+
const wildcardValue = params["*"] ?? params.splat;
|
|
3923
|
+
if (wildcardValue !== void 0) {
|
|
3924
|
+
url = url.replace(
|
|
3925
|
+
/\*[^/]*$/,
|
|
3926
|
+
encodePathParam(wildcardValue)
|
|
3927
|
+
);
|
|
3928
|
+
}
|
|
3485
3929
|
}
|
|
3930
|
+
entries.push({
|
|
3931
|
+
urlPath: url.replace(/\/$/, "") || "/",
|
|
3932
|
+
routeName,
|
|
3933
|
+
concurrency,
|
|
3934
|
+
...hasBuildVars ? { buildVars } : {},
|
|
3935
|
+
isPassthroughRoute
|
|
3936
|
+
});
|
|
3486
3937
|
}
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
true
|
|
3938
|
+
resolvedRoutes++;
|
|
3939
|
+
} catch (err) {
|
|
3940
|
+
resolvedRoutes++;
|
|
3941
|
+
if (err.name === "Skip") {
|
|
3942
|
+
console.log(
|
|
3943
|
+
`[rsc-router] SKIP route "${routeName}" - ${err.message}`
|
|
3944
|
+
);
|
|
3945
|
+
notifyOnError(
|
|
3946
|
+
registry,
|
|
3947
|
+
err,
|
|
3948
|
+
"prerender",
|
|
3949
|
+
routeName,
|
|
3950
|
+
void 0,
|
|
3951
|
+
true
|
|
3952
|
+
);
|
|
3953
|
+
continue;
|
|
3954
|
+
}
|
|
3955
|
+
console.error(
|
|
3956
|
+
`[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
3507
3957
|
);
|
|
3508
|
-
|
|
3958
|
+
notifyOnError(registry, err, "prerender", routeName);
|
|
3959
|
+
throw err;
|
|
3509
3960
|
}
|
|
3510
|
-
|
|
3511
|
-
|
|
3961
|
+
} else {
|
|
3962
|
+
console.warn(
|
|
3963
|
+
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3512
3964
|
);
|
|
3513
|
-
notifyOnError(registry, err, "prerender", routeName);
|
|
3514
|
-
throw err;
|
|
3515
3965
|
}
|
|
3516
|
-
} else {
|
|
3517
|
-
console.warn(
|
|
3518
|
-
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3519
|
-
);
|
|
3520
3966
|
}
|
|
3521
3967
|
}
|
|
3522
3968
|
}
|
|
3969
|
+
} finally {
|
|
3970
|
+
if (progressInterval) {
|
|
3971
|
+
clearInterval(progressInterval);
|
|
3972
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3973
|
+
console.log(
|
|
3974
|
+
`[rsc-router] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3975
|
+
);
|
|
3976
|
+
}
|
|
3523
3977
|
}
|
|
3524
3978
|
if (entries.length === 0) return;
|
|
3525
3979
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
@@ -3546,7 +4000,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3546
4000
|
entry.urlPath,
|
|
3547
4001
|
{},
|
|
3548
4002
|
entry.buildVars,
|
|
3549
|
-
entry.isPassthroughRoute
|
|
4003
|
+
entry.isPassthroughRoute,
|
|
4004
|
+
state.resolvedBuildEnv
|
|
3550
4005
|
);
|
|
3551
4006
|
if (!result) continue;
|
|
3552
4007
|
if (result.passthrough) {
|
|
@@ -3670,7 +4125,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3670
4125
|
const result = await routerInstance.renderStaticSegment(
|
|
3671
4126
|
def.handler,
|
|
3672
4127
|
def.$$id,
|
|
3673
|
-
def.$$routePrefix
|
|
4128
|
+
def.$$routePrefix,
|
|
4129
|
+
state.resolvedBuildEnv,
|
|
4130
|
+
!state.isBuildMode
|
|
3674
4131
|
);
|
|
3675
4132
|
if (result) {
|
|
3676
4133
|
const hasHandles = Object.keys(result.handles).length > 0;
|
|
@@ -3795,7 +4252,11 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3795
4252
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
3796
4253
|
continue;
|
|
3797
4254
|
}
|
|
3798
|
-
const manifest = generateManifestFull(
|
|
4255
|
+
const manifest = generateManifestFull(
|
|
4256
|
+
router.urlpatterns,
|
|
4257
|
+
routerMountIndex,
|
|
4258
|
+
router.__basename ? { urlPrefix: router.__basename } : void 0
|
|
4259
|
+
);
|
|
3799
4260
|
routerMountIndex++;
|
|
3800
4261
|
allManifests.push({ id, manifest });
|
|
3801
4262
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
@@ -3937,7 +4398,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3937
4398
|
}
|
|
3938
4399
|
|
|
3939
4400
|
// src/vite/discovery/route-types-writer.ts
|
|
3940
|
-
import { dirname as dirname3, basename, join as
|
|
4401
|
+
import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
|
|
3941
4402
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
3942
4403
|
function filterUserNamedRoutes(manifest) {
|
|
3943
4404
|
const filtered = {};
|
|
@@ -3958,7 +4419,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3958
4419
|
/\.(tsx?|jsx?)$/,
|
|
3959
4420
|
""
|
|
3960
4421
|
);
|
|
3961
|
-
const outPath =
|
|
4422
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3962
4423
|
try {
|
|
3963
4424
|
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
3964
4425
|
} catch {
|
|
@@ -3971,7 +4432,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3971
4432
|
/\.(tsx?|jsx?)$/,
|
|
3972
4433
|
""
|
|
3973
4434
|
);
|
|
3974
|
-
const outPath =
|
|
4435
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3975
4436
|
if (!existsSync5(outPath)) continue;
|
|
3976
4437
|
try {
|
|
3977
4438
|
const content = readFileSync4(outPath, "utf-8");
|
|
@@ -3988,7 +4449,7 @@ function writeRouteTypesFiles(state) {
|
|
|
3988
4449
|
const entryDir = dirname3(
|
|
3989
4450
|
resolve6(state.projectRoot, state.resolvedEntryPath)
|
|
3990
4451
|
);
|
|
3991
|
-
const oldCombinedPath =
|
|
4452
|
+
const oldCombinedPath = join2(entryDir, "named-routes.gen.ts");
|
|
3992
4453
|
if (existsSync5(oldCombinedPath)) {
|
|
3993
4454
|
unlinkSync2(oldCombinedPath);
|
|
3994
4455
|
console.log(
|
|
@@ -4013,7 +4474,7 @@ Set an explicit \`id\` on createRouter() or check the call site.`
|
|
|
4013
4474
|
}
|
|
4014
4475
|
const routerDir = dirname3(sourceFile);
|
|
4015
4476
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4016
|
-
const outPath =
|
|
4477
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4017
4478
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
4018
4479
|
let effectiveSearchSchemas = routeSearchSchemas;
|
|
4019
4480
|
if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
|
|
@@ -4078,7 +4539,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4078
4539
|
}
|
|
4079
4540
|
const routerDir = dirname3(sourceFile);
|
|
4080
4541
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4081
|
-
const outPath =
|
|
4542
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4082
4543
|
const source = generateRouteTypesSource(
|
|
4083
4544
|
mergedRoutes,
|
|
4084
4545
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
@@ -4092,7 +4553,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4092
4553
|
}
|
|
4093
4554
|
|
|
4094
4555
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
4095
|
-
import { dirname as dirname4, basename as basename2, join as
|
|
4556
|
+
import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
|
|
4096
4557
|
function generateRoutesManifestModule(state) {
|
|
4097
4558
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
4098
4559
|
if (hasManifest) {
|
|
@@ -4107,7 +4568,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4107
4568
|
/\.(tsx?|jsx?)$/,
|
|
4108
4569
|
""
|
|
4109
4570
|
);
|
|
4110
|
-
const genPath =
|
|
4571
|
+
const genPath = join3(
|
|
4111
4572
|
routerDir,
|
|
4112
4573
|
`${routerBasename}.named-routes.gen.js`
|
|
4113
4574
|
).replaceAll("\\", "/");
|
|
@@ -4204,7 +4665,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4204
4665
|
/\.(tsx?|jsx?)$/,
|
|
4205
4666
|
""
|
|
4206
4667
|
);
|
|
4207
|
-
const genPath =
|
|
4668
|
+
const genPath = join3(
|
|
4208
4669
|
routerDir,
|
|
4209
4670
|
`${routerBasename}.named-routes.gen.js`
|
|
4210
4671
|
).replaceAll("\\", "/");
|
|
@@ -4244,48 +4705,45 @@ function postprocessBundle(state) {
|
|
|
4244
4705
|
);
|
|
4245
4706
|
const evictionTargets = [
|
|
4246
4707
|
{
|
|
4247
|
-
|
|
4708
|
+
infos: state.handlerChunkInfoMap.values(),
|
|
4248
4709
|
fnName: "Prerender",
|
|
4249
4710
|
brand: "prerenderHandler",
|
|
4250
4711
|
label: "handler code from RSC bundle"
|
|
4251
4712
|
},
|
|
4252
4713
|
{
|
|
4253
|
-
|
|
4714
|
+
infos: state.staticHandlerChunkInfoMap.values(),
|
|
4254
4715
|
fnName: "Static",
|
|
4255
4716
|
brand: "staticHandler",
|
|
4256
4717
|
label: "static handler code"
|
|
4257
4718
|
}
|
|
4258
4719
|
];
|
|
4259
4720
|
for (const target of evictionTargets) {
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4721
|
+
for (const info of target.infos) {
|
|
4722
|
+
const chunkPath = resolve7(state.projectRoot, "dist/rsc", info.fileName);
|
|
4723
|
+
try {
|
|
4724
|
+
const code = readFileSync5(chunkPath, "utf-8");
|
|
4725
|
+
const result = evictHandlerCode(
|
|
4726
|
+
code,
|
|
4727
|
+
info.exports,
|
|
4728
|
+
target.fnName,
|
|
4729
|
+
target.brand
|
|
4730
|
+
);
|
|
4731
|
+
if (result) {
|
|
4732
|
+
writeFileSync4(chunkPath, result.code);
|
|
4733
|
+
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4734
|
+
console.log(
|
|
4735
|
+
`[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4736
|
+
);
|
|
4737
|
+
}
|
|
4738
|
+
} catch (replaceErr) {
|
|
4739
|
+
console.warn(
|
|
4740
|
+
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4279
4741
|
);
|
|
4280
4742
|
}
|
|
4281
|
-
} catch (replaceErr) {
|
|
4282
|
-
console.warn(
|
|
4283
|
-
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4284
|
-
);
|
|
4285
4743
|
}
|
|
4286
4744
|
}
|
|
4287
|
-
state.
|
|
4288
|
-
state.
|
|
4745
|
+
state.handlerChunkInfoMap.clear();
|
|
4746
|
+
state.staticHandlerChunkInfoMap.clear();
|
|
4289
4747
|
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
4290
4748
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4291
4749
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
@@ -4328,7 +4786,7 @@ function postprocessBundle(state) {
|
|
|
4328
4786
|
}
|
|
4329
4787
|
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
4330
4788
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4331
|
-
if (!rscCode.includes("
|
|
4789
|
+
if (!rscCode.includes("__static-manifest.js")) {
|
|
4332
4790
|
try {
|
|
4333
4791
|
const manifestEntries = [];
|
|
4334
4792
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -4367,7 +4825,24 @@ function postprocessBundle(state) {
|
|
|
4367
4825
|
}
|
|
4368
4826
|
|
|
4369
4827
|
// src/vite/router-discovery.ts
|
|
4828
|
+
var debugDiscovery = createRangoDebugger("rango:discovery");
|
|
4829
|
+
var debugRoutes = createRangoDebugger("rango:routes");
|
|
4830
|
+
var loaderHookRegistered = false;
|
|
4831
|
+
function ensureCloudflareProtocolLoaderRegistered() {
|
|
4832
|
+
if (loaderHookRegistered) return;
|
|
4833
|
+
loaderHookRegistered = true;
|
|
4834
|
+
try {
|
|
4835
|
+
register(
|
|
4836
|
+
new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url)
|
|
4837
|
+
);
|
|
4838
|
+
} catch (err) {
|
|
4839
|
+
console.warn(
|
|
4840
|
+
`[rsc-router] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
|
|
4841
|
+
);
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4370
4844
|
async function createTempRscServer(state, options = {}) {
|
|
4845
|
+
ensureCloudflareProtocolLoaderRegistered();
|
|
4371
4846
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
4372
4847
|
return createViteServer({
|
|
4373
4848
|
root: state.projectRoot,
|
|
@@ -4390,6 +4865,7 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4390
4865
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
4391
4866
|
createVersionPlugin(),
|
|
4392
4867
|
createVirtualStubPlugin(),
|
|
4868
|
+
createCloudflareProtocolStubPlugin(),
|
|
4393
4869
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
4394
4870
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
4395
4871
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
@@ -4397,8 +4873,69 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4397
4873
|
]
|
|
4398
4874
|
});
|
|
4399
4875
|
}
|
|
4876
|
+
async function resolveBuildEnv(option, factoryCtx) {
|
|
4877
|
+
if (!option) return null;
|
|
4878
|
+
if (option === "auto") {
|
|
4879
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
4880
|
+
throw new Error(
|
|
4881
|
+
'[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4882
|
+
);
|
|
4883
|
+
}
|
|
4884
|
+
try {
|
|
4885
|
+
const userRequire = createRequire2(
|
|
4886
|
+
resolve8(factoryCtx.root, "package.json")
|
|
4887
|
+
);
|
|
4888
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
4889
|
+
const { getPlatformProxy } = await import(pathToFileURL(wranglerPath).href);
|
|
4890
|
+
const proxy = await getPlatformProxy();
|
|
4891
|
+
return {
|
|
4892
|
+
env: proxy.env,
|
|
4893
|
+
dispose: proxy.dispose
|
|
4894
|
+
};
|
|
4895
|
+
} catch (err) {
|
|
4896
|
+
throw new Error(
|
|
4897
|
+
`[rsc-router] buildEnv: "auto" requires wrangler to be installed.
|
|
4898
|
+
Install it with: pnpm add -D wrangler
|
|
4899
|
+
${err.message}`
|
|
4900
|
+
);
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
if (typeof option === "function") {
|
|
4904
|
+
return await option(factoryCtx);
|
|
4905
|
+
}
|
|
4906
|
+
return { env: option };
|
|
4907
|
+
}
|
|
4908
|
+
async function acquireBuildEnv(s, command, mode) {
|
|
4909
|
+
const option = s.opts?.buildEnv;
|
|
4910
|
+
if (!option) return false;
|
|
4911
|
+
const result = await resolveBuildEnv(option, {
|
|
4912
|
+
root: s.projectRoot,
|
|
4913
|
+
mode,
|
|
4914
|
+
command,
|
|
4915
|
+
preset: s.opts?.preset ?? "node"
|
|
4916
|
+
});
|
|
4917
|
+
if (!result) return false;
|
|
4918
|
+
s.resolvedBuildEnv = result.env;
|
|
4919
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
4920
|
+
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
4921
|
+
return true;
|
|
4922
|
+
}
|
|
4923
|
+
async function releaseBuildEnv(s) {
|
|
4924
|
+
if (s.buildEnvDispose) {
|
|
4925
|
+
try {
|
|
4926
|
+
await s.buildEnvDispose();
|
|
4927
|
+
} catch (err) {
|
|
4928
|
+
console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
|
|
4929
|
+
}
|
|
4930
|
+
s.buildEnvDispose = null;
|
|
4931
|
+
}
|
|
4932
|
+
s.resolvedBuildEnv = void 0;
|
|
4933
|
+
delete globalThis[BUILD_ENV_GLOBAL_KEY];
|
|
4934
|
+
}
|
|
4400
4935
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4401
4936
|
const s = createDiscoveryState(entryPath, opts);
|
|
4937
|
+
let viteCommand = "build";
|
|
4938
|
+
let viteMode = "production";
|
|
4402
4939
|
return {
|
|
4403
4940
|
name: "@rangojs/router:discovery",
|
|
4404
4941
|
config() {
|
|
@@ -4407,31 +4944,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4407
4944
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
|
|
4408
4945
|
}
|
|
4409
4946
|
};
|
|
4410
|
-
if (opts?.enableBuildPrerender) {
|
|
4411
|
-
config.environments = {
|
|
4412
|
-
rsc: {
|
|
4413
|
-
build: {
|
|
4414
|
-
rollupOptions: {
|
|
4415
|
-
output: {
|
|
4416
|
-
manualChunks(id) {
|
|
4417
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
4418
|
-
return "__prerender-handlers";
|
|
4419
|
-
}
|
|
4420
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
4421
|
-
return "__static-handlers";
|
|
4422
|
-
}
|
|
4423
|
-
}
|
|
4424
|
-
}
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
};
|
|
4429
|
-
}
|
|
4430
4947
|
return config;
|
|
4431
4948
|
},
|
|
4432
4949
|
configResolved(config) {
|
|
4433
4950
|
s.projectRoot = config.root;
|
|
4434
4951
|
s.isBuildMode = config.command === "build";
|
|
4952
|
+
viteCommand = config.command;
|
|
4953
|
+
viteMode = config.mode;
|
|
4435
4954
|
s.userResolveAlias = config.resolve.alias;
|
|
4436
4955
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4437
4956
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
@@ -4445,12 +4964,6 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4445
4964
|
s.resolvedEntryPath = entries[0];
|
|
4446
4965
|
}
|
|
4447
4966
|
}
|
|
4448
|
-
if (opts?.include || opts?.exclude) {
|
|
4449
|
-
s.scanFilter = createScanFilter(s.projectRoot, {
|
|
4450
|
-
include: opts.include,
|
|
4451
|
-
exclude: opts.exclude
|
|
4452
|
-
});
|
|
4453
|
-
}
|
|
4454
4967
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
4455
4968
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
4456
4969
|
writeCombinedRouteTypesWithTracking(s, { preserveIfLarger: true });
|
|
@@ -4482,6 +4995,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4482
4995
|
});
|
|
4483
4996
|
prerenderTempServer = null;
|
|
4484
4997
|
}
|
|
4998
|
+
releaseBuildEnv(s).catch(() => {
|
|
4999
|
+
});
|
|
4485
5000
|
});
|
|
4486
5001
|
async function getOrCreateTempServer() {
|
|
4487
5002
|
if (prerenderNodeRegistry) {
|
|
@@ -4508,14 +5023,33 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4508
5023
|
return null;
|
|
4509
5024
|
}
|
|
4510
5025
|
const discover = async () => {
|
|
5026
|
+
const discoverStart = performance.now();
|
|
4511
5027
|
const rscEnv = server.environments?.rsc;
|
|
4512
5028
|
if (!rscEnv?.runner) {
|
|
5029
|
+
debugDiscovery?.("dev: no rsc runner (cloudflare path)");
|
|
4513
5030
|
s.devServerOrigin = getDevServerOrigin();
|
|
4514
5031
|
try {
|
|
4515
|
-
|
|
5032
|
+
await timed(
|
|
5033
|
+
debugDiscovery,
|
|
5034
|
+
"acquireBuildEnv",
|
|
5035
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5036
|
+
);
|
|
5037
|
+
const tempRscEnv = await timed(
|
|
5038
|
+
debugDiscovery,
|
|
5039
|
+
"getOrCreateTempServer",
|
|
5040
|
+
() => getOrCreateTempServer()
|
|
5041
|
+
);
|
|
4516
5042
|
if (tempRscEnv) {
|
|
4517
|
-
await
|
|
4518
|
-
|
|
5043
|
+
await timed(
|
|
5044
|
+
debugDiscovery,
|
|
5045
|
+
"discoverRouters (cloudflare)",
|
|
5046
|
+
() => discoverRouters(s, tempRscEnv)
|
|
5047
|
+
);
|
|
5048
|
+
timed(
|
|
5049
|
+
debugDiscovery,
|
|
5050
|
+
"writeRouteTypesFiles",
|
|
5051
|
+
() => writeRouteTypesFiles(s)
|
|
5052
|
+
);
|
|
4519
5053
|
}
|
|
4520
5054
|
} catch (err) {
|
|
4521
5055
|
console.warn(
|
|
@@ -4523,26 +5057,54 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4523
5057
|
${err.stack}`
|
|
4524
5058
|
);
|
|
4525
5059
|
}
|
|
5060
|
+
debugDiscovery?.(
|
|
5061
|
+
"dev discovery done (%sms)",
|
|
5062
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5063
|
+
);
|
|
4526
5064
|
resolveDiscovery();
|
|
4527
5065
|
return;
|
|
4528
5066
|
}
|
|
4529
5067
|
try {
|
|
4530
|
-
|
|
4531
|
-
|
|
5068
|
+
debugDiscovery?.("dev: node path start");
|
|
5069
|
+
await timed(
|
|
5070
|
+
debugDiscovery,
|
|
5071
|
+
"acquireBuildEnv",
|
|
5072
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5073
|
+
);
|
|
5074
|
+
const serverMod = await timed(
|
|
5075
|
+
debugDiscovery,
|
|
5076
|
+
"import @rangojs/router/server",
|
|
5077
|
+
() => rscEnv.runner.import("@rangojs/router/server")
|
|
4532
5078
|
);
|
|
4533
5079
|
if (serverMod?.setManifestReadyPromise) {
|
|
4534
5080
|
serverMod.setManifestReadyPromise(discoveryPromise);
|
|
4535
5081
|
}
|
|
4536
|
-
await
|
|
5082
|
+
await timed(
|
|
5083
|
+
debugDiscovery,
|
|
5084
|
+
"discoverRouters",
|
|
5085
|
+
() => discoverRouters(s, rscEnv)
|
|
5086
|
+
);
|
|
4537
5087
|
s.devServerOrigin = getDevServerOrigin();
|
|
4538
|
-
|
|
4539
|
-
|
|
5088
|
+
timed(
|
|
5089
|
+
debugDiscovery,
|
|
5090
|
+
"writeRouteTypesFiles",
|
|
5091
|
+
() => writeRouteTypesFiles(s)
|
|
5092
|
+
);
|
|
5093
|
+
await timed(
|
|
5094
|
+
debugDiscovery,
|
|
5095
|
+
"propagateDiscoveryState",
|
|
5096
|
+
() => propagateDiscoveryState(rscEnv)
|
|
5097
|
+
);
|
|
4540
5098
|
} catch (err) {
|
|
4541
5099
|
console.warn(
|
|
4542
5100
|
`[rsc-router] Router discovery failed: ${err.message}
|
|
4543
5101
|
${err.stack}`
|
|
4544
5102
|
);
|
|
4545
5103
|
} finally {
|
|
5104
|
+
debugDiscovery?.(
|
|
5105
|
+
"dev discovery done (%sms)",
|
|
5106
|
+
(performance.now() - discoverStart).toFixed(1)
|
|
5107
|
+
);
|
|
4546
5108
|
resolveDiscovery();
|
|
4547
5109
|
}
|
|
4548
5110
|
};
|
|
@@ -4591,7 +5153,26 @@ ${err.stack}`
|
|
|
4591
5153
|
res.end("Missing pathname");
|
|
4592
5154
|
return;
|
|
4593
5155
|
}
|
|
4594
|
-
|
|
5156
|
+
const rscEnv = server.environments?.rsc;
|
|
5157
|
+
let registry = null;
|
|
5158
|
+
if (rscEnv?.runner && s.resolvedEntryPath) {
|
|
5159
|
+
try {
|
|
5160
|
+
await rscEnv.runner.import(s.resolvedEntryPath);
|
|
5161
|
+
const serverMod = await rscEnv.runner.import(
|
|
5162
|
+
"@rangojs/router/server"
|
|
5163
|
+
);
|
|
5164
|
+
registry = serverMod.RouterRegistry ?? null;
|
|
5165
|
+
} catch (err) {
|
|
5166
|
+
console.warn(
|
|
5167
|
+
`[rsc-router] Dev prerender module refresh failed: ${err.message}`
|
|
5168
|
+
);
|
|
5169
|
+
res.statusCode = 500;
|
|
5170
|
+
res.end(`Prerender handler error: ${err.message}`);
|
|
5171
|
+
return;
|
|
5172
|
+
}
|
|
5173
|
+
} else {
|
|
5174
|
+
registry = mainRegistry;
|
|
5175
|
+
}
|
|
4595
5176
|
if (!registry) {
|
|
4596
5177
|
if (!prerenderNodeRegistry) {
|
|
4597
5178
|
await getOrCreateTempServer();
|
|
@@ -4613,7 +5194,10 @@ ${err.stack}`
|
|
|
4613
5194
|
pathname,
|
|
4614
5195
|
{},
|
|
4615
5196
|
void 0,
|
|
4616
|
-
wantPassthrough
|
|
5197
|
+
wantPassthrough,
|
|
5198
|
+
s.resolvedBuildEnv,
|
|
5199
|
+
true
|
|
5200
|
+
// devMode: check getParams for passthrough routes
|
|
4617
5201
|
);
|
|
4618
5202
|
if (!result) continue;
|
|
4619
5203
|
if (result.passthrough) continue;
|
|
@@ -4665,15 +5249,32 @@ ${err.stack}`
|
|
|
4665
5249
|
const rscEnv = server.environments?.rsc;
|
|
4666
5250
|
if (!rscEnv?.runner || runtimeRediscoveryInProgress) return;
|
|
4667
5251
|
runtimeRediscoveryInProgress = true;
|
|
5252
|
+
const hmrStart = performance.now();
|
|
4668
5253
|
try {
|
|
4669
|
-
await
|
|
4670
|
-
|
|
4671
|
-
|
|
5254
|
+
await timed(
|
|
5255
|
+
debugDiscovery,
|
|
5256
|
+
"hmr discoverRouters",
|
|
5257
|
+
() => discoverRouters(s, rscEnv)
|
|
5258
|
+
);
|
|
5259
|
+
timed(
|
|
5260
|
+
debugDiscovery,
|
|
5261
|
+
"hmr writeRouteTypesFiles",
|
|
5262
|
+
() => writeRouteTypesFiles(s)
|
|
5263
|
+
);
|
|
5264
|
+
await timed(
|
|
5265
|
+
debugDiscovery,
|
|
5266
|
+
"hmr propagateDiscoveryState",
|
|
5267
|
+
() => propagateDiscoveryState(rscEnv)
|
|
5268
|
+
);
|
|
4672
5269
|
} catch (err) {
|
|
4673
5270
|
console.warn(
|
|
4674
5271
|
`[rsc-router] Runtime re-discovery failed: ${err.message}`
|
|
4675
5272
|
);
|
|
4676
5273
|
} finally {
|
|
5274
|
+
debugDiscovery?.(
|
|
5275
|
+
"hmr re-discovery done (%sms)",
|
|
5276
|
+
(performance.now() - hmrStart).toFixed(1)
|
|
5277
|
+
);
|
|
4677
5278
|
runtimeRediscoveryInProgress = false;
|
|
4678
5279
|
}
|
|
4679
5280
|
};
|
|
@@ -4746,13 +5347,24 @@ ${err.stack}`
|
|
|
4746
5347
|
async buildStart() {
|
|
4747
5348
|
if (!s.isBuildMode) return;
|
|
4748
5349
|
if (s.mergedRouteManifest !== null) return;
|
|
5350
|
+
const buildStartTime = performance.now();
|
|
5351
|
+
debugDiscovery?.("build: start");
|
|
4749
5352
|
resetStagedBuildAssets(s.projectRoot);
|
|
4750
5353
|
s.prerenderManifestEntries = null;
|
|
4751
5354
|
s.staticManifestEntries = null;
|
|
5355
|
+
await timed(
|
|
5356
|
+
debugDiscovery,
|
|
5357
|
+
"build acquireBuildEnv",
|
|
5358
|
+
() => acquireBuildEnv(s, viteCommand, viteMode)
|
|
5359
|
+
);
|
|
4752
5360
|
let tempServer = null;
|
|
4753
5361
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4754
5362
|
try {
|
|
4755
|
-
tempServer = await
|
|
5363
|
+
tempServer = await timed(
|
|
5364
|
+
debugDiscovery,
|
|
5365
|
+
"build createTempRscServer",
|
|
5366
|
+
() => createTempRscServer(s, { forceBuild: true })
|
|
5367
|
+
);
|
|
4756
5368
|
const rscEnv = tempServer.environments?.rsc;
|
|
4757
5369
|
if (!rscEnv?.runner) {
|
|
4758
5370
|
console.warn(
|
|
@@ -4766,8 +5378,16 @@ ${err.stack}`
|
|
|
4766
5378
|
if (tempIdsPlugin?.api?.staticHandlerModules) {
|
|
4767
5379
|
s.resolvedStaticModules = tempIdsPlugin.api.staticHandlerModules;
|
|
4768
5380
|
}
|
|
4769
|
-
await
|
|
4770
|
-
|
|
5381
|
+
await timed(
|
|
5382
|
+
debugDiscovery,
|
|
5383
|
+
"build discoverRouters",
|
|
5384
|
+
() => discoverRouters(s, rscEnv)
|
|
5385
|
+
);
|
|
5386
|
+
timed(
|
|
5387
|
+
debugDiscovery,
|
|
5388
|
+
"build writeRouteTypesFiles",
|
|
5389
|
+
() => writeRouteTypesFiles(s)
|
|
5390
|
+
);
|
|
4771
5391
|
} catch (err) {
|
|
4772
5392
|
const sourceFile = err.stack?.split("\n").find(
|
|
4773
5393
|
(line) => line.includes(s.projectRoot) && !line.includes("node_modules")
|
|
@@ -4786,8 +5406,17 @@ ${details}`
|
|
|
4786
5406
|
} finally {
|
|
4787
5407
|
delete globalThis.__rscRouterDiscoveryActive;
|
|
4788
5408
|
if (tempServer) {
|
|
4789
|
-
await
|
|
5409
|
+
await timed(
|
|
5410
|
+
debugDiscovery,
|
|
5411
|
+
"build tempServer.close",
|
|
5412
|
+
() => tempServer.close()
|
|
5413
|
+
);
|
|
4790
5414
|
}
|
|
5415
|
+
await releaseBuildEnv(s);
|
|
5416
|
+
debugDiscovery?.(
|
|
5417
|
+
"build discovery done (%sms)",
|
|
5418
|
+
(performance.now() - buildStartTime).toFixed(1)
|
|
5419
|
+
);
|
|
4791
5420
|
}
|
|
4792
5421
|
},
|
|
4793
5422
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -4804,17 +5433,36 @@ ${details}`
|
|
|
4804
5433
|
async load(id) {
|
|
4805
5434
|
if (id === "\0" + VIRTUAL_ROUTES_MANIFEST_ID) {
|
|
4806
5435
|
if (s.discoveryDone) {
|
|
4807
|
-
await
|
|
5436
|
+
await timed(
|
|
5437
|
+
debugRoutes,
|
|
5438
|
+
"await discoveryDone (manifest)",
|
|
5439
|
+
() => Promise.resolve(s.discoveryDone)
|
|
5440
|
+
);
|
|
4808
5441
|
}
|
|
4809
|
-
|
|
5442
|
+
const code = await timed(
|
|
5443
|
+
debugRoutes,
|
|
5444
|
+
"generateRoutesManifestModule",
|
|
5445
|
+
() => generateRoutesManifestModule(s)
|
|
5446
|
+
);
|
|
5447
|
+
debugRoutes?.("manifest module emitted (%d bytes)", code?.length ?? 0);
|
|
5448
|
+
return code;
|
|
4810
5449
|
}
|
|
4811
5450
|
const perRouterPrefix = "\0" + VIRTUAL_ROUTES_MANIFEST_ID + "/";
|
|
4812
5451
|
if (id.startsWith(perRouterPrefix)) {
|
|
4813
5452
|
if (s.discoveryDone) {
|
|
4814
|
-
await
|
|
5453
|
+
await timed(
|
|
5454
|
+
debugRoutes,
|
|
5455
|
+
"await discoveryDone (per-router)",
|
|
5456
|
+
() => Promise.resolve(s.discoveryDone)
|
|
5457
|
+
);
|
|
4815
5458
|
}
|
|
4816
5459
|
const routerId = id.slice(perRouterPrefix.length);
|
|
4817
|
-
|
|
5460
|
+
const code = await timed(
|
|
5461
|
+
debugRoutes,
|
|
5462
|
+
`generatePerRouterModule ${routerId}`,
|
|
5463
|
+
() => generatePerRouterModule(s, routerId)
|
|
5464
|
+
);
|
|
5465
|
+
return code;
|
|
4818
5466
|
}
|
|
4819
5467
|
return null;
|
|
4820
5468
|
},
|
|
@@ -4830,20 +5478,30 @@ ${details}`
|
|
|
4830
5478
|
}
|
|
4831
5479
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
4832
5480
|
return;
|
|
5481
|
+
s.handlerChunkInfoMap.clear();
|
|
5482
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
4833
5483
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
4834
5484
|
if (chunk.type !== "chunk") continue;
|
|
4835
|
-
if (
|
|
5485
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
4836
5486
|
const handlers = extractHandlerExportsFromChunk(
|
|
4837
5487
|
chunk.code,
|
|
4838
5488
|
s.resolvedPrerenderModules,
|
|
4839
5489
|
"Prerender",
|
|
4840
|
-
|
|
5490
|
+
false
|
|
4841
5491
|
);
|
|
4842
5492
|
if (handlers.length > 0) {
|
|
4843
|
-
|
|
5493
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
5494
|
+
if (existing) {
|
|
5495
|
+
existing.exports.push(...handlers);
|
|
5496
|
+
} else {
|
|
5497
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
5498
|
+
fileName,
|
|
5499
|
+
exports: handlers
|
|
5500
|
+
});
|
|
5501
|
+
}
|
|
4844
5502
|
}
|
|
4845
5503
|
}
|
|
4846
|
-
if (
|
|
5504
|
+
if (s.resolvedStaticModules?.size) {
|
|
4847
5505
|
const handlers = extractHandlerExportsFromChunk(
|
|
4848
5506
|
chunk.code,
|
|
4849
5507
|
s.resolvedStaticModules,
|
|
@@ -4851,7 +5509,15 @@ ${details}`
|
|
|
4851
5509
|
false
|
|
4852
5510
|
);
|
|
4853
5511
|
if (handlers.length > 0) {
|
|
4854
|
-
|
|
5512
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
5513
|
+
if (existing) {
|
|
5514
|
+
existing.exports.push(...handlers);
|
|
5515
|
+
} else {
|
|
5516
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
5517
|
+
fileName,
|
|
5518
|
+
exports: handlers
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
4855
5521
|
}
|
|
4856
5522
|
}
|
|
4857
5523
|
}
|
|
@@ -4872,14 +5538,30 @@ ${details}`
|
|
|
4872
5538
|
}
|
|
4873
5539
|
|
|
4874
5540
|
// src/vite/rango.ts
|
|
5541
|
+
var debugConfig = createRangoDebugger("rango:config");
|
|
4875
5542
|
async function rango(options) {
|
|
5543
|
+
const rangoStart = performance.now();
|
|
4876
5544
|
const resolvedOptions = options ?? { preset: "node" };
|
|
4877
5545
|
const preset = resolvedOptions.preset ?? "node";
|
|
4878
5546
|
const showBanner = resolvedOptions.banner ?? true;
|
|
5547
|
+
debugConfig?.("rango(%s) setup start", preset);
|
|
4879
5548
|
const plugins = [];
|
|
4880
|
-
const rangoAliases = getPackageAliases();
|
|
4881
|
-
const excludeDeps =
|
|
4882
|
-
|
|
5549
|
+
const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
|
|
5550
|
+
const excludeDeps = [
|
|
5551
|
+
...getExcludeDeps(),
|
|
5552
|
+
// plugin-rsc itself injects these into the client env's
|
|
5553
|
+
// optimizeDeps.include, which overrides exclude for the dep's own
|
|
5554
|
+
// pre-bundle entry. What exclude still controls is how *other*
|
|
5555
|
+
// pre-bundled deps treat imports of these specs (external vs inlined)
|
|
5556
|
+
// via esbuildCjsExternalPlugin. The cjs-to-esm transform in
|
|
5557
|
+
// plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
|
|
5558
|
+
// where client.browser's bare include fails to resolve and Vite ends up
|
|
5559
|
+
// serving the raw CJS file at dev-serve time.
|
|
5560
|
+
"@vitejs/plugin-rsc/browser",
|
|
5561
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser"
|
|
5562
|
+
];
|
|
5563
|
+
const pkg = getPublishedPackageName();
|
|
5564
|
+
const nested = (spec) => `${pkg} > ${spec}`;
|
|
4883
5565
|
const routerRef = { path: void 0 };
|
|
4884
5566
|
const prerenderEnabled = true;
|
|
4885
5567
|
if (preset === "cloudflare") {
|
|
@@ -4917,7 +5599,7 @@ async function rango(options) {
|
|
|
4917
5599
|
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
4918
5600
|
// Exclude rsc-router modules to ensure same Context instance
|
|
4919
5601
|
optimizeDeps: {
|
|
4920
|
-
include: ["rsc-html-stream/client"],
|
|
5602
|
+
include: [nested("rsc-html-stream/client")],
|
|
4921
5603
|
exclude: excludeDeps,
|
|
4922
5604
|
esbuildOptions: sharedEsbuildOptions
|
|
4923
5605
|
}
|
|
@@ -4942,8 +5624,10 @@ async function rango(options) {
|
|
|
4942
5624
|
"react-dom/static.edge",
|
|
4943
5625
|
"react/jsx-runtime",
|
|
4944
5626
|
"react/jsx-dev-runtime",
|
|
4945
|
-
"rsc-html-stream/server",
|
|
4946
|
-
|
|
5627
|
+
nested("rsc-html-stream/server"),
|
|
5628
|
+
nested(
|
|
5629
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5630
|
+
)
|
|
4947
5631
|
],
|
|
4948
5632
|
exclude: excludeDeps,
|
|
4949
5633
|
esbuildOptions: sharedEsbuildOptions
|
|
@@ -4958,7 +5642,9 @@ async function rango(options) {
|
|
|
4958
5642
|
"react",
|
|
4959
5643
|
"react/jsx-runtime",
|
|
4960
5644
|
"react/jsx-dev-runtime",
|
|
4961
|
-
|
|
5645
|
+
nested(
|
|
5646
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
5647
|
+
)
|
|
4962
5648
|
],
|
|
4963
5649
|
exclude: excludeDeps,
|
|
4964
5650
|
esbuildOptions: sharedEsbuildOptions
|
|
@@ -4975,6 +5661,7 @@ async function rango(options) {
|
|
|
4975
5661
|
}
|
|
4976
5662
|
});
|
|
4977
5663
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
5664
|
+
plugins.push(performanceTracksPlugin());
|
|
4978
5665
|
plugins.push(
|
|
4979
5666
|
rsc({
|
|
4980
5667
|
entries: finalEntries,
|
|
@@ -4983,153 +5670,126 @@ async function rango(options) {
|
|
|
4983
5670
|
);
|
|
4984
5671
|
plugins.push(clientRefDedup());
|
|
4985
5672
|
} else {
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
const
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
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:
|
|
5008
|
-
${list}`
|
|
5009
|
-
);
|
|
5010
|
-
}
|
|
5673
|
+
plugins.push({
|
|
5674
|
+
name: "@rangojs/router:auto-discover",
|
|
5675
|
+
config(userConfig) {
|
|
5676
|
+
if (routerRef.path) return;
|
|
5677
|
+
const root = userConfig.root ? resolve9(process.cwd(), userConfig.root) : process.cwd();
|
|
5678
|
+
const candidates = findRouterFiles(root);
|
|
5679
|
+
if (candidates.length === 1) {
|
|
5680
|
+
const abs = candidates[0];
|
|
5681
|
+
routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
5682
|
+
} else if (candidates.length > 1) {
|
|
5683
|
+
const list = candidates.map(
|
|
5684
|
+
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5685
|
+
).join("\n");
|
|
5686
|
+
throw new Error(`[rsc-router] Multiple routers found:
|
|
5687
|
+
${list}`);
|
|
5011
5688
|
}
|
|
5012
|
-
}
|
|
5013
|
-
}
|
|
5014
|
-
const
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
resolve: {
|
|
5043
|
-
alias: rangoAliases
|
|
5044
|
-
},
|
|
5045
|
-
environments: {
|
|
5046
|
-
client: {
|
|
5047
|
-
build: {
|
|
5048
|
-
rollupOptions: {
|
|
5049
|
-
output: {
|
|
5050
|
-
manualChunks: getManualChunks
|
|
5051
|
-
}
|
|
5052
|
-
}
|
|
5053
|
-
},
|
|
5054
|
-
// Always exclude rsc-router modules, conditionally add virtual entry
|
|
5055
|
-
optimizeDeps: {
|
|
5056
|
-
// Pre-bundle React and rsc-html-stream to prevent late discovery
|
|
5057
|
-
// triggering ERR_OUTDATED_OPTIMIZED_DEP on cold starts
|
|
5058
|
-
include: [
|
|
5059
|
-
"react",
|
|
5060
|
-
"react-dom",
|
|
5061
|
-
"react/jsx-runtime",
|
|
5062
|
-
"react/jsx-dev-runtime",
|
|
5063
|
-
"rsc-html-stream/client"
|
|
5064
|
-
],
|
|
5065
|
-
exclude: excludeDeps,
|
|
5066
|
-
esbuildOptions: sharedEsbuildOptions,
|
|
5067
|
-
...useVirtualClient && {
|
|
5068
|
-
// Tell Vite to scan the virtual entry for dependencies
|
|
5069
|
-
entries: [VIRTUAL_IDS.browser]
|
|
5070
|
-
}
|
|
5071
|
-
}
|
|
5072
|
-
},
|
|
5073
|
-
...useVirtualSSR && {
|
|
5074
|
-
ssr: {
|
|
5075
|
-
optimizeDeps: {
|
|
5076
|
-
entries: [VIRTUAL_IDS.ssr],
|
|
5077
|
-
// Pre-bundle all SSR deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
5078
|
-
include: [
|
|
5079
|
-
"react",
|
|
5080
|
-
"react-dom",
|
|
5081
|
-
"react-dom/server.edge",
|
|
5082
|
-
"react-dom/static.edge",
|
|
5083
|
-
"react/jsx-runtime",
|
|
5084
|
-
"react/jsx-dev-runtime",
|
|
5085
|
-
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5086
|
-
],
|
|
5087
|
-
exclude: excludeDeps,
|
|
5088
|
-
esbuildOptions: sharedEsbuildOptions
|
|
5689
|
+
}
|
|
5690
|
+
});
|
|
5691
|
+
const finalEntries = {
|
|
5692
|
+
client: VIRTUAL_IDS.browser,
|
|
5693
|
+
ssr: VIRTUAL_IDS.ssr,
|
|
5694
|
+
rsc: VIRTUAL_IDS.rsc
|
|
5695
|
+
};
|
|
5696
|
+
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
5697
|
+
let hasWarnedDuplicate = false;
|
|
5698
|
+
plugins.push({
|
|
5699
|
+
name: "@rangojs/router:rsc-integration",
|
|
5700
|
+
enforce: "pre",
|
|
5701
|
+
config() {
|
|
5702
|
+
return {
|
|
5703
|
+
optimizeDeps: {
|
|
5704
|
+
exclude: excludeDeps,
|
|
5705
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5706
|
+
},
|
|
5707
|
+
build: {
|
|
5708
|
+
rollupOptions: { onwarn }
|
|
5709
|
+
},
|
|
5710
|
+
resolve: {
|
|
5711
|
+
alias: rangoAliases
|
|
5712
|
+
},
|
|
5713
|
+
environments: {
|
|
5714
|
+
client: {
|
|
5715
|
+
build: {
|
|
5716
|
+
rollupOptions: {
|
|
5717
|
+
output: {
|
|
5718
|
+
manualChunks: getManualChunks
|
|
5089
5719
|
}
|
|
5090
5720
|
}
|
|
5091
5721
|
},
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5722
|
+
optimizeDeps: {
|
|
5723
|
+
include: [
|
|
5724
|
+
"react",
|
|
5725
|
+
"react-dom",
|
|
5726
|
+
"react/jsx-runtime",
|
|
5727
|
+
"react/jsx-dev-runtime",
|
|
5728
|
+
nested("rsc-html-stream/client")
|
|
5729
|
+
],
|
|
5730
|
+
exclude: excludeDeps,
|
|
5731
|
+
esbuildOptions: sharedEsbuildOptions,
|
|
5732
|
+
entries: [VIRTUAL_IDS.browser]
|
|
5733
|
+
}
|
|
5734
|
+
},
|
|
5735
|
+
ssr: {
|
|
5736
|
+
optimizeDeps: {
|
|
5737
|
+
entries: [VIRTUAL_IDS.ssr],
|
|
5738
|
+
include: [
|
|
5739
|
+
"react",
|
|
5740
|
+
"react-dom",
|
|
5741
|
+
"react-dom/server.edge",
|
|
5742
|
+
"react-dom/static.edge",
|
|
5743
|
+
"react/jsx-runtime",
|
|
5744
|
+
"react/jsx-dev-runtime",
|
|
5745
|
+
nested(
|
|
5746
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5747
|
+
)
|
|
5748
|
+
],
|
|
5749
|
+
exclude: excludeDeps,
|
|
5750
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5751
|
+
}
|
|
5752
|
+
},
|
|
5753
|
+
rsc: {
|
|
5754
|
+
optimizeDeps: {
|
|
5755
|
+
entries: [VIRTUAL_IDS.rsc],
|
|
5756
|
+
include: [
|
|
5757
|
+
"react",
|
|
5758
|
+
"react/jsx-runtime",
|
|
5759
|
+
"react/jsx-dev-runtime",
|
|
5760
|
+
nested(
|
|
5761
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
5762
|
+
)
|
|
5763
|
+
],
|
|
5764
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5106
5765
|
}
|
|
5107
5766
|
}
|
|
5108
|
-
};
|
|
5109
|
-
},
|
|
5110
|
-
configResolved(config) {
|
|
5111
|
-
if (showBanner) {
|
|
5112
|
-
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
5113
|
-
printBanner(mode, "node", rangoVersion);
|
|
5114
|
-
}
|
|
5115
|
-
const rscMinimalCount = config.plugins.filter(
|
|
5116
|
-
(p) => p.name === "rsc:minimal"
|
|
5117
|
-
).length;
|
|
5118
|
-
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5119
|
-
hasWarnedDuplicate = true;
|
|
5120
|
-
console.warn(
|
|
5121
|
-
"[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your config or use rango({ rsc: false }) for manual configuration."
|
|
5122
|
-
);
|
|
5123
5767
|
}
|
|
5768
|
+
};
|
|
5769
|
+
},
|
|
5770
|
+
configResolved(config) {
|
|
5771
|
+
if (showBanner) {
|
|
5772
|
+
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
5773
|
+
printBanner(mode, "node", rangoVersion);
|
|
5124
5774
|
}
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5775
|
+
const rscMinimalCount = config.plugins.filter(
|
|
5776
|
+
(p) => p.name === "rsc:minimal"
|
|
5777
|
+
).length;
|
|
5778
|
+
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5779
|
+
hasWarnedDuplicate = true;
|
|
5780
|
+
console.warn(
|
|
5781
|
+
"[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
|
|
5782
|
+
);
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
});
|
|
5786
|
+
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
5787
|
+
plugins.push(performanceTracksPlugin());
|
|
5788
|
+
plugins.push(
|
|
5789
|
+
rsc({
|
|
5790
|
+
entries: finalEntries
|
|
5791
|
+
})
|
|
5792
|
+
);
|
|
5133
5793
|
plugins.push(clientRefDedup());
|
|
5134
5794
|
}
|
|
5135
5795
|
plugins.push({
|
|
@@ -5157,20 +5817,24 @@ ${list}`
|
|
|
5157
5817
|
plugins.push(createVersionPlugin());
|
|
5158
5818
|
const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
|
|
5159
5819
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
plugins.push(createVersionInjectorPlugin(injectorEntryPath));
|
|
5820
|
+
if (preset === "cloudflare") {
|
|
5821
|
+
plugins.push(createVersionInjectorPlugin(void 0));
|
|
5163
5822
|
}
|
|
5164
5823
|
plugins.push(createCjsToEsmPlugin());
|
|
5165
5824
|
plugins.push(
|
|
5166
5825
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5167
5826
|
routerPathRef: discoveryRouterRef,
|
|
5168
5827
|
enableBuildPrerender: prerenderEnabled,
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
exclude: resolvedOptions.exclude
|
|
5828
|
+
buildEnv: options?.buildEnv,
|
|
5829
|
+
preset
|
|
5172
5830
|
})
|
|
5173
5831
|
);
|
|
5832
|
+
debugConfig?.(
|
|
5833
|
+
"rango(%s) setup done: %d plugin(s) (%sms)",
|
|
5834
|
+
preset,
|
|
5835
|
+
plugins.length,
|
|
5836
|
+
(performance.now() - rangoStart).toFixed(1)
|
|
5837
|
+
);
|
|
5174
5838
|
return plugins;
|
|
5175
5839
|
}
|
|
5176
5840
|
|
|
@@ -5181,29 +5845,75 @@ function poke() {
|
|
|
5181
5845
|
apply: "serve",
|
|
5182
5846
|
configureServer(server) {
|
|
5183
5847
|
const stdin = process.stdin;
|
|
5184
|
-
const
|
|
5848
|
+
const debug2 = process.env.RANGO_POKE_DEBUG === "1";
|
|
5849
|
+
const triggerReload = (source) => {
|
|
5850
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
5851
|
+
server.config.logger.info(` browser reload (${source})`, {
|
|
5852
|
+
timestamp: true
|
|
5853
|
+
});
|
|
5854
|
+
};
|
|
5855
|
+
const toBuffer = (chunk) => {
|
|
5856
|
+
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5857
|
+
};
|
|
5858
|
+
const formatChunk = (chunk) => {
|
|
5859
|
+
const data = toBuffer(chunk);
|
|
5860
|
+
const hex = Array.from(data).map((byte) => `0x${byte.toString(16).padStart(2, "0")}`).join(" ");
|
|
5861
|
+
const ascii = Array.from(data).map((byte) => {
|
|
5862
|
+
if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
|
|
5863
|
+
if (byte === 10) return "\\n";
|
|
5864
|
+
if (byte === 13) return "\\r";
|
|
5865
|
+
if (byte === 9) return "\\t";
|
|
5866
|
+
return ".";
|
|
5867
|
+
}).join("");
|
|
5868
|
+
return `len=${data.length} hex=[${hex}] ascii="${ascii}"`;
|
|
5869
|
+
};
|
|
5870
|
+
const readCtrlR = (chunk) => {
|
|
5871
|
+
const data = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5872
|
+
return data.length === 1 && data[0] === 18;
|
|
5873
|
+
};
|
|
5874
|
+
const readSubmittedCommands = (chunk) => {
|
|
5875
|
+
const text = toBuffer(chunk).toString("utf8").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
5876
|
+
if (!text.includes("\n")) return [];
|
|
5877
|
+
const lines = text.split("\n");
|
|
5878
|
+
lines.pop();
|
|
5879
|
+
return lines;
|
|
5880
|
+
};
|
|
5881
|
+
if (debug2) {
|
|
5882
|
+
server.config.logger.info(
|
|
5883
|
+
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5884
|
+
{ timestamp: true }
|
|
5885
|
+
);
|
|
5886
|
+
}
|
|
5185
5887
|
if (stdin.isTTY) {
|
|
5186
|
-
|
|
5888
|
+
server.config.logger.info(
|
|
5889
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
5890
|
+
{ timestamp: true }
|
|
5891
|
+
);
|
|
5187
5892
|
}
|
|
5188
5893
|
const onData = (data) => {
|
|
5189
|
-
if (
|
|
5190
|
-
|
|
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)", {
|
|
5894
|
+
if (debug2) {
|
|
5895
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5197
5896
|
timestamp: true
|
|
5198
5897
|
});
|
|
5199
5898
|
}
|
|
5899
|
+
if (readCtrlR(data)) {
|
|
5900
|
+
triggerReload("ctrl+r");
|
|
5901
|
+
return;
|
|
5902
|
+
}
|
|
5903
|
+
for (const command of readSubmittedCommands(data)) {
|
|
5904
|
+
if (command === "e") {
|
|
5905
|
+
triggerReload("e+enter");
|
|
5906
|
+
return;
|
|
5907
|
+
}
|
|
5908
|
+
if (command === "\x1Br") {
|
|
5909
|
+
triggerReload("option+r+enter");
|
|
5910
|
+
return;
|
|
5911
|
+
}
|
|
5912
|
+
}
|
|
5200
5913
|
};
|
|
5201
5914
|
stdin.on("data", onData);
|
|
5202
5915
|
server.httpServer?.on("close", () => {
|
|
5203
5916
|
stdin.off("data", onData);
|
|
5204
|
-
if (stdin.isTTY && previousRawMode !== null) {
|
|
5205
|
-
stdin.setRawMode(previousRawMode);
|
|
5206
|
-
}
|
|
5207
5917
|
});
|
|
5208
5918
|
}
|
|
5209
5919
|
};
|