@rangojs/router 0.0.0-experimental.8678bb02 → 0.0.0-experimental.88
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 +126 -38
- package/dist/bin/rango.js +130 -47
- package/dist/vite/index.js +867 -385
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +5 -5
- package/skills/breadcrumbs/SKILL.md +3 -1
- 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 +35 -2
- 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 +59 -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 +24 -0
- package/skills/router-setup/SKILL.md +35 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +3 -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/navigation-bridge.ts +87 -6
- package/src/browser/navigation-client.ts +128 -77
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/partial-update.ts +60 -7
- package/src/browser/prefetch/cache.ts +129 -21
- package/src/browser/prefetch/fetch.ts +156 -18
- package/src/browser/prefetch/queue.ts +36 -5
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +72 -8
- package/src/browser/react/NavigationProvider.tsx +57 -11
- 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 +60 -9
- package/src/browser/scroll-restoration.ts +10 -8
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/browser/server-action-bridge.ts +8 -18
- package/src/browser/types.ts +33 -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 +211 -72
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cf/cf-cache-store.ts +5 -7
- package/src/client.tsx +84 -230
- package/src/deps/browser.ts +0 -1
- 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 +210 -35
- package/src/route-definition/helpers-types.ts +61 -14
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +9 -1
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/handler-context.ts +70 -17
- package/src/router/intercept-resolution.ts +9 -4
- package/src/router/lazy-includes.ts +6 -6
- package/src/router/loader-resolution.ts +153 -21
- package/src/router/manifest.ts +22 -13
- package/src/router/match-api.ts +127 -192
- package/src/router/match-middleware/cache-lookup.ts +28 -8
- package/src/router/match-middleware/segment-resolution.ts +53 -0
- package/src/router/match-result.ts +82 -4
- package/src/router/middleware-types.ts +2 -28
- package/src/router/middleware.ts +32 -7
- 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-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +70 -5
- package/src/router/segment-resolution/revalidation.ts +87 -9
- package/src/router/trie-matching.ts +10 -4
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +54 -7
- package/src/rsc/handler.ts +478 -399
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/loader-fetch.ts +18 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +14 -3
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +15 -2
- package/src/rsc/server-action.ts +10 -2
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +6 -4
- 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 +65 -5
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +142 -55
- package/src/ssr/index.tsx +3 -0
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +17 -43
- package/src/types/loader-types.ts +37 -11
- package/src/types/request-scope.ts +126 -0
- 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/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +18 -16
- package/src/use-loader.tsx +77 -5
- 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 -4
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +60 -5
- 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-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 +64 -206
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/rango.ts +50 -20
- package/src/vite/router-discovery.ts +237 -37
- package/src/vite/utils/banner.ts +1 -1
- 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/src/browser/debug-channel.ts +0 -93
package/dist/vite/index.js
CHANGED
|
@@ -9,18 +9,21 @@ import fs from "node:fs";
|
|
|
9
9
|
|
|
10
10
|
// src/vite/plugins/expose-id-utils.ts
|
|
11
11
|
import path from "node:path";
|
|
12
|
-
import
|
|
12
|
+
import crypto from "node:crypto";
|
|
13
13
|
function normalizePath(p) {
|
|
14
14
|
return p.split(path.sep).join("/");
|
|
15
15
|
}
|
|
16
16
|
function hashId(filePath, exportName) {
|
|
17
17
|
const input = `${filePath}#${exportName}`;
|
|
18
|
-
const hash =
|
|
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
|
-
return
|
|
26
|
+
return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
|
|
24
27
|
}
|
|
25
28
|
function buildExportMap(program) {
|
|
26
29
|
const exportMap = /* @__PURE__ */ new Map();
|
|
@@ -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.88",
|
|
1749
1869
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1750
1870
|
keywords: [
|
|
1751
1871
|
"react",
|
|
@@ -1878,16 +1998,16 @@ 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",
|
|
1891
2011
|
"magic-string": "^0.30.17",
|
|
1892
2012
|
picomatch: "^4.0.3",
|
|
1893
2013
|
"rsc-html-stream": "^0.0.7"
|
|
@@ -1907,7 +2027,7 @@ var package_default = {
|
|
|
1907
2027
|
},
|
|
1908
2028
|
peerDependencies: {
|
|
1909
2029
|
"@cloudflare/vite-plugin": "^1.25.0",
|
|
1910
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
2030
|
+
"@vitejs/plugin-rsc": "^0.5.23",
|
|
1911
2031
|
react: "^18.0.0 || ^19.0.0",
|
|
1912
2032
|
vite: "^7.3.0"
|
|
1913
2033
|
},
|
|
@@ -1922,6 +2042,7 @@ var package_default = {
|
|
|
1922
2042
|
};
|
|
1923
2043
|
|
|
1924
2044
|
// src/vite/utils/package-resolution.ts
|
|
2045
|
+
var require2 = createRequire(import.meta.url);
|
|
1925
2046
|
var VIRTUAL_PACKAGE_NAME = "@rangojs/router";
|
|
1926
2047
|
function getPublishedPackageName() {
|
|
1927
2048
|
return package_default.name;
|
|
@@ -1962,6 +2083,20 @@ function getPackageAliases() {
|
|
|
1962
2083
|
}
|
|
1963
2084
|
return aliases;
|
|
1964
2085
|
}
|
|
2086
|
+
function getVendorAliases() {
|
|
2087
|
+
const specs = [
|
|
2088
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
|
|
2089
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
2090
|
+
];
|
|
2091
|
+
const aliases = {};
|
|
2092
|
+
for (const spec of specs) {
|
|
2093
|
+
try {
|
|
2094
|
+
aliases[spec] = require2.resolve(spec);
|
|
2095
|
+
} catch {
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
return aliases;
|
|
2099
|
+
}
|
|
1965
2100
|
|
|
1966
2101
|
// src/build/route-types/param-extraction.ts
|
|
1967
2102
|
function extractParamsFromPattern(pattern) {
|
|
@@ -2317,7 +2452,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2317
2452
|
}
|
|
2318
2453
|
return routeMap;
|
|
2319
2454
|
}
|
|
2320
|
-
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut) {
|
|
2455
|
+
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
|
|
2321
2456
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
2322
2457
|
const realPath = resolve2(filePath);
|
|
2323
2458
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
@@ -2333,7 +2468,9 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2333
2468
|
return { routes: {}, searchSchemas: {} };
|
|
2334
2469
|
}
|
|
2335
2470
|
let block;
|
|
2336
|
-
if (
|
|
2471
|
+
if (inlineBlock) {
|
|
2472
|
+
block = inlineBlock;
|
|
2473
|
+
} else if (variableName) {
|
|
2337
2474
|
const extracted = extractUrlsBlockForVariable(source, variableName);
|
|
2338
2475
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
2339
2476
|
block = extracted;
|
|
@@ -2452,7 +2589,7 @@ Router root: ${conflict.ancestor}
|
|
|
2452
2589
|
Nested router: ${conflict.nested}
|
|
2453
2590
|
Move the nested router into a sibling directory or configure it as a separate app root.`;
|
|
2454
2591
|
}
|
|
2455
|
-
function
|
|
2592
|
+
function extractUrlsFromRouter(code) {
|
|
2456
2593
|
const sourceFile = ts5.createSourceFile(
|
|
2457
2594
|
"router.tsx",
|
|
2458
2595
|
code,
|
|
@@ -2466,24 +2603,70 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2466
2603
|
const callee = node.expression;
|
|
2467
2604
|
return ts5.isIdentifier(callee) && callee.text === "createRouter";
|
|
2468
2605
|
}
|
|
2606
|
+
function isInlineBuilder(node) {
|
|
2607
|
+
return ts5.isArrowFunction(node) || ts5.isFunctionExpression(node);
|
|
2608
|
+
}
|
|
2609
|
+
function isRoutesOnCreateRouter(node) {
|
|
2610
|
+
if (!ts5.isPropertyAccessExpression(node.expression) || node.expression.name.text !== "routes")
|
|
2611
|
+
return false;
|
|
2612
|
+
let inner = node.expression.expression;
|
|
2613
|
+
while (ts5.isCallExpression(inner) && ts5.isPropertyAccessExpression(inner.expression)) {
|
|
2614
|
+
inner = inner.expression.expression;
|
|
2615
|
+
}
|
|
2616
|
+
return isCreateRouterCall(inner);
|
|
2617
|
+
}
|
|
2469
2618
|
function visit(node) {
|
|
2470
2619
|
if (result) return;
|
|
2471
|
-
if (ts5.isCallExpression(node) &&
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
}
|
|
2476
|
-
|
|
2477
|
-
result = node.arguments[0].text;
|
|
2478
|
-
return;
|
|
2620
|
+
if (ts5.isCallExpression(node) && node.arguments.length >= 1 && isRoutesOnCreateRouter(node)) {
|
|
2621
|
+
const arg = node.arguments[0];
|
|
2622
|
+
if (ts5.isIdentifier(arg)) {
|
|
2623
|
+
result = { kind: "variable", name: arg.text };
|
|
2624
|
+
} else if (isInlineBuilder(arg)) {
|
|
2625
|
+
result = { kind: "inline", block: arg.getText(sourceFile) };
|
|
2479
2626
|
}
|
|
2627
|
+
return;
|
|
2480
2628
|
}
|
|
2481
2629
|
if (isCreateRouterCall(node)) {
|
|
2482
2630
|
const callExpr = node;
|
|
2483
|
-
for (const
|
|
2631
|
+
for (const callArg of callExpr.arguments) {
|
|
2632
|
+
if (ts5.isObjectLiteralExpression(callArg)) {
|
|
2633
|
+
for (const prop of callArg.properties) {
|
|
2634
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "urls") {
|
|
2635
|
+
if (ts5.isIdentifier(prop.initializer)) {
|
|
2636
|
+
result = { kind: "variable", name: prop.initializer.text };
|
|
2637
|
+
} else if (isInlineBuilder(prop.initializer)) {
|
|
2638
|
+
result = {
|
|
2639
|
+
kind: "inline",
|
|
2640
|
+
block: prop.initializer.getText(sourceFile)
|
|
2641
|
+
};
|
|
2642
|
+
}
|
|
2643
|
+
return;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
ts5.forEachChild(node, visit);
|
|
2650
|
+
}
|
|
2651
|
+
visit(sourceFile);
|
|
2652
|
+
return result;
|
|
2653
|
+
}
|
|
2654
|
+
function extractBasenameFromRouter(code) {
|
|
2655
|
+
const sourceFile = ts5.createSourceFile(
|
|
2656
|
+
"router.tsx",
|
|
2657
|
+
code,
|
|
2658
|
+
ts5.ScriptTarget.Latest,
|
|
2659
|
+
true,
|
|
2660
|
+
ts5.ScriptKind.TSX
|
|
2661
|
+
);
|
|
2662
|
+
let result;
|
|
2663
|
+
function visit(node) {
|
|
2664
|
+
if (result !== void 0) return;
|
|
2665
|
+
if (ts5.isCallExpression(node) && ts5.isIdentifier(node.expression) && node.expression.text === "createRouter") {
|
|
2666
|
+
for (const arg of node.arguments) {
|
|
2484
2667
|
if (ts5.isObjectLiteralExpression(arg)) {
|
|
2485
2668
|
for (const prop of arg.properties) {
|
|
2486
|
-
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "
|
|
2669
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "basename" && ts5.isStringLiteral(prop.initializer)) {
|
|
2487
2670
|
result = prop.initializer.text;
|
|
2488
2671
|
return;
|
|
2489
2672
|
}
|
|
@@ -2496,6 +2679,19 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2496
2679
|
visit(sourceFile);
|
|
2497
2680
|
return result;
|
|
2498
2681
|
}
|
|
2682
|
+
function applyBasenameToRoutes(result, basename3) {
|
|
2683
|
+
const prefixed = {};
|
|
2684
|
+
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
2685
|
+
if (pattern === "/") {
|
|
2686
|
+
prefixed[name] = basename3;
|
|
2687
|
+
} else if (basename3.endsWith("/") && pattern.startsWith("/")) {
|
|
2688
|
+
prefixed[name] = basename3 + pattern.slice(1);
|
|
2689
|
+
} else {
|
|
2690
|
+
prefixed[name] = basename3 + pattern;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
2694
|
+
}
|
|
2499
2695
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2500
2696
|
let routerSource;
|
|
2501
2697
|
try {
|
|
@@ -2503,19 +2699,40 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2503
2699
|
} catch {
|
|
2504
2700
|
return { routes: {}, searchSchemas: {} };
|
|
2505
2701
|
}
|
|
2506
|
-
const
|
|
2507
|
-
if (!
|
|
2702
|
+
const extraction = extractUrlsFromRouter(routerSource);
|
|
2703
|
+
if (!extraction) {
|
|
2508
2704
|
return { routes: {}, searchSchemas: {} };
|
|
2509
2705
|
}
|
|
2510
|
-
const
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2706
|
+
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
2707
|
+
const basename3 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
|
|
2708
|
+
let result;
|
|
2709
|
+
if (extraction.kind === "inline") {
|
|
2710
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2711
|
+
routerFilePath,
|
|
2712
|
+
void 0,
|
|
2713
|
+
void 0,
|
|
2714
|
+
void 0,
|
|
2715
|
+
extraction.block
|
|
2716
|
+
);
|
|
2717
|
+
} else {
|
|
2718
|
+
const imported = resolveImportedVariable(routerSource, extraction.name);
|
|
2719
|
+
if (imported) {
|
|
2720
|
+
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2721
|
+
if (!targetFile) {
|
|
2722
|
+
return { routes: {}, searchSchemas: {} };
|
|
2723
|
+
}
|
|
2724
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2725
|
+
targetFile,
|
|
2726
|
+
imported.exportedName
|
|
2727
|
+
);
|
|
2728
|
+
} else {
|
|
2729
|
+
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
2515
2730
|
}
|
|
2516
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2517
2731
|
}
|
|
2518
|
-
|
|
2732
|
+
if (basename3) {
|
|
2733
|
+
result = applyBasenameToRoutes(result, basename3);
|
|
2734
|
+
}
|
|
2735
|
+
return result;
|
|
2519
2736
|
}
|
|
2520
2737
|
function findRouterFiles(root, filter) {
|
|
2521
2738
|
const result = [];
|
|
@@ -2540,25 +2757,15 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2540
2757
|
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
2541
2758
|
}
|
|
2542
2759
|
for (const routerFilePath of routerFilePaths) {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
routerSource
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
2553
|
-
if (imported) {
|
|
2554
|
-
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2555
|
-
if (!targetFile) continue;
|
|
2556
|
-
result = buildCombinedRouteMapWithSearch(
|
|
2557
|
-
targetFile,
|
|
2558
|
-
imported.exportedName
|
|
2559
|
-
);
|
|
2560
|
-
} else {
|
|
2561
|
-
result = buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2760
|
+
const result = buildCombinedRouteMapForRouterFile(routerFilePath);
|
|
2761
|
+
if (Object.keys(result.routes).length === 0 && Object.keys(result.searchSchemas).length === 0) {
|
|
2762
|
+
let routerSource;
|
|
2763
|
+
try {
|
|
2764
|
+
routerSource = readFileSync2(routerFilePath, "utf-8");
|
|
2765
|
+
} catch {
|
|
2766
|
+
continue;
|
|
2767
|
+
}
|
|
2768
|
+
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
2562
2769
|
}
|
|
2563
2770
|
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2564
2771
|
/\.(tsx?|jsx?)$/,
|
|
@@ -2784,6 +2991,68 @@ function createVersionPlugin() {
|
|
|
2784
2991
|
|
|
2785
2992
|
// src/vite/utils/shared-utils.ts
|
|
2786
2993
|
import * as Vite from "vite";
|
|
2994
|
+
|
|
2995
|
+
// src/vite/plugins/performance-tracks.ts
|
|
2996
|
+
import { readFile } from "node:fs/promises";
|
|
2997
|
+
var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
|
|
2998
|
+
function buildPatchReplacement(match, debugInfoVar) {
|
|
2999
|
+
return `${match}
|
|
3000
|
+
if (${debugInfoVar} && 0 === ${debugInfoVar}.length && "fulfilled" === root.status) {
|
|
3001
|
+
var _resolved = "function" === typeof resolveLazy ? resolveLazy(root.value) : root.value;
|
|
3002
|
+
if ("object" === typeof _resolved && null !== _resolved && isArrayImpl(_resolved._debugInfo)) {
|
|
3003
|
+
${debugInfoVar} = _resolved._debugInfo;
|
|
3004
|
+
}
|
|
3005
|
+
}`;
|
|
3006
|
+
}
|
|
3007
|
+
function patchRsdwClientDebugInfoRecovery(code) {
|
|
3008
|
+
const match = code.match(RSDW_PATCH_RE);
|
|
3009
|
+
if (!match) {
|
|
3010
|
+
return { code, debugInfoVar: null };
|
|
3011
|
+
}
|
|
3012
|
+
return {
|
|
3013
|
+
code: code.replace(match[1], buildPatchReplacement(match[1], match[2])),
|
|
3014
|
+
debugInfoVar: match[2]
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
3017
|
+
function performanceTracksOptimizeDepsPlugin() {
|
|
3018
|
+
return {
|
|
3019
|
+
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
3020
|
+
setup(build) {
|
|
3021
|
+
build.onLoad(
|
|
3022
|
+
{
|
|
3023
|
+
filter: /react-server-dom-webpack-client\.browser\.(development|production)\.js$/
|
|
3024
|
+
},
|
|
3025
|
+
async (args) => {
|
|
3026
|
+
const code = await readFile(args.path, "utf8");
|
|
3027
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3028
|
+
return {
|
|
3029
|
+
contents: patched.code,
|
|
3030
|
+
loader: "js"
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
function performanceTracksPlugin() {
|
|
3038
|
+
return {
|
|
3039
|
+
name: "@rangojs/router:performance-tracks",
|
|
3040
|
+
transform(code, id) {
|
|
3041
|
+
if (!id.includes("react-server-dom") || !id.includes("client")) return;
|
|
3042
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
3043
|
+
if (!patched.debugInfoVar) return;
|
|
3044
|
+
if (process.env.INTERNAL_RANGO_DEBUG)
|
|
3045
|
+
console.log(
|
|
3046
|
+
"[perf-tracks] patched RSDW client (var:",
|
|
3047
|
+
patched.debugInfoVar,
|
|
3048
|
+
")"
|
|
3049
|
+
);
|
|
3050
|
+
return patched.code;
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// src/vite/utils/shared-utils.ts
|
|
2787
3056
|
var versionEsbuildPlugin = {
|
|
2788
3057
|
name: "@rangojs/router-version",
|
|
2789
3058
|
setup(build) {
|
|
@@ -2801,7 +3070,7 @@ var versionEsbuildPlugin = {
|
|
|
2801
3070
|
}
|
|
2802
3071
|
};
|
|
2803
3072
|
var sharedEsbuildOptions = {
|
|
2804
|
-
plugins: [versionEsbuildPlugin]
|
|
3073
|
+
plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
2805
3074
|
};
|
|
2806
3075
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
2807
3076
|
const virtualModules = {};
|
|
@@ -3007,6 +3276,8 @@ function createCjsToEsmPlugin() {
|
|
|
3007
3276
|
import { createServer as createViteServer } from "vite";
|
|
3008
3277
|
import { resolve as resolve8 } from "node:path";
|
|
3009
3278
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3279
|
+
import { createRequire as createRequire2, register } from "node:module";
|
|
3280
|
+
import { pathToFileURL } from "node:url";
|
|
3010
3281
|
|
|
3011
3282
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3012
3283
|
function createVirtualStubPlugin() {
|
|
@@ -3032,6 +3303,113 @@ function createVirtualStubPlugin() {
|
|
|
3032
3303
|
};
|
|
3033
3304
|
}
|
|
3034
3305
|
|
|
3306
|
+
// src/vite/plugins/cloudflare-protocol-stub.ts
|
|
3307
|
+
var VIRTUAL_PREFIX = "virtual:rango-cloudflare-stub-";
|
|
3308
|
+
var NULL_PREFIX = "\0" + VIRTUAL_PREFIX;
|
|
3309
|
+
var CF_PREFIX = "cloudflare:";
|
|
3310
|
+
var BUILD_ENV_GLOBAL_KEY = "__rango_build_env__";
|
|
3311
|
+
var SOURCE_EXT_RE = /\.[mc]?[jt]sx?$/;
|
|
3312
|
+
var IMPORT_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
3313
|
+
"ImportDeclaration",
|
|
3314
|
+
"ImportExpression",
|
|
3315
|
+
"ExportNamedDeclaration",
|
|
3316
|
+
"ExportAllDeclaration"
|
|
3317
|
+
]);
|
|
3318
|
+
var STUBS = {
|
|
3319
|
+
"cloudflare:workers": `
|
|
3320
|
+
export class DurableObject { constructor(_ctx, _env) {} }
|
|
3321
|
+
export class WorkerEntrypoint { constructor(_ctx, _env) {} }
|
|
3322
|
+
export class WorkflowEntrypoint { constructor(_ctx, _env) {} }
|
|
3323
|
+
export class RpcTarget {}
|
|
3324
|
+
export const env = globalThis[${JSON.stringify(BUILD_ENV_GLOBAL_KEY)}] ?? {};
|
|
3325
|
+
export default {};
|
|
3326
|
+
`,
|
|
3327
|
+
"cloudflare:email": `
|
|
3328
|
+
export class EmailMessage { constructor(_from, _to, _raw) {} }
|
|
3329
|
+
export default {};
|
|
3330
|
+
`,
|
|
3331
|
+
"cloudflare:sockets": `
|
|
3332
|
+
export function connect() { return {}; }
|
|
3333
|
+
export default {};
|
|
3334
|
+
`,
|
|
3335
|
+
"cloudflare:workflows": `
|
|
3336
|
+
export class NonRetryableError extends Error {
|
|
3337
|
+
constructor(message, name) { super(message); this.name = name ?? "NonRetryableError"; }
|
|
3338
|
+
}
|
|
3339
|
+
export default {};
|
|
3340
|
+
`
|
|
3341
|
+
};
|
|
3342
|
+
var FALLBACK_STUB = `export default {};
|
|
3343
|
+
`;
|
|
3344
|
+
function createCloudflareProtocolStubPlugin() {
|
|
3345
|
+
return {
|
|
3346
|
+
name: "@rangojs/router:cloudflare-protocol-stub",
|
|
3347
|
+
transform(code, id) {
|
|
3348
|
+
const cleanId = id.split("?")[0] ?? id;
|
|
3349
|
+
if (!SOURCE_EXT_RE.test(cleanId)) return null;
|
|
3350
|
+
if (!code.includes(CF_PREFIX)) return null;
|
|
3351
|
+
let ast;
|
|
3352
|
+
try {
|
|
3353
|
+
ast = this.parse(code);
|
|
3354
|
+
} catch {
|
|
3355
|
+
return null;
|
|
3356
|
+
}
|
|
3357
|
+
const hits = [];
|
|
3358
|
+
walk(ast, (node) => {
|
|
3359
|
+
if (!IMPORT_NODE_TYPES.has(node.type)) return;
|
|
3360
|
+
const source = node.source;
|
|
3361
|
+
if (!source || source.type !== "Literal") return;
|
|
3362
|
+
if (typeof source.value !== "string") return;
|
|
3363
|
+
if (!source.value.startsWith(CF_PREFIX)) return;
|
|
3364
|
+
if (typeof source.start !== "number" || typeof source.end !== "number")
|
|
3365
|
+
return;
|
|
3366
|
+
hits.push({
|
|
3367
|
+
start: source.start,
|
|
3368
|
+
end: source.end,
|
|
3369
|
+
value: source.value
|
|
3370
|
+
});
|
|
3371
|
+
});
|
|
3372
|
+
if (hits.length === 0) return null;
|
|
3373
|
+
hits.sort((a, b) => b.start - a.start);
|
|
3374
|
+
let out = code;
|
|
3375
|
+
for (const hit of hits) {
|
|
3376
|
+
const submodule = hit.value.slice(CF_PREFIX.length);
|
|
3377
|
+
const quote = code[hit.start] === "'" ? "'" : '"';
|
|
3378
|
+
out = out.slice(0, hit.start) + quote + VIRTUAL_PREFIX + submodule + quote + out.slice(hit.end);
|
|
3379
|
+
}
|
|
3380
|
+
return { code: out, map: null };
|
|
3381
|
+
},
|
|
3382
|
+
resolveId(id) {
|
|
3383
|
+
if (id.startsWith(VIRTUAL_PREFIX)) {
|
|
3384
|
+
return "\0" + id;
|
|
3385
|
+
}
|
|
3386
|
+
return null;
|
|
3387
|
+
},
|
|
3388
|
+
load(id) {
|
|
3389
|
+
if (!id.startsWith(NULL_PREFIX)) return null;
|
|
3390
|
+
const submodule = id.slice(NULL_PREFIX.length);
|
|
3391
|
+
const specifier = CF_PREFIX + submodule;
|
|
3392
|
+
return STUBS[specifier] ?? FALLBACK_STUB;
|
|
3393
|
+
}
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
function walk(node, visit) {
|
|
3397
|
+
if (!node || typeof node !== "object") return;
|
|
3398
|
+
if (Array.isArray(node)) {
|
|
3399
|
+
for (const child of node) walk(child, visit);
|
|
3400
|
+
return;
|
|
3401
|
+
}
|
|
3402
|
+
const n = node;
|
|
3403
|
+
if (typeof n.type !== "string") return;
|
|
3404
|
+
visit(n);
|
|
3405
|
+
for (const key in n) {
|
|
3406
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") {
|
|
3407
|
+
continue;
|
|
3408
|
+
}
|
|
3409
|
+
walk(n[key], visit);
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3035
3413
|
// src/vite/plugins/client-ref-hashing.ts
|
|
3036
3414
|
import { relative } from "node:path";
|
|
3037
3415
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -3190,8 +3568,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3190
3568
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
3191
3569
|
prerenderManifestEntries: null,
|
|
3192
3570
|
staticManifestEntries: null,
|
|
3193
|
-
|
|
3194
|
-
|
|
3571
|
+
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3572
|
+
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3195
3573
|
rscEntryFileName: null,
|
|
3196
3574
|
resolvedPrerenderModules: void 0,
|
|
3197
3575
|
resolvedStaticModules: void 0,
|
|
@@ -3322,13 +3700,31 @@ function encodePathParam(value) {
|
|
|
3322
3700
|
}
|
|
3323
3701
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3324
3702
|
let result = pattern;
|
|
3703
|
+
let hadOmittedOptional = false;
|
|
3325
3704
|
for (const [key, value] of Object.entries(params)) {
|
|
3326
3705
|
const escaped = escapeRegExp2(key);
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3706
|
+
if (value === "") {
|
|
3707
|
+
result = result.replace(
|
|
3708
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
3709
|
+
""
|
|
3710
|
+
);
|
|
3711
|
+
result = result.replace(`*${key}`, "");
|
|
3712
|
+
} else {
|
|
3713
|
+
result = result.replace(
|
|
3714
|
+
new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
|
|
3715
|
+
encode(value)
|
|
3716
|
+
);
|
|
3717
|
+
result = result.replace(`*${key}`, encode(value));
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
3721
|
+
hadOmittedOptional = true;
|
|
3722
|
+
return "";
|
|
3723
|
+
});
|
|
3724
|
+
if (hadOmittedOptional) {
|
|
3725
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
3726
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3727
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
3332
3728
|
}
|
|
3333
3729
|
return result;
|
|
3334
3730
|
}
|
|
@@ -3438,84 +3834,126 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3438
3834
|
if (!params) return pattern;
|
|
3439
3835
|
return substituteRouteParams(pattern, params);
|
|
3440
3836
|
};
|
|
3837
|
+
let resolvedRoutes = 0;
|
|
3838
|
+
let totalDynamic = 0;
|
|
3441
3839
|
for (const { manifest } of allManifests) {
|
|
3442
3840
|
if (!manifest.prerenderRoutes) continue;
|
|
3443
|
-
const defs = manifest._prerenderDefs || {};
|
|
3444
3841
|
for (const routeName of manifest.prerenderRoutes) {
|
|
3445
3842
|
const pattern = manifest.routeManifest[routeName];
|
|
3446
|
-
if (
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
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
|
-
|
|
3843
|
+
if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
|
|
3844
|
+
totalDynamic++;
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
const paramsStart = performance.now();
|
|
3849
|
+
const progressInterval = totalDynamic > 0 ? setInterval(() => {
|
|
3850
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3851
|
+
console.log(
|
|
3852
|
+
`[rsc-router] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3853
|
+
);
|
|
3854
|
+
}, 5e3) : void 0;
|
|
3855
|
+
try {
|
|
3856
|
+
for (const { manifest } of allManifests) {
|
|
3857
|
+
if (!manifest.prerenderRoutes) continue;
|
|
3858
|
+
const defs = manifest._prerenderDefs || {};
|
|
3859
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
3860
|
+
for (const routeName of manifest.prerenderRoutes) {
|
|
3861
|
+
const pattern = manifest.routeManifest[routeName];
|
|
3862
|
+
if (!pattern) continue;
|
|
3863
|
+
const def = defs[routeName];
|
|
3864
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
3865
|
+
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
3866
|
+
if (!hasDynamic) {
|
|
3867
|
+
entries.push({
|
|
3868
|
+
urlPath: pattern.replace(/\/$/, "") || "/",
|
|
3869
|
+
routeName,
|
|
3870
|
+
concurrency: 1,
|
|
3871
|
+
isPassthroughRoute
|
|
3872
|
+
});
|
|
3873
|
+
} else {
|
|
3874
|
+
if (def?.getParams) {
|
|
3875
|
+
try {
|
|
3876
|
+
const buildVars = {};
|
|
3877
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
3878
|
+
const getParamsCtx = {
|
|
3879
|
+
build: true,
|
|
3880
|
+
dev: !state.isBuildMode,
|
|
3881
|
+
set: ((keyOrVar, value) => {
|
|
3882
|
+
contextSet(buildVars, keyOrVar, value);
|
|
3883
|
+
}),
|
|
3884
|
+
reverse: getParamsReverse,
|
|
3885
|
+
get env() {
|
|
3886
|
+
if (buildEnv !== void 0) return buildEnv;
|
|
3887
|
+
throw new Error(
|
|
3888
|
+
"[rsc-router] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3889
|
+
);
|
|
3481
3890
|
}
|
|
3891
|
+
};
|
|
3892
|
+
const paramsList = await def.getParams(getParamsCtx);
|
|
3893
|
+
const concurrency = def.options?.concurrency ?? 1;
|
|
3894
|
+
const hasBuildVars = Object.keys(buildVars).length > 0 || Object.getOwnPropertySymbols(buildVars).length > 0;
|
|
3895
|
+
for (const params of paramsList) {
|
|
3896
|
+
let url = substituteRouteParams(
|
|
3897
|
+
pattern,
|
|
3898
|
+
params,
|
|
3899
|
+
encodePathParam
|
|
3900
|
+
);
|
|
3901
|
+
if (url.includes("*")) {
|
|
3902
|
+
const wildcardValue = params["*"] ?? params.splat;
|
|
3903
|
+
if (wildcardValue !== void 0) {
|
|
3904
|
+
url = url.replace(
|
|
3905
|
+
/\*[^/]*$/,
|
|
3906
|
+
encodePathParam(wildcardValue)
|
|
3907
|
+
);
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
entries.push({
|
|
3911
|
+
urlPath: url.replace(/\/$/, "") || "/",
|
|
3912
|
+
routeName,
|
|
3913
|
+
concurrency,
|
|
3914
|
+
...hasBuildVars ? { buildVars } : {},
|
|
3915
|
+
isPassthroughRoute
|
|
3916
|
+
});
|
|
3482
3917
|
}
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
true
|
|
3918
|
+
resolvedRoutes++;
|
|
3919
|
+
} catch (err) {
|
|
3920
|
+
resolvedRoutes++;
|
|
3921
|
+
if (err.name === "Skip") {
|
|
3922
|
+
console.log(
|
|
3923
|
+
`[rsc-router] SKIP route "${routeName}" - ${err.message}`
|
|
3924
|
+
);
|
|
3925
|
+
notifyOnError(
|
|
3926
|
+
registry,
|
|
3927
|
+
err,
|
|
3928
|
+
"prerender",
|
|
3929
|
+
routeName,
|
|
3930
|
+
void 0,
|
|
3931
|
+
true
|
|
3932
|
+
);
|
|
3933
|
+
continue;
|
|
3934
|
+
}
|
|
3935
|
+
console.error(
|
|
3936
|
+
`[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`
|
|
3503
3937
|
);
|
|
3504
|
-
|
|
3938
|
+
notifyOnError(registry, err, "prerender", routeName);
|
|
3939
|
+
throw err;
|
|
3505
3940
|
}
|
|
3506
|
-
|
|
3507
|
-
|
|
3941
|
+
} else {
|
|
3942
|
+
console.warn(
|
|
3943
|
+
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3508
3944
|
);
|
|
3509
|
-
notifyOnError(registry, err, "prerender", routeName);
|
|
3510
|
-
throw err;
|
|
3511
3945
|
}
|
|
3512
|
-
} else {
|
|
3513
|
-
console.warn(
|
|
3514
|
-
`[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`
|
|
3515
|
-
);
|
|
3516
3946
|
}
|
|
3517
3947
|
}
|
|
3518
3948
|
}
|
|
3949
|
+
} finally {
|
|
3950
|
+
if (progressInterval) {
|
|
3951
|
+
clearInterval(progressInterval);
|
|
3952
|
+
const elapsed = ((performance.now() - paramsStart) / 1e3).toFixed(1);
|
|
3953
|
+
console.log(
|
|
3954
|
+
`[rsc-router] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`
|
|
3955
|
+
);
|
|
3956
|
+
}
|
|
3519
3957
|
}
|
|
3520
3958
|
if (entries.length === 0) return;
|
|
3521
3959
|
const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
|
|
@@ -3542,7 +3980,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3542
3980
|
entry.urlPath,
|
|
3543
3981
|
{},
|
|
3544
3982
|
entry.buildVars,
|
|
3545
|
-
entry.isPassthroughRoute
|
|
3983
|
+
entry.isPassthroughRoute,
|
|
3984
|
+
state.resolvedBuildEnv
|
|
3546
3985
|
);
|
|
3547
3986
|
if (!result) continue;
|
|
3548
3987
|
if (result.passthrough) {
|
|
@@ -3666,7 +4105,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3666
4105
|
const result = await routerInstance.renderStaticSegment(
|
|
3667
4106
|
def.handler,
|
|
3668
4107
|
def.$$id,
|
|
3669
|
-
def.$$routePrefix
|
|
4108
|
+
def.$$routePrefix,
|
|
4109
|
+
state.resolvedBuildEnv,
|
|
4110
|
+
!state.isBuildMode
|
|
3670
4111
|
);
|
|
3671
4112
|
if (result) {
|
|
3672
4113
|
const hasHandles = Object.keys(result.handles).length > 0;
|
|
@@ -3791,7 +4232,11 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3791
4232
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
3792
4233
|
continue;
|
|
3793
4234
|
}
|
|
3794
|
-
const manifest = generateManifestFull(
|
|
4235
|
+
const manifest = generateManifestFull(
|
|
4236
|
+
router.urlpatterns,
|
|
4237
|
+
routerMountIndex,
|
|
4238
|
+
router.__basename ? { urlPrefix: router.__basename } : void 0
|
|
4239
|
+
);
|
|
3795
4240
|
routerMountIndex++;
|
|
3796
4241
|
allManifests.push({ id, manifest });
|
|
3797
4242
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
@@ -4240,48 +4685,45 @@ function postprocessBundle(state) {
|
|
|
4240
4685
|
);
|
|
4241
4686
|
const evictionTargets = [
|
|
4242
4687
|
{
|
|
4243
|
-
|
|
4688
|
+
infos: state.handlerChunkInfoMap.values(),
|
|
4244
4689
|
fnName: "Prerender",
|
|
4245
4690
|
brand: "prerenderHandler",
|
|
4246
4691
|
label: "handler code from RSC bundle"
|
|
4247
4692
|
},
|
|
4248
4693
|
{
|
|
4249
|
-
|
|
4694
|
+
infos: state.staticHandlerChunkInfoMap.values(),
|
|
4250
4695
|
fnName: "Static",
|
|
4251
4696
|
brand: "staticHandler",
|
|
4252
4697
|
label: "static handler code"
|
|
4253
4698
|
}
|
|
4254
4699
|
];
|
|
4255
4700
|
for (const target of evictionTargets) {
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4701
|
+
for (const info of target.infos) {
|
|
4702
|
+
const chunkPath = resolve7(state.projectRoot, "dist/rsc", info.fileName);
|
|
4703
|
+
try {
|
|
4704
|
+
const code = readFileSync5(chunkPath, "utf-8");
|
|
4705
|
+
const result = evictHandlerCode(
|
|
4706
|
+
code,
|
|
4707
|
+
info.exports,
|
|
4708
|
+
target.fnName,
|
|
4709
|
+
target.brand
|
|
4710
|
+
);
|
|
4711
|
+
if (result) {
|
|
4712
|
+
writeFileSync4(chunkPath, result.code);
|
|
4713
|
+
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4714
|
+
console.log(
|
|
4715
|
+
`[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4716
|
+
);
|
|
4717
|
+
}
|
|
4718
|
+
} catch (replaceErr) {
|
|
4719
|
+
console.warn(
|
|
4720
|
+
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4275
4721
|
);
|
|
4276
4722
|
}
|
|
4277
|
-
} catch (replaceErr) {
|
|
4278
|
-
console.warn(
|
|
4279
|
-
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4280
|
-
);
|
|
4281
4723
|
}
|
|
4282
4724
|
}
|
|
4283
|
-
state.
|
|
4284
|
-
state.
|
|
4725
|
+
state.handlerChunkInfoMap.clear();
|
|
4726
|
+
state.staticHandlerChunkInfoMap.clear();
|
|
4285
4727
|
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
4286
4728
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4287
4729
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
@@ -4324,7 +4766,7 @@ function postprocessBundle(state) {
|
|
|
4324
4766
|
}
|
|
4325
4767
|
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
4326
4768
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4327
|
-
if (!rscCode.includes("
|
|
4769
|
+
if (!rscCode.includes("__static-manifest.js")) {
|
|
4328
4770
|
try {
|
|
4329
4771
|
const manifestEntries = [];
|
|
4330
4772
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -4363,7 +4805,22 @@ function postprocessBundle(state) {
|
|
|
4363
4805
|
}
|
|
4364
4806
|
|
|
4365
4807
|
// src/vite/router-discovery.ts
|
|
4808
|
+
var loaderHookRegistered = false;
|
|
4809
|
+
function ensureCloudflareProtocolLoaderRegistered() {
|
|
4810
|
+
if (loaderHookRegistered) return;
|
|
4811
|
+
loaderHookRegistered = true;
|
|
4812
|
+
try {
|
|
4813
|
+
register(
|
|
4814
|
+
new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url)
|
|
4815
|
+
);
|
|
4816
|
+
} catch (err) {
|
|
4817
|
+
console.warn(
|
|
4818
|
+
`[rsc-router] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
|
|
4819
|
+
);
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4366
4822
|
async function createTempRscServer(state, options = {}) {
|
|
4823
|
+
ensureCloudflareProtocolLoaderRegistered();
|
|
4367
4824
|
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
4368
4825
|
return createViteServer({
|
|
4369
4826
|
root: state.projectRoot,
|
|
@@ -4386,6 +4843,7 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4386
4843
|
...options.forceBuild ? [hashClientRefs(state.projectRoot)] : [],
|
|
4387
4844
|
createVersionPlugin(),
|
|
4388
4845
|
createVirtualStubPlugin(),
|
|
4846
|
+
createCloudflareProtocolStubPlugin(),
|
|
4389
4847
|
// Dev prerender must use dev-mode IDs (path-based) to match the workerd
|
|
4390
4848
|
// runtime. forceBuild produces hashed IDs for production bundle consistency.
|
|
4391
4849
|
exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
|
|
@@ -4393,8 +4851,69 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4393
4851
|
]
|
|
4394
4852
|
});
|
|
4395
4853
|
}
|
|
4854
|
+
async function resolveBuildEnv(option, factoryCtx) {
|
|
4855
|
+
if (!option) return null;
|
|
4856
|
+
if (option === "auto") {
|
|
4857
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
4858
|
+
throw new Error(
|
|
4859
|
+
'[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4860
|
+
);
|
|
4861
|
+
}
|
|
4862
|
+
try {
|
|
4863
|
+
const userRequire = createRequire2(
|
|
4864
|
+
resolve8(factoryCtx.root, "package.json")
|
|
4865
|
+
);
|
|
4866
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
4867
|
+
const { getPlatformProxy } = await import(pathToFileURL(wranglerPath).href);
|
|
4868
|
+
const proxy = await getPlatformProxy();
|
|
4869
|
+
return {
|
|
4870
|
+
env: proxy.env,
|
|
4871
|
+
dispose: proxy.dispose
|
|
4872
|
+
};
|
|
4873
|
+
} catch (err) {
|
|
4874
|
+
throw new Error(
|
|
4875
|
+
`[rsc-router] buildEnv: "auto" requires wrangler to be installed.
|
|
4876
|
+
Install it with: pnpm add -D wrangler
|
|
4877
|
+
${err.message}`
|
|
4878
|
+
);
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
if (typeof option === "function") {
|
|
4882
|
+
return await option(factoryCtx);
|
|
4883
|
+
}
|
|
4884
|
+
return { env: option };
|
|
4885
|
+
}
|
|
4886
|
+
async function acquireBuildEnv(s, command, mode) {
|
|
4887
|
+
const option = s.opts?.buildEnv;
|
|
4888
|
+
if (!option) return false;
|
|
4889
|
+
const result = await resolveBuildEnv(option, {
|
|
4890
|
+
root: s.projectRoot,
|
|
4891
|
+
mode,
|
|
4892
|
+
command,
|
|
4893
|
+
preset: s.opts?.preset ?? "node"
|
|
4894
|
+
});
|
|
4895
|
+
if (!result) return false;
|
|
4896
|
+
s.resolvedBuildEnv = result.env;
|
|
4897
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
4898
|
+
globalThis[BUILD_ENV_GLOBAL_KEY] = result.env;
|
|
4899
|
+
return true;
|
|
4900
|
+
}
|
|
4901
|
+
async function releaseBuildEnv(s) {
|
|
4902
|
+
if (s.buildEnvDispose) {
|
|
4903
|
+
try {
|
|
4904
|
+
await s.buildEnvDispose();
|
|
4905
|
+
} catch (err) {
|
|
4906
|
+
console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
|
|
4907
|
+
}
|
|
4908
|
+
s.buildEnvDispose = null;
|
|
4909
|
+
}
|
|
4910
|
+
s.resolvedBuildEnv = void 0;
|
|
4911
|
+
delete globalThis[BUILD_ENV_GLOBAL_KEY];
|
|
4912
|
+
}
|
|
4396
4913
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4397
4914
|
const s = createDiscoveryState(entryPath, opts);
|
|
4915
|
+
let viteCommand = "build";
|
|
4916
|
+
let viteMode = "production";
|
|
4398
4917
|
return {
|
|
4399
4918
|
name: "@rangojs/router:discovery",
|
|
4400
4919
|
config() {
|
|
@@ -4403,31 +4922,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4403
4922
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
|
|
4404
4923
|
}
|
|
4405
4924
|
};
|
|
4406
|
-
if (opts?.enableBuildPrerender) {
|
|
4407
|
-
config.environments = {
|
|
4408
|
-
rsc: {
|
|
4409
|
-
build: {
|
|
4410
|
-
rollupOptions: {
|
|
4411
|
-
output: {
|
|
4412
|
-
manualChunks(id) {
|
|
4413
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
4414
|
-
return "__prerender-handlers";
|
|
4415
|
-
}
|
|
4416
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
4417
|
-
return "__static-handlers";
|
|
4418
|
-
}
|
|
4419
|
-
}
|
|
4420
|
-
}
|
|
4421
|
-
}
|
|
4422
|
-
}
|
|
4423
|
-
}
|
|
4424
|
-
};
|
|
4425
|
-
}
|
|
4426
4925
|
return config;
|
|
4427
4926
|
},
|
|
4428
4927
|
configResolved(config) {
|
|
4429
4928
|
s.projectRoot = config.root;
|
|
4430
4929
|
s.isBuildMode = config.command === "build";
|
|
4930
|
+
viteCommand = config.command;
|
|
4931
|
+
viteMode = config.mode;
|
|
4431
4932
|
s.userResolveAlias = config.resolve.alias;
|
|
4432
4933
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4433
4934
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
@@ -4472,6 +4973,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4472
4973
|
});
|
|
4473
4974
|
prerenderTempServer = null;
|
|
4474
4975
|
}
|
|
4976
|
+
releaseBuildEnv(s).catch(() => {
|
|
4977
|
+
});
|
|
4475
4978
|
});
|
|
4476
4979
|
async function getOrCreateTempServer() {
|
|
4477
4980
|
if (prerenderNodeRegistry) {
|
|
@@ -4502,6 +5005,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4502
5005
|
if (!rscEnv?.runner) {
|
|
4503
5006
|
s.devServerOrigin = getDevServerOrigin();
|
|
4504
5007
|
try {
|
|
5008
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4505
5009
|
const tempRscEnv = await getOrCreateTempServer();
|
|
4506
5010
|
if (tempRscEnv) {
|
|
4507
5011
|
await discoverRouters(s, tempRscEnv);
|
|
@@ -4517,6 +5021,7 @@ ${err.stack}`
|
|
|
4517
5021
|
return;
|
|
4518
5022
|
}
|
|
4519
5023
|
try {
|
|
5024
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4520
5025
|
const serverMod = await rscEnv.runner.import(
|
|
4521
5026
|
"@rangojs/router/server"
|
|
4522
5027
|
);
|
|
@@ -4581,7 +5086,26 @@ ${err.stack}`
|
|
|
4581
5086
|
res.end("Missing pathname");
|
|
4582
5087
|
return;
|
|
4583
5088
|
}
|
|
4584
|
-
|
|
5089
|
+
const rscEnv = server.environments?.rsc;
|
|
5090
|
+
let registry = null;
|
|
5091
|
+
if (rscEnv?.runner && s.resolvedEntryPath) {
|
|
5092
|
+
try {
|
|
5093
|
+
await rscEnv.runner.import(s.resolvedEntryPath);
|
|
5094
|
+
const serverMod = await rscEnv.runner.import(
|
|
5095
|
+
"@rangojs/router/server"
|
|
5096
|
+
);
|
|
5097
|
+
registry = serverMod.RouterRegistry ?? null;
|
|
5098
|
+
} catch (err) {
|
|
5099
|
+
console.warn(
|
|
5100
|
+
`[rsc-router] Dev prerender module refresh failed: ${err.message}`
|
|
5101
|
+
);
|
|
5102
|
+
res.statusCode = 500;
|
|
5103
|
+
res.end(`Prerender handler error: ${err.message}`);
|
|
5104
|
+
return;
|
|
5105
|
+
}
|
|
5106
|
+
} else {
|
|
5107
|
+
registry = mainRegistry;
|
|
5108
|
+
}
|
|
4585
5109
|
if (!registry) {
|
|
4586
5110
|
if (!prerenderNodeRegistry) {
|
|
4587
5111
|
await getOrCreateTempServer();
|
|
@@ -4603,7 +5127,10 @@ ${err.stack}`
|
|
|
4603
5127
|
pathname,
|
|
4604
5128
|
{},
|
|
4605
5129
|
void 0,
|
|
4606
|
-
wantPassthrough
|
|
5130
|
+
wantPassthrough,
|
|
5131
|
+
s.resolvedBuildEnv,
|
|
5132
|
+
true
|
|
5133
|
+
// devMode: check getParams for passthrough routes
|
|
4607
5134
|
);
|
|
4608
5135
|
if (!result) continue;
|
|
4609
5136
|
if (result.passthrough) continue;
|
|
@@ -4739,6 +5266,7 @@ ${err.stack}`
|
|
|
4739
5266
|
resetStagedBuildAssets(s.projectRoot);
|
|
4740
5267
|
s.prerenderManifestEntries = null;
|
|
4741
5268
|
s.staticManifestEntries = null;
|
|
5269
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4742
5270
|
let tempServer = null;
|
|
4743
5271
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4744
5272
|
try {
|
|
@@ -4778,6 +5306,7 @@ ${details}`
|
|
|
4778
5306
|
if (tempServer) {
|
|
4779
5307
|
await tempServer.close();
|
|
4780
5308
|
}
|
|
5309
|
+
await releaseBuildEnv(s);
|
|
4781
5310
|
}
|
|
4782
5311
|
},
|
|
4783
5312
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -4820,20 +5349,30 @@ ${details}`
|
|
|
4820
5349
|
}
|
|
4821
5350
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
4822
5351
|
return;
|
|
5352
|
+
s.handlerChunkInfoMap.clear();
|
|
5353
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
4823
5354
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
4824
5355
|
if (chunk.type !== "chunk") continue;
|
|
4825
|
-
if (
|
|
5356
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
4826
5357
|
const handlers = extractHandlerExportsFromChunk(
|
|
4827
5358
|
chunk.code,
|
|
4828
5359
|
s.resolvedPrerenderModules,
|
|
4829
5360
|
"Prerender",
|
|
4830
|
-
|
|
5361
|
+
false
|
|
4831
5362
|
);
|
|
4832
5363
|
if (handlers.length > 0) {
|
|
4833
|
-
|
|
5364
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
5365
|
+
if (existing) {
|
|
5366
|
+
existing.exports.push(...handlers);
|
|
5367
|
+
} else {
|
|
5368
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
5369
|
+
fileName,
|
|
5370
|
+
exports: handlers
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
4834
5373
|
}
|
|
4835
5374
|
}
|
|
4836
|
-
if (
|
|
5375
|
+
if (s.resolvedStaticModules?.size) {
|
|
4837
5376
|
const handlers = extractHandlerExportsFromChunk(
|
|
4838
5377
|
chunk.code,
|
|
4839
5378
|
s.resolvedStaticModules,
|
|
@@ -4841,7 +5380,15 @@ ${details}`
|
|
|
4841
5380
|
false
|
|
4842
5381
|
);
|
|
4843
5382
|
if (handlers.length > 0) {
|
|
4844
|
-
|
|
5383
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
5384
|
+
if (existing) {
|
|
5385
|
+
existing.exports.push(...handlers);
|
|
5386
|
+
} else {
|
|
5387
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
5388
|
+
fileName,
|
|
5389
|
+
exports: handlers
|
|
5390
|
+
});
|
|
5391
|
+
}
|
|
4845
5392
|
}
|
|
4846
5393
|
}
|
|
4847
5394
|
}
|
|
@@ -4861,144 +5408,28 @@ ${details}`
|
|
|
4861
5408
|
};
|
|
4862
5409
|
}
|
|
4863
5410
|
|
|
4864
|
-
// src/vite/plugins/performance-tracks.ts
|
|
4865
|
-
import { Module } from "node:module";
|
|
4866
|
-
var DEBUG_ID_HEADER = "X-RSC-Debug-Id";
|
|
4867
|
-
var DEBUG_S2C_EVENT = "rango:perf-s2c";
|
|
4868
|
-
var DEBUG_C2S_EVENT = "rango:perf-c2s";
|
|
4869
|
-
var GLOBAL_KEY = "__RANGO_DEBUG_CHANNELS__";
|
|
4870
|
-
function getRegistry() {
|
|
4871
|
-
return Module[GLOBAL_KEY] ??= {
|
|
4872
|
-
channels: /* @__PURE__ */ new Map(),
|
|
4873
|
-
sessions: /* @__PURE__ */ new Map()
|
|
4874
|
-
};
|
|
4875
|
-
}
|
|
4876
|
-
var bytesToBase64 = (bytes) => Buffer.from(bytes).toString("base64");
|
|
4877
|
-
var base64ToBytes = (base64) => new Uint8Array(Buffer.from(base64, "base64"));
|
|
4878
|
-
function performanceTracksPlugin() {
|
|
4879
|
-
return {
|
|
4880
|
-
name: "@rangojs/router:performance-tracks",
|
|
4881
|
-
// Only configureServer hook — naturally dev-only
|
|
4882
|
-
configureServer(server) {
|
|
4883
|
-
console.log("[perf-tracks] plugin loaded, configureServer called");
|
|
4884
|
-
const hot = server.environments.client.hot;
|
|
4885
|
-
const registry = getRegistry();
|
|
4886
|
-
const sessions = registry.sessions;
|
|
4887
|
-
const sendChunk = (debugId, chunk) => {
|
|
4888
|
-
hot.send(DEBUG_S2C_EVENT, {
|
|
4889
|
-
i: debugId,
|
|
4890
|
-
b: bytesToBase64(chunk)
|
|
4891
|
-
});
|
|
4892
|
-
};
|
|
4893
|
-
const cleanupIfEnded = (debugId, session) => {
|
|
4894
|
-
if (session.pendingChunks || !session.ended) return;
|
|
4895
|
-
sessions.delete(debugId);
|
|
4896
|
-
hot.send(DEBUG_S2C_EVENT, {
|
|
4897
|
-
i: debugId,
|
|
4898
|
-
d: true
|
|
4899
|
-
});
|
|
4900
|
-
};
|
|
4901
|
-
const registerDebugChannel = (debugId) => {
|
|
4902
|
-
let session = sessions.get(debugId);
|
|
4903
|
-
if (!session) {
|
|
4904
|
-
session = { pendingChunks: [], ended: false };
|
|
4905
|
-
sessions.set(debugId, session);
|
|
4906
|
-
}
|
|
4907
|
-
const readable = new ReadableStream({
|
|
4908
|
-
start(controller) {
|
|
4909
|
-
session.cmdController = controller;
|
|
4910
|
-
},
|
|
4911
|
-
cancel() {
|
|
4912
|
-
delete session.cmdController;
|
|
4913
|
-
}
|
|
4914
|
-
});
|
|
4915
|
-
const writable = new WritableStream({
|
|
4916
|
-
write(chunk) {
|
|
4917
|
-
if (session.pendingChunks) {
|
|
4918
|
-
session.pendingChunks.push(chunk);
|
|
4919
|
-
} else {
|
|
4920
|
-
sendChunk(debugId, chunk);
|
|
4921
|
-
}
|
|
4922
|
-
},
|
|
4923
|
-
close() {
|
|
4924
|
-
session.ended = true;
|
|
4925
|
-
cleanupIfEnded(debugId, session);
|
|
4926
|
-
},
|
|
4927
|
-
abort() {
|
|
4928
|
-
session.ended = true;
|
|
4929
|
-
cleanupIfEnded(debugId, session);
|
|
4930
|
-
}
|
|
4931
|
-
});
|
|
4932
|
-
registry.channels.set(debugId, { readable, writable });
|
|
4933
|
-
};
|
|
4934
|
-
hot.on(DEBUG_C2S_EVENT, (raw) => {
|
|
4935
|
-
const payload = raw;
|
|
4936
|
-
const session = sessions.get(payload.i);
|
|
4937
|
-
if (payload.d) {
|
|
4938
|
-
if (session?.cmdController) {
|
|
4939
|
-
try {
|
|
4940
|
-
session.cmdController.close();
|
|
4941
|
-
} catch {
|
|
4942
|
-
}
|
|
4943
|
-
delete session.cmdController;
|
|
4944
|
-
}
|
|
4945
|
-
return;
|
|
4946
|
-
}
|
|
4947
|
-
if (payload.b) {
|
|
4948
|
-
if (session?.cmdController) {
|
|
4949
|
-
try {
|
|
4950
|
-
session.cmdController.enqueue(base64ToBytes(payload.b));
|
|
4951
|
-
} catch {
|
|
4952
|
-
delete session.cmdController;
|
|
4953
|
-
}
|
|
4954
|
-
}
|
|
4955
|
-
return;
|
|
4956
|
-
}
|
|
4957
|
-
if (session) {
|
|
4958
|
-
if (session.pendingChunks) {
|
|
4959
|
-
for (const chunk of session.pendingChunks) {
|
|
4960
|
-
sendChunk(payload.i, chunk);
|
|
4961
|
-
}
|
|
4962
|
-
delete session.pendingChunks;
|
|
4963
|
-
}
|
|
4964
|
-
cleanupIfEnded(payload.i, session);
|
|
4965
|
-
} else {
|
|
4966
|
-
sessions.set(payload.i, { ended: false });
|
|
4967
|
-
}
|
|
4968
|
-
});
|
|
4969
|
-
server.middlewares.use((req, _res, next) => {
|
|
4970
|
-
const existingId = req.headers[DEBUG_ID_HEADER.toLowerCase()];
|
|
4971
|
-
const debugId = existingId || crypto.randomUUID();
|
|
4972
|
-
if (!existingId) {
|
|
4973
|
-
const lowerName = DEBUG_ID_HEADER.toLowerCase();
|
|
4974
|
-
req.headers[lowerName] = debugId;
|
|
4975
|
-
if (req.rawHeaders) {
|
|
4976
|
-
req.rawHeaders.push(DEBUG_ID_HEADER, debugId);
|
|
4977
|
-
}
|
|
4978
|
-
}
|
|
4979
|
-
registerDebugChannel(debugId);
|
|
4980
|
-
console.log(
|
|
4981
|
-
"[perf-tracks] middleware: channel for",
|
|
4982
|
-
debugId,
|
|
4983
|
-
"url:",
|
|
4984
|
-
req.url?.slice(0, 60),
|
|
4985
|
-
existingId ? "(client)" : "(server-generated)"
|
|
4986
|
-
);
|
|
4987
|
-
next();
|
|
4988
|
-
});
|
|
4989
|
-
}
|
|
4990
|
-
};
|
|
4991
|
-
}
|
|
4992
|
-
|
|
4993
5411
|
// src/vite/rango.ts
|
|
4994
5412
|
async function rango(options) {
|
|
4995
5413
|
const resolvedOptions = options ?? { preset: "node" };
|
|
4996
5414
|
const preset = resolvedOptions.preset ?? "node";
|
|
4997
|
-
console.log("[perf-tracks] rango() called, preset:", preset);
|
|
4998
5415
|
const showBanner = resolvedOptions.banner ?? true;
|
|
4999
5416
|
const plugins = [];
|
|
5000
|
-
const rangoAliases = getPackageAliases();
|
|
5001
|
-
const excludeDeps =
|
|
5417
|
+
const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
|
|
5418
|
+
const excludeDeps = [
|
|
5419
|
+
...getExcludeDeps(),
|
|
5420
|
+
// plugin-rsc itself injects these into the client env's
|
|
5421
|
+
// optimizeDeps.include, which overrides exclude for the dep's own
|
|
5422
|
+
// pre-bundle entry. What exclude still controls is how *other*
|
|
5423
|
+
// pre-bundled deps treat imports of these specs (external vs inlined)
|
|
5424
|
+
// via esbuildCjsExternalPlugin. The cjs-to-esm transform in
|
|
5425
|
+
// plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
|
|
5426
|
+
// where client.browser's bare include fails to resolve and Vite ends up
|
|
5427
|
+
// serving the raw CJS file at dev-serve time.
|
|
5428
|
+
"@vitejs/plugin-rsc/browser",
|
|
5429
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser"
|
|
5430
|
+
];
|
|
5431
|
+
const pkg = getPublishedPackageName();
|
|
5432
|
+
const nested = (spec) => `${pkg} > ${spec}`;
|
|
5002
5433
|
const routerRef = { path: void 0 };
|
|
5003
5434
|
const prerenderEnabled = true;
|
|
5004
5435
|
if (preset === "cloudflare") {
|
|
@@ -5036,7 +5467,7 @@ async function rango(options) {
|
|
|
5036
5467
|
// Pre-bundle rsc-html-stream to prevent discovery during first request
|
|
5037
5468
|
// Exclude rsc-router modules to ensure same Context instance
|
|
5038
5469
|
optimizeDeps: {
|
|
5039
|
-
include: ["rsc-html-stream/client"],
|
|
5470
|
+
include: [nested("rsc-html-stream/client")],
|
|
5040
5471
|
exclude: excludeDeps,
|
|
5041
5472
|
esbuildOptions: sharedEsbuildOptions
|
|
5042
5473
|
}
|
|
@@ -5061,8 +5492,10 @@ async function rango(options) {
|
|
|
5061
5492
|
"react-dom/static.edge",
|
|
5062
5493
|
"react/jsx-runtime",
|
|
5063
5494
|
"react/jsx-dev-runtime",
|
|
5064
|
-
"rsc-html-stream/server",
|
|
5065
|
-
|
|
5495
|
+
nested("rsc-html-stream/server"),
|
|
5496
|
+
nested(
|
|
5497
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5498
|
+
)
|
|
5066
5499
|
],
|
|
5067
5500
|
exclude: excludeDeps,
|
|
5068
5501
|
esbuildOptions: sharedEsbuildOptions
|
|
@@ -5077,7 +5510,9 @@ async function rango(options) {
|
|
|
5077
5510
|
"react",
|
|
5078
5511
|
"react/jsx-runtime",
|
|
5079
5512
|
"react/jsx-dev-runtime",
|
|
5080
|
-
|
|
5513
|
+
nested(
|
|
5514
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
5515
|
+
)
|
|
5081
5516
|
],
|
|
5082
5517
|
exclude: excludeDeps,
|
|
5083
5518
|
esbuildOptions: sharedEsbuildOptions
|
|
@@ -5094,6 +5529,7 @@ async function rango(options) {
|
|
|
5094
5529
|
}
|
|
5095
5530
|
});
|
|
5096
5531
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
5532
|
+
plugins.push(performanceTracksPlugin());
|
|
5097
5533
|
plugins.push(
|
|
5098
5534
|
rsc({
|
|
5099
5535
|
entries: finalEntries,
|
|
@@ -5157,7 +5593,7 @@ ${list}`);
|
|
|
5157
5593
|
"react-dom",
|
|
5158
5594
|
"react/jsx-runtime",
|
|
5159
5595
|
"react/jsx-dev-runtime",
|
|
5160
|
-
"rsc-html-stream/client"
|
|
5596
|
+
nested("rsc-html-stream/client")
|
|
5161
5597
|
],
|
|
5162
5598
|
exclude: excludeDeps,
|
|
5163
5599
|
esbuildOptions: sharedEsbuildOptions,
|
|
@@ -5174,7 +5610,9 @@ ${list}`);
|
|
|
5174
5610
|
"react-dom/static.edge",
|
|
5175
5611
|
"react/jsx-runtime",
|
|
5176
5612
|
"react/jsx-dev-runtime",
|
|
5177
|
-
|
|
5613
|
+
nested(
|
|
5614
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5615
|
+
)
|
|
5178
5616
|
],
|
|
5179
5617
|
exclude: excludeDeps,
|
|
5180
5618
|
esbuildOptions: sharedEsbuildOptions
|
|
@@ -5187,7 +5625,9 @@ ${list}`);
|
|
|
5187
5625
|
"react",
|
|
5188
5626
|
"react/jsx-runtime",
|
|
5189
5627
|
"react/jsx-dev-runtime",
|
|
5190
|
-
|
|
5628
|
+
nested(
|
|
5629
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
5630
|
+
)
|
|
5191
5631
|
],
|
|
5192
5632
|
esbuildOptions: sharedEsbuildOptions
|
|
5193
5633
|
}
|
|
@@ -5212,12 +5652,7 @@ ${list}`);
|
|
|
5212
5652
|
}
|
|
5213
5653
|
});
|
|
5214
5654
|
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
5215
|
-
|
|
5216
|
-
console.log(
|
|
5217
|
-
"[perf-tracks] rango: plugin created, has configureServer:",
|
|
5218
|
-
!!perfPlugin.configureServer
|
|
5219
|
-
);
|
|
5220
|
-
plugins.push(perfPlugin);
|
|
5655
|
+
plugins.push(performanceTracksPlugin());
|
|
5221
5656
|
plugins.push(
|
|
5222
5657
|
rsc({
|
|
5223
5658
|
entries: finalEntries
|
|
@@ -5258,7 +5693,8 @@ ${list}`);
|
|
|
5258
5693
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5259
5694
|
routerPathRef: discoveryRouterRef,
|
|
5260
5695
|
enableBuildPrerender: prerenderEnabled,
|
|
5261
|
-
|
|
5696
|
+
buildEnv: options?.buildEnv,
|
|
5697
|
+
preset
|
|
5262
5698
|
})
|
|
5263
5699
|
);
|
|
5264
5700
|
return plugins;
|
|
@@ -5271,29 +5707,75 @@ function poke() {
|
|
|
5271
5707
|
apply: "serve",
|
|
5272
5708
|
configureServer(server) {
|
|
5273
5709
|
const stdin = process.stdin;
|
|
5274
|
-
const
|
|
5710
|
+
const debug = process.env.RANGO_POKE_DEBUG === "1";
|
|
5711
|
+
const triggerReload = (source) => {
|
|
5712
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
5713
|
+
server.config.logger.info(` browser reload (${source})`, {
|
|
5714
|
+
timestamp: true
|
|
5715
|
+
});
|
|
5716
|
+
};
|
|
5717
|
+
const toBuffer = (chunk) => {
|
|
5718
|
+
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5719
|
+
};
|
|
5720
|
+
const formatChunk = (chunk) => {
|
|
5721
|
+
const data = toBuffer(chunk);
|
|
5722
|
+
const hex = Array.from(data).map((byte) => `0x${byte.toString(16).padStart(2, "0")}`).join(" ");
|
|
5723
|
+
const ascii = Array.from(data).map((byte) => {
|
|
5724
|
+
if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
|
|
5725
|
+
if (byte === 10) return "\\n";
|
|
5726
|
+
if (byte === 13) return "\\r";
|
|
5727
|
+
if (byte === 9) return "\\t";
|
|
5728
|
+
return ".";
|
|
5729
|
+
}).join("");
|
|
5730
|
+
return `len=${data.length} hex=[${hex}] ascii="${ascii}"`;
|
|
5731
|
+
};
|
|
5732
|
+
const readCtrlR = (chunk) => {
|
|
5733
|
+
const data = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5734
|
+
return data.length === 1 && data[0] === 18;
|
|
5735
|
+
};
|
|
5736
|
+
const readSubmittedCommands = (chunk) => {
|
|
5737
|
+
const text = toBuffer(chunk).toString("utf8").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
5738
|
+
if (!text.includes("\n")) return [];
|
|
5739
|
+
const lines = text.split("\n");
|
|
5740
|
+
lines.pop();
|
|
5741
|
+
return lines;
|
|
5742
|
+
};
|
|
5743
|
+
if (debug) {
|
|
5744
|
+
server.config.logger.info(
|
|
5745
|
+
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5746
|
+
{ timestamp: true }
|
|
5747
|
+
);
|
|
5748
|
+
}
|
|
5275
5749
|
if (stdin.isTTY) {
|
|
5276
|
-
|
|
5750
|
+
server.config.logger.info(
|
|
5751
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
5752
|
+
{ timestamp: true }
|
|
5753
|
+
);
|
|
5277
5754
|
}
|
|
5278
5755
|
const onData = (data) => {
|
|
5279
|
-
if (
|
|
5280
|
-
|
|
5281
|
-
process.emit("SIGINT", "SIGINT");
|
|
5282
|
-
return;
|
|
5283
|
-
}
|
|
5284
|
-
if (data[0] === 18) {
|
|
5285
|
-
server.hot.send({ type: "full-reload", path: "*" });
|
|
5286
|
-
server.config.logger.info(" browser reload (ctrl+r)", {
|
|
5756
|
+
if (debug) {
|
|
5757
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5287
5758
|
timestamp: true
|
|
5288
5759
|
});
|
|
5289
5760
|
}
|
|
5761
|
+
if (readCtrlR(data)) {
|
|
5762
|
+
triggerReload("ctrl+r");
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5765
|
+
for (const command of readSubmittedCommands(data)) {
|
|
5766
|
+
if (command === "e") {
|
|
5767
|
+
triggerReload("e+enter");
|
|
5768
|
+
return;
|
|
5769
|
+
}
|
|
5770
|
+
if (command === "\x1Br") {
|
|
5771
|
+
triggerReload("option+r+enter");
|
|
5772
|
+
return;
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5290
5775
|
};
|
|
5291
5776
|
stdin.on("data", onData);
|
|
5292
5777
|
server.httpServer?.on("close", () => {
|
|
5293
5778
|
stdin.off("data", onData);
|
|
5294
|
-
if (stdin.isTTY && previousRawMode !== null) {
|
|
5295
|
-
stdin.setRawMode(previousRawMode);
|
|
5296
|
-
}
|
|
5297
5779
|
});
|
|
5298
5780
|
}
|
|
5299
5781
|
};
|