@rangojs/router 0.0.0-experimental.57 → 0.0.0-experimental.57005a2b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -18
- package/dist/bin/rango.js +2 -1
- package/dist/vite/index.js +507 -192
- package/dist/vite/index.js.bak +5448 -0
- package/package.json +3 -3
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/intercept/SKILL.md +20 -0
- package/skills/layout/SKILL.md +22 -0
- package/skills/middleware/SKILL.md +32 -3
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +764 -0
- package/skills/parallel/SKILL.md +59 -0
- package/skills/prerender/SKILL.md +110 -68
- package/skills/rango/SKILL.md +24 -22
- package/skills/route/SKILL.md +24 -0
- package/src/__internal.ts +1 -1
- package/src/browser/navigation-bridge.ts +21 -2
- package/src/browser/navigation-client.ts +34 -6
- package/src/browser/partial-update.ts +14 -2
- package/src/browser/prefetch/cache.ts +16 -6
- package/src/browser/prefetch/fetch.ts +60 -4
- package/src/browser/react/Link.tsx +25 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/scroll-restoration.ts +10 -8
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/build/generate-manifest.ts +3 -6
- package/src/build/route-trie.ts +50 -24
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/client.tsx +84 -230
- package/src/handle.ts +40 -0
- package/src/index.rsc.ts +3 -1
- package/src/index.ts +46 -6
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +138 -77
- package/src/reverse.ts +25 -1
- package/src/route-definition/dsl-helpers.ts +194 -32
- package/src/route-definition/helpers-types.ts +61 -14
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/handler-context.ts +46 -6
- package/src/router/lazy-includes.ts +5 -5
- package/src/router/loader-resolution.ts +147 -19
- package/src/router/manifest.ts +12 -7
- package/src/router/match-api.ts +124 -189
- package/src/router/match-middleware/cache-lookup.ts +24 -7
- package/src/router/match-middleware/segment-resolution.ts +53 -0
- package/src/router/match-result.ts +82 -4
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/prerender-match.ts +108 -8
- 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-interfaces.ts +11 -0
- package/src/router/segment-resolution/fresh.ts +59 -2
- package/src/router/segment-resolution/revalidation.ts +79 -6
- package/src/router.ts +13 -1
- package/src/rsc/handler.ts +468 -377
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/progressive-enhancement.ts +10 -2
- package/src/rsc/rsc-rendering.ts +5 -1
- package/src/rsc/server-action.ts +6 -0
- package/src/rsc/ssr-setup.ts +1 -1
- package/src/rsc/types.ts +1 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +11 -61
- package/src/server/context.ts +40 -4
- package/src/server/handle-store.ts +19 -0
- package/src/server/request-context.ts +125 -3
- package/src/static-handler.ts +18 -6
- package/src/types/handler-context.ts +12 -2
- package/src/types/loader-types.ts +32 -4
- package/src/types/route-entry.ts +12 -1
- package/src/types/segments.ts +1 -1
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +47 -12
- package/src/urls/response-types.ts +16 -6
- package/src/use-loader.tsx +77 -5
- package/src/vite/discovery/bundle-postprocess.ts +30 -33
- package/src/vite/discovery/prerender-collection.ts +128 -74
- package/src/vite/discovery/state.ts +13 -4
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +60 -5
- 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/refresh-cmd.ts +88 -26
- package/src/vite/rango.ts +2 -1
- package/src/vite/router-discovery.ts +178 -37
- package/src/vite/utils/prerender-utils.ts +37 -5
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);
|
|
@@ -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 {
|
|
@@ -1745,7 +1864,7 @@ import { resolve } from "node:path";
|
|
|
1745
1864
|
// package.json
|
|
1746
1865
|
var package_default = {
|
|
1747
1866
|
name: "@rangojs/router",
|
|
1748
|
-
version: "0.0.0-experimental.
|
|
1867
|
+
version: "0.0.0-experimental.57005a2b",
|
|
1749
1868
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1750
1869
|
keywords: [
|
|
1751
1870
|
"react",
|
|
@@ -1887,7 +2006,7 @@ var package_default = {
|
|
|
1887
2006
|
"test:unit:watch": "vitest"
|
|
1888
2007
|
},
|
|
1889
2008
|
dependencies: {
|
|
1890
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2009
|
+
"@vitejs/plugin-rsc": "^0.5.23",
|
|
1891
2010
|
"magic-string": "^0.30.17",
|
|
1892
2011
|
picomatch: "^4.0.3",
|
|
1893
2012
|
"rsc-html-stream": "^0.0.7"
|
|
@@ -1907,7 +2026,7 @@ var package_default = {
|
|
|
1907
2026
|
},
|
|
1908
2027
|
peerDependencies: {
|
|
1909
2028
|
"@cloudflare/vite-plugin": "^1.25.0",
|
|
1910
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2029
|
+
"@vitejs/plugin-rsc": "^0.5.23",
|
|
1911
2030
|
react: "^18.0.0 || ^19.0.0",
|
|
1912
2031
|
vite: "^7.3.0"
|
|
1913
2032
|
},
|
|
@@ -3141,6 +3260,8 @@ function createCjsToEsmPlugin() {
|
|
|
3141
3260
|
import { createServer as createViteServer } from "vite";
|
|
3142
3261
|
import { resolve as resolve8 } from "node:path";
|
|
3143
3262
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3263
|
+
import { createRequire } from "node:module";
|
|
3264
|
+
import { pathToFileURL } from "node:url";
|
|
3144
3265
|
|
|
3145
3266
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3146
3267
|
function createVirtualStubPlugin() {
|
|
@@ -3324,8 +3445,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3324
3445
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
3325
3446
|
prerenderManifestEntries: null,
|
|
3326
3447
|
staticManifestEntries: null,
|
|
3327
|
-
|
|
3328
|
-
|
|
3448
|
+
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3449
|
+
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3329
3450
|
rscEntryFileName: null,
|
|
3330
3451
|
resolvedPrerenderModules: void 0,
|
|
3331
3452
|
resolvedStaticModules: void 0,
|
|
@@ -3456,13 +3577,31 @@ function encodePathParam(value) {
|
|
|
3456
3577
|
}
|
|
3457
3578
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3458
3579
|
let result = pattern;
|
|
3580
|
+
let hadOmittedOptional = false;
|
|
3459
3581
|
for (const [key, value] of Object.entries(params)) {
|
|
3460
3582
|
const escaped = escapeRegExp2(key);
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3583
|
+
if (value === "") {
|
|
3584
|
+
result = result.replace(
|
|
3585
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
3586
|
+
""
|
|
3587
|
+
);
|
|
3588
|
+
result = result.replace(`*${key}`, "");
|
|
3589
|
+
} else {
|
|
3590
|
+
result = result.replace(
|
|
3591
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
3592
|
+
encode(value)
|
|
3593
|
+
);
|
|
3594
|
+
result = result.replace(`*${key}`, encode(value));
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
3598
|
+
hadOmittedOptional = true;
|
|
3599
|
+
return "";
|
|
3600
|
+
});
|
|
3601
|
+
if (hadOmittedOptional) {
|
|
3602
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
3603
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3604
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
3466
3605
|
}
|
|
3467
3606
|
return result;
|
|
3468
3607
|
}
|
|
@@ -3572,84 +3711,126 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3572
3711
|
if (!params) return pattern;
|
|
3573
3712
|
return substituteRouteParams(pattern, params);
|
|
3574
3713
|
};
|
|
3714
|
+
let resolvedRoutes = 0;
|
|
3715
|
+
let totalDynamic = 0;
|
|
3575
3716
|
for (const { manifest } of allManifests) {
|
|
3576
3717
|
if (!manifest.prerenderRoutes) continue;
|
|
3577
|
-
const defs = manifest._prerenderDefs || {};
|
|
3578
3718
|
for (const routeName of manifest.prerenderRoutes) {
|
|
3579
3719
|
const pattern = manifest.routeManifest[routeName];
|
|
3580
|
-
if (
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3720
|
+
if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
|
|
3721
|
+
totalDynamic++;
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
const paramsStart = performance.now();
|
|
3726
|
+
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
3727
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3728
|
+
console.log(
|
|
3729
|
+
`[rsc-router] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3730
|
+
);
|
|
3731
|
+
}, 5e3) : void 0;
|
|
3732
|
+
try {
|
|
3733
|
+
for (const { manifest } of allManifests) {
|
|
3734
|
+
if (!manifest.prerenderRoutes) continue;
|
|
3735
|
+
const defs = manifest._prerenderDefs || {};
|
|
3736
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
3737
|
+
for (const routeName of manifest.prerenderRoutes) {
|
|
3738
|
+
const pattern = manifest.routeManifest[routeName];
|
|
3739
|
+
if (!pattern) continue;
|
|
3740
|
+
const def = defs[routeName];
|
|
3741
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
3742
|
+
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
3743
|
+
if (!hasDynamic) {
|
|
3744
|
+
entries.push({
|
|
3745
|
+
urlPath: pattern.replace(/\/$/, "") || "/",
|
|
3746
|
+
routeName,
|
|
3747
|
+
concurrency: 1,
|
|
3748
|
+
isPassthroughRoute
|
|
3749
|
+
});
|
|
3750
|
+
} else {
|
|
3751
|
+
if (def?.getParams) {
|
|
3752
|
+
try {
|
|
3753
|
+
const buildVars = {};
|
|
3754
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
3755
|
+
const getParamsCtx = {
|
|
3756
|
+
build: true,
|
|
3757
|
+
dev: !state.isBuildMode,
|
|
3758
|
+
set: ((keyOrVar, value) => {
|
|
3759
|
+
contextSet(buildVars, keyOrVar, value);
|
|
3760
|
+
}),
|
|
3761
|
+
reverse: getParamsReverse,
|
|
3762
|
+
get env() {
|
|
3763
|
+
if (buildEnv !== void 0) return buildEnv;
|
|
3764
|
+
throw new Error(
|
|
3765
|
+
"[rsc-router] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3766
|
+
);
|
|
3767
|
+
}
|
|
3768
|
+
};
|
|
3769
|
+
const paramsList = await def.getParams(getParamsCtx);
|
|
3770
|
+
const concurrency = def.options?.concurrency ?? 1;
|
|
3771
|
+
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
3772
|
+
for (const params of paramsList) {
|
|
3773
|
+
let url = substituteRouteParams(
|
|
3774
|
+
pattern,
|
|
3775
|
+
params,
|
|
3776
|
+
encodePathParam
|
|
3777
|
+
);
|
|
3778
|
+
if (url.includes("*")) {
|
|
3779
|
+
const wildcardValue = params["*"] ?? params.splat;
|
|
3780
|
+
if (wildcardValue !== void 0) {
|
|
3781
|
+
url = url.replace(
|
|
3782
|
+
/\*[^/]*$/,
|
|
3783
|
+
encodePathParam(wildcardValue)
|
|
3784
|
+
);
|
|
3785
|
+
}
|
|
3615
3786
|
}
|
|
3787
|
+
entries.push({
|
|
3788
|
+
urlPath: url.replace(/\/$/, "") || "/",
|
|
3789
|
+
routeName,
|
|
3790
|
+
concurrency,
|
|
3791
|
+
...hasBuildVars ? { buildVars } : {},
|
|
3792
|
+
isPassthroughRoute
|
|
3793
|
+
});
|
|
3616
3794
|
}
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
true
|
|
3795
|
+
resolvedRoutes++;
|
|
3796
|
+
} catch (err) {
|
|
3797
|
+
resolvedRoutes++;
|
|
3798
|
+
if (err.name === "Skip") {
|
|
3799
|
+
console.log(
|
|
3800
|
+
`[rsc-router] SKIP route "${routeName}" - ${err.message}`
|
|
3801
|
+
);
|
|
3802
|
+
notifyOnError(
|
|
3803
|
+
registry,
|
|
3804
|
+
err,
|
|
3805
|
+
"prerender",
|
|
3806
|
+
routeName,
|
|
3807
|
+
void 0,
|
|
3808
|
+
true
|
|
3809
|
+
);
|
|
3810
|
+
continue;
|
|
3811
|
+
}
|
|
3812
|
+
console.error(
|
|
3813
|
+
`[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
3637
3814
|
);
|
|
3638
|
-
|
|
3815
|
+
notifyOnError(registry, err, "prerender", routeName);
|
|
3816
|
+
throw err;
|
|
3639
3817
|
}
|
|
3640
|
-
|
|
3641
|
-
|
|
3818
|
+
} else {
|
|
3819
|
+
console.warn(
|
|
3820
|
+
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3642
3821
|
);
|
|
3643
|
-
notifyOnError(registry, err, "prerender", routeName);
|
|
3644
|
-
throw err;
|
|
3645
3822
|
}
|
|
3646
|
-
} else {
|
|
3647
|
-
console.warn(
|
|
3648
|
-
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3649
|
-
);
|
|
3650
3823
|
}
|
|
3651
3824
|
}
|
|
3652
3825
|
}
|
|
3826
|
+
} finally {
|
|
3827
|
+
if (progressInterval) {
|
|
3828
|
+
clearInterval(progressInterval);
|
|
3829
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3830
|
+
console.log(
|
|
3831
|
+
`[rsc-router] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3653
3834
|
}
|
|
3654
3835
|
if (entries.length === 0) return;
|
|
3655
3836
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
@@ -3676,7 +3857,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3676
3857
|
entry.urlPath,
|
|
3677
3858
|
{},
|
|
3678
3859
|
entry.buildVars,
|
|
3679
|
-
entry.isPassthroughRoute
|
|
3860
|
+
entry.isPassthroughRoute,
|
|
3861
|
+
state.resolvedBuildEnv
|
|
3680
3862
|
);
|
|
3681
3863
|
if (!result) continue;
|
|
3682
3864
|
if (result.passthrough) {
|
|
@@ -3800,7 +3982,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3800
3982
|
const result = await routerInstance.renderStaticSegment(
|
|
3801
3983
|
def.handler,
|
|
3802
3984
|
def.$$id,
|
|
3803
|
-
def.$$routePrefix
|
|
3985
|
+
def.$$routePrefix,
|
|
3986
|
+
state.resolvedBuildEnv,
|
|
3987
|
+
!state.isBuildMode
|
|
3804
3988
|
);
|
|
3805
3989
|
if (result) {
|
|
3806
3990
|
const hasHandles = Object.keys(result.handles).length > 0;
|
|
@@ -4378,48 +4562,45 @@ function postprocessBundle(state) {
|
|
|
4378
4562
|
);
|
|
4379
4563
|
const evictionTargets = [
|
|
4380
4564
|
{
|
|
4381
|
-
|
|
4565
|
+
infos: state.handlerChunkInfoMap.values(),
|
|
4382
4566
|
fnName: "Prerender",
|
|
4383
4567
|
brand: "prerenderHandler",
|
|
4384
4568
|
label: "handler code from RSC bundle"
|
|
4385
4569
|
},
|
|
4386
4570
|
{
|
|
4387
|
-
|
|
4571
|
+
infos: state.staticHandlerChunkInfoMap.values(),
|
|
4388
4572
|
fnName: "Static",
|
|
4389
4573
|
brand: "staticHandler",
|
|
4390
4574
|
label: "static handler code"
|
|
4391
4575
|
}
|
|
4392
4576
|
];
|
|
4393
4577
|
for (const target of evictionTargets) {
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4578
|
+
for (const info of target.infos) {
|
|
4579
|
+
const chunkPath = resolve7(state.projectRoot, "dist/rsc", info.fileName);
|
|
4580
|
+
try {
|
|
4581
|
+
const code = readFileSync5(chunkPath, "utf-8");
|
|
4582
|
+
const result = evictHandlerCode(
|
|
4583
|
+
code,
|
|
4584
|
+
info.exports,
|
|
4585
|
+
target.fnName,
|
|
4586
|
+
target.brand
|
|
4587
|
+
);
|
|
4588
|
+
if (result) {
|
|
4589
|
+
writeFileSync4(chunkPath, result.code);
|
|
4590
|
+
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4591
|
+
console.log(
|
|
4592
|
+
`[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4593
|
+
);
|
|
4594
|
+
}
|
|
4595
|
+
} catch (replaceErr) {
|
|
4596
|
+
console.warn(
|
|
4597
|
+
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4413
4598
|
);
|
|
4414
4599
|
}
|
|
4415
|
-
} catch (replaceErr) {
|
|
4416
|
-
console.warn(
|
|
4417
|
-
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4418
|
-
);
|
|
4419
4600
|
}
|
|
4420
4601
|
}
|
|
4421
|
-
state.
|
|
4422
|
-
state.
|
|
4602
|
+
state.handlerChunkInfoMap.clear();
|
|
4603
|
+
state.staticHandlerChunkInfoMap.clear();
|
|
4423
4604
|
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
4424
4605
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4425
4606
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
@@ -4462,7 +4643,7 @@ function postprocessBundle(state) {
|
|
|
4462
4643
|
}
|
|
4463
4644
|
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
4464
4645
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4465
|
-
if (!rscCode.includes("
|
|
4646
|
+
if (!rscCode.includes("__static-manifest.js")) {
|
|
4466
4647
|
try {
|
|
4467
4648
|
const manifestEntries = [];
|
|
4468
4649
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -4531,8 +4712,67 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4531
4712
|
]
|
|
4532
4713
|
});
|
|
4533
4714
|
}
|
|
4715
|
+
async function resolveBuildEnv(option, factoryCtx) {
|
|
4716
|
+
if (!option) return null;
|
|
4717
|
+
if (option === "auto") {
|
|
4718
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
4719
|
+
throw new Error(
|
|
4720
|
+
'[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4721
|
+
);
|
|
4722
|
+
}
|
|
4723
|
+
try {
|
|
4724
|
+
const userRequire = createRequire(
|
|
4725
|
+
resolve8(factoryCtx.root, "package.json")
|
|
4726
|
+
);
|
|
4727
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
4728
|
+
const { getPlatformProxy } = await import(pathToFileURL(wranglerPath).href);
|
|
4729
|
+
const proxy = await getPlatformProxy();
|
|
4730
|
+
return {
|
|
4731
|
+
env: proxy.env,
|
|
4732
|
+
dispose: proxy.dispose
|
|
4733
|
+
};
|
|
4734
|
+
} catch (err) {
|
|
4735
|
+
throw new Error(
|
|
4736
|
+
`[rsc-router] buildEnv: "auto" requires wrangler to be installed.
|
|
4737
|
+
Install it with: pnpm add -D wrangler
|
|
4738
|
+
${err.message}`
|
|
4739
|
+
);
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
if (typeof option === "function") {
|
|
4743
|
+
return await option(factoryCtx);
|
|
4744
|
+
}
|
|
4745
|
+
return { env: option };
|
|
4746
|
+
}
|
|
4747
|
+
async function acquireBuildEnv(s, command, mode) {
|
|
4748
|
+
const option = s.opts?.buildEnv;
|
|
4749
|
+
if (!option) return false;
|
|
4750
|
+
const result = await resolveBuildEnv(option, {
|
|
4751
|
+
root: s.projectRoot,
|
|
4752
|
+
mode,
|
|
4753
|
+
command,
|
|
4754
|
+
preset: s.opts?.preset ?? "node"
|
|
4755
|
+
});
|
|
4756
|
+
if (!result) return false;
|
|
4757
|
+
s.resolvedBuildEnv = result.env;
|
|
4758
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
4759
|
+
return true;
|
|
4760
|
+
}
|
|
4761
|
+
async function releaseBuildEnv(s) {
|
|
4762
|
+
if (s.buildEnvDispose) {
|
|
4763
|
+
try {
|
|
4764
|
+
await s.buildEnvDispose();
|
|
4765
|
+
} catch (err) {
|
|
4766
|
+
console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
|
|
4767
|
+
}
|
|
4768
|
+
s.buildEnvDispose = null;
|
|
4769
|
+
}
|
|
4770
|
+
s.resolvedBuildEnv = void 0;
|
|
4771
|
+
}
|
|
4534
4772
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4535
4773
|
const s = createDiscoveryState(entryPath, opts);
|
|
4774
|
+
let viteCommand = "build";
|
|
4775
|
+
let viteMode = "production";
|
|
4536
4776
|
return {
|
|
4537
4777
|
name: "@rangojs/router:discovery",
|
|
4538
4778
|
config() {
|
|
@@ -4541,31 +4781,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4541
4781
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
|
|
4542
4782
|
}
|
|
4543
4783
|
};
|
|
4544
|
-
if (opts?.enableBuildPrerender) {
|
|
4545
|
-
config.environments = {
|
|
4546
|
-
rsc: {
|
|
4547
|
-
build: {
|
|
4548
|
-
rollupOptions: {
|
|
4549
|
-
output: {
|
|
4550
|
-
manualChunks(id) {
|
|
4551
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
4552
|
-
return "__prerender-handlers";
|
|
4553
|
-
}
|
|
4554
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
4555
|
-
return "__static-handlers";
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
}
|
|
4559
|
-
}
|
|
4560
|
-
}
|
|
4561
|
-
}
|
|
4562
|
-
};
|
|
4563
|
-
}
|
|
4564
4784
|
return config;
|
|
4565
4785
|
},
|
|
4566
4786
|
configResolved(config) {
|
|
4567
4787
|
s.projectRoot = config.root;
|
|
4568
4788
|
s.isBuildMode = config.command === "build";
|
|
4789
|
+
viteCommand = config.command;
|
|
4790
|
+
viteMode = config.mode;
|
|
4569
4791
|
s.userResolveAlias = config.resolve.alias;
|
|
4570
4792
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4571
4793
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
@@ -4610,6 +4832,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4610
4832
|
});
|
|
4611
4833
|
prerenderTempServer = null;
|
|
4612
4834
|
}
|
|
4835
|
+
releaseBuildEnv(s).catch(() => {
|
|
4836
|
+
});
|
|
4613
4837
|
});
|
|
4614
4838
|
async function getOrCreateTempServer() {
|
|
4615
4839
|
if (prerenderNodeRegistry) {
|
|
@@ -4640,6 +4864,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4640
4864
|
if (!rscEnv?.runner) {
|
|
4641
4865
|
s.devServerOrigin = getDevServerOrigin();
|
|
4642
4866
|
try {
|
|
4867
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4643
4868
|
const tempRscEnv = await getOrCreateTempServer();
|
|
4644
4869
|
if (tempRscEnv) {
|
|
4645
4870
|
await discoverRouters(s, tempRscEnv);
|
|
@@ -4655,6 +4880,7 @@ ${err.stack}`
|
|
|
4655
4880
|
return;
|
|
4656
4881
|
}
|
|
4657
4882
|
try {
|
|
4883
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4658
4884
|
const serverMod = await rscEnv.runner.import(
|
|
4659
4885
|
"@rangojs/router/server"
|
|
4660
4886
|
);
|
|
@@ -4719,7 +4945,26 @@ ${err.stack}`
|
|
|
4719
4945
|
res.end("Missing pathname");
|
|
4720
4946
|
return;
|
|
4721
4947
|
}
|
|
4722
|
-
|
|
4948
|
+
const rscEnv = server.environments?.rsc;
|
|
4949
|
+
let registry = null;
|
|
4950
|
+
if (rscEnv?.runner && s.resolvedEntryPath) {
|
|
4951
|
+
try {
|
|
4952
|
+
await rscEnv.runner.import(s.resolvedEntryPath);
|
|
4953
|
+
const serverMod = await rscEnv.runner.import(
|
|
4954
|
+
"@rangojs/router/server"
|
|
4955
|
+
);
|
|
4956
|
+
registry = serverMod.RouterRegistry ?? null;
|
|
4957
|
+
} catch (err) {
|
|
4958
|
+
console.warn(
|
|
4959
|
+
`[rsc-router] Dev prerender module refresh failed: ${err.message}`
|
|
4960
|
+
);
|
|
4961
|
+
res.statusCode = 500;
|
|
4962
|
+
res.end(`Prerender handler error: ${err.message}`);
|
|
4963
|
+
return;
|
|
4964
|
+
}
|
|
4965
|
+
} else {
|
|
4966
|
+
registry = mainRegistry;
|
|
4967
|
+
}
|
|
4723
4968
|
if (!registry) {
|
|
4724
4969
|
if (!prerenderNodeRegistry) {
|
|
4725
4970
|
await getOrCreateTempServer();
|
|
@@ -4741,7 +4986,10 @@ ${err.stack}`
|
|
|
4741
4986
|
pathname,
|
|
4742
4987
|
{},
|
|
4743
4988
|
void 0,
|
|
4744
|
-
wantPassthrough
|
|
4989
|
+
wantPassthrough,
|
|
4990
|
+
s.resolvedBuildEnv,
|
|
4991
|
+
true
|
|
4992
|
+
// devMode: check getParams for passthrough routes
|
|
4745
4993
|
);
|
|
4746
4994
|
if (!result) continue;
|
|
4747
4995
|
if (result.passthrough) continue;
|
|
@@ -4877,6 +5125,7 @@ ${err.stack}`
|
|
|
4877
5125
|
resetStagedBuildAssets(s.projectRoot);
|
|
4878
5126
|
s.prerenderManifestEntries = null;
|
|
4879
5127
|
s.staticManifestEntries = null;
|
|
5128
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4880
5129
|
let tempServer = null;
|
|
4881
5130
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4882
5131
|
try {
|
|
@@ -4916,6 +5165,7 @@ ${details}`
|
|
|
4916
5165
|
if (tempServer) {
|
|
4917
5166
|
await tempServer.close();
|
|
4918
5167
|
}
|
|
5168
|
+
await releaseBuildEnv(s);
|
|
4919
5169
|
}
|
|
4920
5170
|
},
|
|
4921
5171
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -4958,20 +5208,30 @@ ${details}`
|
|
|
4958
5208
|
}
|
|
4959
5209
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
4960
5210
|
return;
|
|
5211
|
+
s.handlerChunkInfoMap.clear();
|
|
5212
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
4961
5213
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
4962
5214
|
if (chunk.type !== "chunk") continue;
|
|
4963
|
-
if (
|
|
5215
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
4964
5216
|
const handlers = extractHandlerExportsFromChunk(
|
|
4965
5217
|
chunk.code,
|
|
4966
5218
|
s.resolvedPrerenderModules,
|
|
4967
5219
|
"Prerender",
|
|
4968
|
-
|
|
5220
|
+
false
|
|
4969
5221
|
);
|
|
4970
5222
|
if (handlers.length > 0) {
|
|
4971
|
-
|
|
5223
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
5224
|
+
if (existing) {
|
|
5225
|
+
existing.exports.push(...handlers);
|
|
5226
|
+
} else {
|
|
5227
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
5228
|
+
fileName,
|
|
5229
|
+
exports: handlers
|
|
5230
|
+
});
|
|
5231
|
+
}
|
|
4972
5232
|
}
|
|
4973
5233
|
}
|
|
4974
|
-
if (
|
|
5234
|
+
if (s.resolvedStaticModules?.size) {
|
|
4975
5235
|
const handlers = extractHandlerExportsFromChunk(
|
|
4976
5236
|
chunk.code,
|
|
4977
5237
|
s.resolvedStaticModules,
|
|
@@ -4979,7 +5239,15 @@ ${details}`
|
|
|
4979
5239
|
false
|
|
4980
5240
|
);
|
|
4981
5241
|
if (handlers.length > 0) {
|
|
4982
|
-
|
|
5242
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
5243
|
+
if (existing) {
|
|
5244
|
+
existing.exports.push(...handlers);
|
|
5245
|
+
} else {
|
|
5246
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
5247
|
+
fileName,
|
|
5248
|
+
exports: handlers
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
4983
5251
|
}
|
|
4984
5252
|
}
|
|
4985
5253
|
}
|
|
@@ -5271,7 +5539,8 @@ ${list}`);
|
|
|
5271
5539
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5272
5540
|
routerPathRef: discoveryRouterRef,
|
|
5273
5541
|
enableBuildPrerender: prerenderEnabled,
|
|
5274
|
-
|
|
5542
|
+
buildEnv: options?.buildEnv,
|
|
5543
|
+
preset
|
|
5275
5544
|
})
|
|
5276
5545
|
);
|
|
5277
5546
|
return plugins;
|
|
@@ -5284,29 +5553,75 @@ function poke() {
|
|
|
5284
5553
|
apply: "serve",
|
|
5285
5554
|
configureServer(server) {
|
|
5286
5555
|
const stdin = process.stdin;
|
|
5287
|
-
const
|
|
5556
|
+
const debug = process.env.RANGO_POKE_DEBUG === "1";
|
|
5557
|
+
const triggerReload = (source) => {
|
|
5558
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
5559
|
+
server.config.logger.info(` browser reload (${source})`, {
|
|
5560
|
+
timestamp: true
|
|
5561
|
+
});
|
|
5562
|
+
};
|
|
5563
|
+
const toBuffer = (chunk) => {
|
|
5564
|
+
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5565
|
+
};
|
|
5566
|
+
const formatChunk = (chunk) => {
|
|
5567
|
+
const data = toBuffer(chunk);
|
|
5568
|
+
const hex = Array.from(data).map((byte) => `0x${byte.toString(16).padStart(2, "0")}`).join(" ");
|
|
5569
|
+
const ascii = Array.from(data).map((byte) => {
|
|
5570
|
+
if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
|
|
5571
|
+
if (byte === 10) return "\\n";
|
|
5572
|
+
if (byte === 13) return "\\r";
|
|
5573
|
+
if (byte === 9) return "\\t";
|
|
5574
|
+
return ".";
|
|
5575
|
+
}).join("");
|
|
5576
|
+
return `len=${data.length} hex=[${hex}] ascii="${ascii}"`;
|
|
5577
|
+
};
|
|
5578
|
+
const readCtrlR = (chunk) => {
|
|
5579
|
+
const data = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5580
|
+
return data.length === 1 && data[0] === 18;
|
|
5581
|
+
};
|
|
5582
|
+
const readSubmittedCommands = (chunk) => {
|
|
5583
|
+
const text = toBuffer(chunk).toString("utf8").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
5584
|
+
if (!text.includes("\n")) return [];
|
|
5585
|
+
const lines = text.split("\n");
|
|
5586
|
+
lines.pop();
|
|
5587
|
+
return lines;
|
|
5588
|
+
};
|
|
5589
|
+
if (debug) {
|
|
5590
|
+
server.config.logger.info(
|
|
5591
|
+
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5592
|
+
{ timestamp: true }
|
|
5593
|
+
);
|
|
5594
|
+
}
|
|
5288
5595
|
if (stdin.isTTY) {
|
|
5289
|
-
|
|
5596
|
+
server.config.logger.info(
|
|
5597
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
5598
|
+
{ timestamp: true }
|
|
5599
|
+
);
|
|
5290
5600
|
}
|
|
5291
5601
|
const onData = (data) => {
|
|
5292
|
-
if (
|
|
5293
|
-
|
|
5294
|
-
process.emit("SIGINT", "SIGINT");
|
|
5295
|
-
return;
|
|
5296
|
-
}
|
|
5297
|
-
if (data[0] === 18) {
|
|
5298
|
-
server.hot.send({ type: "full-reload", path: "*" });
|
|
5299
|
-
server.config.logger.info(" browser reload (ctrl+r)", {
|
|
5602
|
+
if (debug) {
|
|
5603
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5300
5604
|
timestamp: true
|
|
5301
5605
|
});
|
|
5302
5606
|
}
|
|
5607
|
+
if (readCtrlR(data)) {
|
|
5608
|
+
triggerReload("ctrl+r");
|
|
5609
|
+
return;
|
|
5610
|
+
}
|
|
5611
|
+
for (const command of readSubmittedCommands(data)) {
|
|
5612
|
+
if (command === "e") {
|
|
5613
|
+
triggerReload("e+enter");
|
|
5614
|
+
return;
|
|
5615
|
+
}
|
|
5616
|
+
if (command === "\x1Br") {
|
|
5617
|
+
triggerReload("option+r+enter");
|
|
5618
|
+
return;
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5303
5621
|
};
|
|
5304
5622
|
stdin.on("data", onData);
|
|
5305
5623
|
server.httpServer?.on("close", () => {
|
|
5306
5624
|
stdin.off("data", onData);
|
|
5307
|
-
if (stdin.isTTY && previousRawMode !== null) {
|
|
5308
|
-
stdin.setRawMode(previousRawMode);
|
|
5309
|
-
}
|
|
5310
5625
|
});
|
|
5311
5626
|
}
|
|
5312
5627
|
};
|