@rangojs/router 0.0.0-experimental.1b930379 → 0.0.0-experimental.1fa245e2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/README.md +76 -18
- package/dist/bin/rango.js +138 -50
- package/dist/vite/index.js +558 -319
- package/package.json +16 -15
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +45 -4
- package/skills/links/SKILL.md +3 -1
- package/skills/loader/SKILL.md +53 -43
- package/skills/middleware/SKILL.md +2 -0
- package/skills/parallel/SKILL.md +126 -0
- package/skills/prerender/SKILL.md +110 -68
- package/skills/route/SKILL.md +31 -0
- package/skills/router-setup/SKILL.md +87 -2
- package/skills/typesafety/SKILL.md +10 -0
- package/src/__internal.ts +1 -1
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/navigation-bridge.ts +19 -13
- package/src/browser/navigation-client.ts +115 -58
- package/src/browser/navigation-store.ts +43 -8
- package/src/browser/navigation-transaction.ts +11 -9
- package/src/browser/partial-update.ts +80 -15
- package/src/browser/prefetch/cache.ts +57 -5
- package/src/browser/prefetch/fetch.ts +38 -23
- package/src/browser/prefetch/queue.ts +92 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/react/Link.tsx +53 -9
- package/src/browser/react/NavigationProvider.tsx +40 -4
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-router.ts +21 -8
- package/src/browser/rsc-router.tsx +134 -59
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +6 -1
- package/src/browser/server-action-bridge.ts +8 -6
- package/src/browser/types.ts +36 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +223 -74
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +48 -7
- package/src/cache/cf/cf-cache-store.ts +453 -11
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.tsx +2 -56
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/index.rsc.ts +3 -1
- package/src/index.ts +8 -0
- package/src/prerender/store.ts +5 -4
- package/src/prerender.ts +138 -77
- package/src/reverse.ts +22 -1
- package/src/route-definition/dsl-helpers.ts +73 -25
- package/src/route-definition/helpers-types.ts +10 -6
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +11 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +79 -23
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +4 -1
- package/src/router/loader-resolution.ts +122 -10
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +9 -3
- package/src/router/match-api.ts +124 -189
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +88 -16
- package/src/router/match-middleware/cache-store.ts +53 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +22 -6
- package/src/router/metrics.ts +6 -1
- package/src/router/middleware-types.ts +6 -8
- package/src/router/middleware.ts +4 -6
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/prerender-match.ts +110 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +36 -4
- package/src/router/router-options.ts +37 -11
- package/src/router/segment-resolution/fresh.ts +183 -20
- package/src/router/segment-resolution/helpers.ts +29 -24
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +412 -297
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/types.ts +1 -0
- package/src/router.ts +59 -6
- package/src/rsc/handler.ts +460 -368
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +4 -0
- package/src/rsc/rsc-rendering.ts +5 -0
- package/src/rsc/server-action.ts +2 -0
- package/src/rsc/ssr-setup.ts +2 -2
- package/src/rsc/types.ts +8 -1
- package/src/segment-system.tsx +140 -4
- package/src/server/context.ts +140 -14
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +144 -18
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +137 -33
- package/src/types/loader-types.ts +36 -9
- package/src/types/route-entry.ts +8 -1
- package/src/types/segments.ts +2 -0
- package/src/urls/path-helper-types.ts +9 -2
- package/src/urls/path-helper.ts +48 -13
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +16 -6
- package/src/use-loader.tsx +73 -4
- 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 +14 -1
- package/src/vite/discovery/state.ts +13 -6
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/expose-action-id.ts +1 -3
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +88 -26
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +163 -211
- package/src/vite/router-discovery.ts +153 -42
- package/src/vite/utils/banner.ts +3 -3
- package/src/vite/utils/prerender-utils.ts +18 -0
- package/src/vite/utils/shared-utils.ts +3 -2
package/dist/vite/index.js
CHANGED
|
@@ -292,7 +292,7 @@ function exposeActionId() {
|
|
|
292
292
|
}
|
|
293
293
|
if (!rscPluginApi) {
|
|
294
294
|
throw new Error(
|
|
295
|
-
"[rsc-router] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin
|
|
295
|
+
"[rsc-router] Could not find @vitejs/plugin-rsc. @rangojs/router requires the Vite RSC plugin, which is included automatically by rango()."
|
|
296
296
|
);
|
|
297
297
|
}
|
|
298
298
|
if (!isBuild) return;
|
|
@@ -1745,7 +1745,7 @@ import { resolve } from "node:path";
|
|
|
1745
1745
|
// package.json
|
|
1746
1746
|
var package_default = {
|
|
1747
1747
|
name: "@rangojs/router",
|
|
1748
|
-
version: "0.0.0-experimental.
|
|
1748
|
+
version: "0.0.0-experimental.1fa245e2",
|
|
1749
1749
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1750
1750
|
keywords: [
|
|
1751
1751
|
"react",
|
|
@@ -1887,7 +1887,7 @@ var package_default = {
|
|
|
1887
1887
|
"test:unit:watch": "vitest"
|
|
1888
1888
|
},
|
|
1889
1889
|
dependencies: {
|
|
1890
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
1890
|
+
"@vitejs/plugin-rsc": "^0.5.19",
|
|
1891
1891
|
"magic-string": "^0.30.17",
|
|
1892
1892
|
picomatch: "^4.0.3",
|
|
1893
1893
|
"rsc-html-stream": "^0.0.7"
|
|
@@ -2095,31 +2095,7 @@ declare global {
|
|
|
2095
2095
|
}
|
|
2096
2096
|
|
|
2097
2097
|
// src/build/route-types/scan-filter.ts
|
|
2098
|
-
import { join, relative } from "node:path";
|
|
2099
2098
|
import picomatch from "picomatch";
|
|
2100
|
-
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2101
|
-
"**/__tests__/**",
|
|
2102
|
-
"**/__mocks__/**",
|
|
2103
|
-
"**/dist/**",
|
|
2104
|
-
"**/coverage/**",
|
|
2105
|
-
"**/*.test.{ts,tsx,js,jsx}",
|
|
2106
|
-
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2107
|
-
];
|
|
2108
|
-
function createScanFilter(root, opts) {
|
|
2109
|
-
const { include, exclude } = opts;
|
|
2110
|
-
const hasInclude = include && include.length > 0;
|
|
2111
|
-
const hasCustomExclude = exclude !== void 0;
|
|
2112
|
-
if (!hasInclude && !hasCustomExclude) return void 0;
|
|
2113
|
-
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
|
|
2114
|
-
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2115
|
-
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2116
|
-
return (absolutePath) => {
|
|
2117
|
-
const rel = relative(root, absolutePath);
|
|
2118
|
-
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2119
|
-
if (includeMatcher) return includeMatcher(rel);
|
|
2120
|
-
return true;
|
|
2121
|
-
};
|
|
2122
|
-
}
|
|
2123
2099
|
|
|
2124
2100
|
// src/build/route-types/per-module-writer.ts
|
|
2125
2101
|
import ts4 from "typescript";
|
|
@@ -2341,7 +2317,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2341
2317
|
}
|
|
2342
2318
|
return routeMap;
|
|
2343
2319
|
}
|
|
2344
|
-
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut) {
|
|
2320
|
+
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
|
|
2345
2321
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
2346
2322
|
const realPath = resolve2(filePath);
|
|
2347
2323
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
@@ -2357,7 +2333,9 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2357
2333
|
return { routes: {}, searchSchemas: {} };
|
|
2358
2334
|
}
|
|
2359
2335
|
let block;
|
|
2360
|
-
if (
|
|
2336
|
+
if (inlineBlock) {
|
|
2337
|
+
block = inlineBlock;
|
|
2338
|
+
} else if (variableName) {
|
|
2361
2339
|
const extracted = extractUrlsBlockForVariable(source, variableName);
|
|
2362
2340
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
2363
2341
|
block = extracted;
|
|
@@ -2386,7 +2364,7 @@ import {
|
|
|
2386
2364
|
readdirSync
|
|
2387
2365
|
} from "node:fs";
|
|
2388
2366
|
import {
|
|
2389
|
-
join
|
|
2367
|
+
join,
|
|
2390
2368
|
dirname as dirname2,
|
|
2391
2369
|
resolve as resolve3,
|
|
2392
2370
|
sep,
|
|
@@ -2406,7 +2384,7 @@ function countPublicRouteEntries(source) {
|
|
|
2406
2384
|
}
|
|
2407
2385
|
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2408
2386
|
function isRoutableSourceFile(name) {
|
|
2409
|
-
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.");
|
|
2387
|
+
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2410
2388
|
}
|
|
2411
2389
|
function findRouterFilesRecursive(dir, filter, results) {
|
|
2412
2390
|
let entries;
|
|
@@ -2421,9 +2399,10 @@ function findRouterFilesRecursive(dir, filter, results) {
|
|
|
2421
2399
|
const childDirs = [];
|
|
2422
2400
|
const routerFilesInDir = [];
|
|
2423
2401
|
for (const entry of entries) {
|
|
2424
|
-
const fullPath =
|
|
2402
|
+
const fullPath = join(dir, entry.name);
|
|
2425
2403
|
if (entry.isDirectory()) {
|
|
2426
|
-
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
2404
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
|
|
2405
|
+
continue;
|
|
2427
2406
|
childDirs.push(fullPath);
|
|
2428
2407
|
continue;
|
|
2429
2408
|
}
|
|
@@ -2475,7 +2454,7 @@ Router root: ${conflict.ancestor}
|
|
|
2475
2454
|
Nested router: ${conflict.nested}
|
|
2476
2455
|
Move the nested router into a sibling directory or configure it as a separate app root.`;
|
|
2477
2456
|
}
|
|
2478
|
-
function
|
|
2457
|
+
function extractUrlsFromRouter(code) {
|
|
2479
2458
|
const sourceFile = ts5.createSourceFile(
|
|
2480
2459
|
"router.tsx",
|
|
2481
2460
|
code,
|
|
@@ -2489,24 +2468,70 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2489
2468
|
const callee = node.expression;
|
|
2490
2469
|
return ts5.isIdentifier(callee) && callee.text === "createRouter";
|
|
2491
2470
|
}
|
|
2471
|
+
function isInlineBuilder(node) {
|
|
2472
|
+
return ts5.isArrowFunction(node) || ts5.isFunctionExpression(node);
|
|
2473
|
+
}
|
|
2474
|
+
function isRoutesOnCreateRouter(node) {
|
|
2475
|
+
if (!ts5.isPropertyAccessExpression(node.expression) || node.expression.name.text !== "routes")
|
|
2476
|
+
return false;
|
|
2477
|
+
let inner = node.expression.expression;
|
|
2478
|
+
while (ts5.isCallExpression(inner) && ts5.isPropertyAccessExpression(inner.expression)) {
|
|
2479
|
+
inner = inner.expression.expression;
|
|
2480
|
+
}
|
|
2481
|
+
return isCreateRouterCall(inner);
|
|
2482
|
+
}
|
|
2492
2483
|
function visit(node) {
|
|
2493
2484
|
if (result) return;
|
|
2494
|
-
if (ts5.isCallExpression(node) &&
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
}
|
|
2499
|
-
|
|
2500
|
-
result = node.arguments[0].text;
|
|
2501
|
-
return;
|
|
2485
|
+
if (ts5.isCallExpression(node) && node.arguments.length >= 1 && isRoutesOnCreateRouter(node)) {
|
|
2486
|
+
const arg = node.arguments[0];
|
|
2487
|
+
if (ts5.isIdentifier(arg)) {
|
|
2488
|
+
result = { kind: "variable", name: arg.text };
|
|
2489
|
+
} else if (isInlineBuilder(arg)) {
|
|
2490
|
+
result = { kind: "inline", block: arg.getText(sourceFile) };
|
|
2502
2491
|
}
|
|
2492
|
+
return;
|
|
2503
2493
|
}
|
|
2504
2494
|
if (isCreateRouterCall(node)) {
|
|
2505
2495
|
const callExpr = node;
|
|
2506
|
-
for (const
|
|
2496
|
+
for (const callArg of callExpr.arguments) {
|
|
2497
|
+
if (ts5.isObjectLiteralExpression(callArg)) {
|
|
2498
|
+
for (const prop of callArg.properties) {
|
|
2499
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "urls") {
|
|
2500
|
+
if (ts5.isIdentifier(prop.initializer)) {
|
|
2501
|
+
result = { kind: "variable", name: prop.initializer.text };
|
|
2502
|
+
} else if (isInlineBuilder(prop.initializer)) {
|
|
2503
|
+
result = {
|
|
2504
|
+
kind: "inline",
|
|
2505
|
+
block: prop.initializer.getText(sourceFile)
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
ts5.forEachChild(node, visit);
|
|
2515
|
+
}
|
|
2516
|
+
visit(sourceFile);
|
|
2517
|
+
return result;
|
|
2518
|
+
}
|
|
2519
|
+
function extractBasenameFromRouter(code) {
|
|
2520
|
+
const sourceFile = ts5.createSourceFile(
|
|
2521
|
+
"router.tsx",
|
|
2522
|
+
code,
|
|
2523
|
+
ts5.ScriptTarget.Latest,
|
|
2524
|
+
true,
|
|
2525
|
+
ts5.ScriptKind.TSX
|
|
2526
|
+
);
|
|
2527
|
+
let result;
|
|
2528
|
+
function visit(node) {
|
|
2529
|
+
if (result !== void 0) return;
|
|
2530
|
+
if (ts5.isCallExpression(node) && ts5.isIdentifier(node.expression) && node.expression.text === "createRouter") {
|
|
2531
|
+
for (const arg of node.arguments) {
|
|
2507
2532
|
if (ts5.isObjectLiteralExpression(arg)) {
|
|
2508
2533
|
for (const prop of arg.properties) {
|
|
2509
|
-
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "
|
|
2534
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "basename" && ts5.isStringLiteral(prop.initializer)) {
|
|
2510
2535
|
result = prop.initializer.text;
|
|
2511
2536
|
return;
|
|
2512
2537
|
}
|
|
@@ -2519,6 +2544,19 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2519
2544
|
visit(sourceFile);
|
|
2520
2545
|
return result;
|
|
2521
2546
|
}
|
|
2547
|
+
function applyBasenameToRoutes(result, basename3) {
|
|
2548
|
+
const prefixed = {};
|
|
2549
|
+
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
2550
|
+
if (pattern === "/") {
|
|
2551
|
+
prefixed[name] = basename3;
|
|
2552
|
+
} else if (basename3.endsWith("/") && pattern.startsWith("/")) {
|
|
2553
|
+
prefixed[name] = basename3 + pattern.slice(1);
|
|
2554
|
+
} else {
|
|
2555
|
+
prefixed[name] = basename3 + pattern;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
2559
|
+
}
|
|
2522
2560
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2523
2561
|
let routerSource;
|
|
2524
2562
|
try {
|
|
@@ -2526,19 +2564,40 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2526
2564
|
} catch {
|
|
2527
2565
|
return { routes: {}, searchSchemas: {} };
|
|
2528
2566
|
}
|
|
2529
|
-
const
|
|
2530
|
-
if (!
|
|
2567
|
+
const extraction = extractUrlsFromRouter(routerSource);
|
|
2568
|
+
if (!extraction) {
|
|
2531
2569
|
return { routes: {}, searchSchemas: {} };
|
|
2532
2570
|
}
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2571
|
+
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
2572
|
+
const basename3 = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
|
|
2573
|
+
let result;
|
|
2574
|
+
if (extraction.kind === "inline") {
|
|
2575
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2576
|
+
routerFilePath,
|
|
2577
|
+
void 0,
|
|
2578
|
+
void 0,
|
|
2579
|
+
void 0,
|
|
2580
|
+
extraction.block
|
|
2581
|
+
);
|
|
2582
|
+
} else {
|
|
2583
|
+
const imported = resolveImportedVariable(routerSource, extraction.name);
|
|
2584
|
+
if (imported) {
|
|
2585
|
+
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2586
|
+
if (!targetFile) {
|
|
2587
|
+
return { routes: {}, searchSchemas: {} };
|
|
2588
|
+
}
|
|
2589
|
+
result = buildCombinedRouteMapWithSearch(
|
|
2590
|
+
targetFile,
|
|
2591
|
+
imported.exportedName
|
|
2592
|
+
);
|
|
2593
|
+
} else {
|
|
2594
|
+
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
2538
2595
|
}
|
|
2539
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2540
2596
|
}
|
|
2541
|
-
|
|
2597
|
+
if (basename3) {
|
|
2598
|
+
result = applyBasenameToRoutes(result, basename3);
|
|
2599
|
+
}
|
|
2600
|
+
return result;
|
|
2542
2601
|
}
|
|
2543
2602
|
function findRouterFiles(root, filter) {
|
|
2544
2603
|
const result = [];
|
|
@@ -2547,7 +2606,7 @@ function findRouterFiles(root, filter) {
|
|
|
2547
2606
|
}
|
|
2548
2607
|
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
2549
2608
|
try {
|
|
2550
|
-
const oldCombinedPath =
|
|
2609
|
+
const oldCombinedPath = join(root, "src", "named-routes.gen.ts");
|
|
2551
2610
|
if (existsSync3(oldCombinedPath)) {
|
|
2552
2611
|
unlinkSync(oldCombinedPath);
|
|
2553
2612
|
console.log(
|
|
@@ -2563,31 +2622,21 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2563
2622
|
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
2564
2623
|
}
|
|
2565
2624
|
for (const routerFilePath of routerFilePaths) {
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
routerSource
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
2576
|
-
if (imported) {
|
|
2577
|
-
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2578
|
-
if (!targetFile) continue;
|
|
2579
|
-
result = buildCombinedRouteMapWithSearch(
|
|
2580
|
-
targetFile,
|
|
2581
|
-
imported.exportedName
|
|
2582
|
-
);
|
|
2583
|
-
} else {
|
|
2584
|
-
result = buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
2625
|
+
const result = buildCombinedRouteMapForRouterFile(routerFilePath);
|
|
2626
|
+
if (Object.keys(result.routes).length === 0 && Object.keys(result.searchSchemas).length === 0) {
|
|
2627
|
+
let routerSource;
|
|
2628
|
+
try {
|
|
2629
|
+
routerSource = readFileSync2(routerFilePath, "utf-8");
|
|
2630
|
+
} catch {
|
|
2631
|
+
continue;
|
|
2632
|
+
}
|
|
2633
|
+
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
2585
2634
|
}
|
|
2586
2635
|
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2587
2636
|
/\.(tsx?|jsx?)$/,
|
|
2588
2637
|
""
|
|
2589
2638
|
);
|
|
2590
|
-
const outPath =
|
|
2639
|
+
const outPath = join(
|
|
2591
2640
|
dirname2(routerFilePath),
|
|
2592
2641
|
`${routerBasename}.named-routes.gen.ts`
|
|
2593
2642
|
);
|
|
@@ -2717,8 +2766,9 @@ function createVersionPlugin() {
|
|
|
2717
2766
|
let isDev = false;
|
|
2718
2767
|
let server = null;
|
|
2719
2768
|
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
2769
|
+
let versionCounter = 0;
|
|
2720
2770
|
const bumpVersion = (reason) => {
|
|
2721
|
-
currentVersion = Date.now().toString(16);
|
|
2771
|
+
currentVersion = Date.now().toString(16) + String(++versionCounter);
|
|
2722
2772
|
console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
|
|
2723
2773
|
const rscEnv = server?.environments?.rsc;
|
|
2724
2774
|
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
@@ -2774,6 +2824,9 @@ function createVersionPlugin() {
|
|
|
2774
2824
|
if (!isDev) return;
|
|
2775
2825
|
const isRscModule = this.environment?.name === "rsc";
|
|
2776
2826
|
if (!isRscModule) return;
|
|
2827
|
+
if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2777
2830
|
if (isCodeModule(ctx.file)) {
|
|
2778
2831
|
const filePath = normalizeModuleId(ctx.file);
|
|
2779
2832
|
const previousSignature = clientModuleSignatures.get(filePath);
|
|
@@ -2803,6 +2856,68 @@ function createVersionPlugin() {
|
|
|
2803
2856
|
|
|
2804
2857
|
// src/vite/utils/shared-utils.ts
|
|
2805
2858
|
import * as Vite from "vite";
|
|
2859
|
+
|
|
2860
|
+
// src/vite/plugins/performance-tracks.ts
|
|
2861
|
+
import { readFile } from "node:fs/promises";
|
|
2862
|
+
var RSDW_PATCH_RE = /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
|
|
2863
|
+
function buildPatchReplacement(match, debugInfoVar) {
|
|
2864
|
+
return `${match}
|
|
2865
|
+
if (${debugInfoVar} && 0 === ${debugInfoVar}.length && "fulfilled" === root.status) {
|
|
2866
|
+
var _resolved = "function" === typeof resolveLazy ? resolveLazy(root.value) : root.value;
|
|
2867
|
+
if ("object" === typeof _resolved && null !== _resolved && isArrayImpl(_resolved._debugInfo)) {
|
|
2868
|
+
${debugInfoVar} = _resolved._debugInfo;
|
|
2869
|
+
}
|
|
2870
|
+
}`;
|
|
2871
|
+
}
|
|
2872
|
+
function patchRsdwClientDebugInfoRecovery(code) {
|
|
2873
|
+
const match = code.match(RSDW_PATCH_RE);
|
|
2874
|
+
if (!match) {
|
|
2875
|
+
return { code, debugInfoVar: null };
|
|
2876
|
+
}
|
|
2877
|
+
return {
|
|
2878
|
+
code: code.replace(match[1], buildPatchReplacement(match[1], match[2])),
|
|
2879
|
+
debugInfoVar: match[2]
|
|
2880
|
+
};
|
|
2881
|
+
}
|
|
2882
|
+
function performanceTracksOptimizeDepsPlugin() {
|
|
2883
|
+
return {
|
|
2884
|
+
name: "@rangojs/router:performance-tracks-optimize-deps",
|
|
2885
|
+
setup(build) {
|
|
2886
|
+
build.onLoad(
|
|
2887
|
+
{
|
|
2888
|
+
filter: /react-server-dom-webpack-client\.browser\.(development|production)\.js$/
|
|
2889
|
+
},
|
|
2890
|
+
async (args) => {
|
|
2891
|
+
const code = await readFile(args.path, "utf8");
|
|
2892
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
2893
|
+
return {
|
|
2894
|
+
contents: patched.code,
|
|
2895
|
+
loader: "js"
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
function performanceTracksPlugin() {
|
|
2903
|
+
return {
|
|
2904
|
+
name: "@rangojs/router:performance-tracks",
|
|
2905
|
+
transform(code, id) {
|
|
2906
|
+
if (!id.includes("react-server-dom") || !id.includes("client")) return;
|
|
2907
|
+
const patched = patchRsdwClientDebugInfoRecovery(code);
|
|
2908
|
+
if (!patched.debugInfoVar) return;
|
|
2909
|
+
if (process.env.INTERNAL_RANGO_DEBUG)
|
|
2910
|
+
console.log(
|
|
2911
|
+
"[perf-tracks] patched RSDW client (var:",
|
|
2912
|
+
patched.debugInfoVar,
|
|
2913
|
+
")"
|
|
2914
|
+
);
|
|
2915
|
+
return patched.code;
|
|
2916
|
+
}
|
|
2917
|
+
};
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
// src/vite/utils/shared-utils.ts
|
|
2806
2921
|
var versionEsbuildPlugin = {
|
|
2807
2922
|
name: "@rangojs/router-version",
|
|
2808
2923
|
setup(build) {
|
|
@@ -2820,7 +2935,7 @@ var versionEsbuildPlugin = {
|
|
|
2820
2935
|
}
|
|
2821
2936
|
};
|
|
2822
2937
|
var sharedEsbuildOptions = {
|
|
2823
|
-
plugins: [versionEsbuildPlugin]
|
|
2938
|
+
plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
2824
2939
|
};
|
|
2825
2940
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
2826
2941
|
const virtualModules = {};
|
|
@@ -2903,11 +3018,11 @@ ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2
|
|
|
2903
3018
|
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
2904
3019
|
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
2905
3020
|
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2551 \u2551 \u2551 \u2566\u2550\u2557\u2554\u2550\u2557\u2554\u2557\u2554\u2554\u2550\u2557\u2554\u2550\u2557${reset}${dim} \u2727 \u2726${reset}
|
|
2906
|
-
${dim}
|
|
3021
|
+
${dim} ${reset}${bold}\u2551\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
|
|
2907
3022
|
${dim} ${reset}${bold}\u2551\u255A\u2550\u255D \u2554\u2550\u2550\u2550\u255D \u2569\u255A\u2550\u2569 \u2569\u255D\u255A\u255D\u255A\u2550\u255D\u255A\u2550\u255D${reset}${dim} \u2726 . *${reset}
|
|
2908
3023
|
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
2909
|
-
${dim} * ${reset}${bold}\u2551 \
|
|
2910
|
-
${bold}\u2550\u2550\u2550\
|
|
3024
|
+
${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
|
|
3025
|
+
${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
|
|
2911
3026
|
|
|
2912
3027
|
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
2913
3028
|
`;
|
|
@@ -3026,6 +3141,8 @@ function createCjsToEsmPlugin() {
|
|
|
3026
3141
|
import { createServer as createViteServer } from "vite";
|
|
3027
3142
|
import { resolve as resolve8 } from "node:path";
|
|
3028
3143
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3144
|
+
import { createRequire } from "node:module";
|
|
3145
|
+
import { pathToFileURL } from "node:url";
|
|
3029
3146
|
|
|
3030
3147
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
3031
3148
|
function createVirtualStubPlugin() {
|
|
@@ -3052,7 +3169,7 @@ function createVirtualStubPlugin() {
|
|
|
3052
3169
|
}
|
|
3053
3170
|
|
|
3054
3171
|
// src/vite/plugins/client-ref-hashing.ts
|
|
3055
|
-
import { relative
|
|
3172
|
+
import { relative } from "node:path";
|
|
3056
3173
|
import { createHash as createHash2 } from "node:crypto";
|
|
3057
3174
|
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
3058
3175
|
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
@@ -3065,10 +3182,10 @@ function computeProductionHash(projectRoot, refKey) {
|
|
|
3065
3182
|
const absPath = decodeURIComponent(
|
|
3066
3183
|
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
3067
3184
|
);
|
|
3068
|
-
toHash =
|
|
3185
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3069
3186
|
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
3070
3187
|
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
3071
|
-
toHash =
|
|
3188
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
3072
3189
|
} else if (refKey.startsWith("/")) {
|
|
3073
3190
|
toHash = refKey.slice(1);
|
|
3074
3191
|
} else {
|
|
@@ -3209,8 +3326,8 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3209
3326
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
3210
3327
|
prerenderManifestEntries: null,
|
|
3211
3328
|
staticManifestEntries: null,
|
|
3212
|
-
|
|
3213
|
-
|
|
3329
|
+
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3330
|
+
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3214
3331
|
rscEntryFileName: null,
|
|
3215
3332
|
resolvedPrerenderModules: void 0,
|
|
3216
3333
|
resolvedStaticModules: void 0,
|
|
@@ -3293,8 +3410,17 @@ function jsonParseExpression(value) {
|
|
|
3293
3410
|
}
|
|
3294
3411
|
|
|
3295
3412
|
// src/context-var.ts
|
|
3413
|
+
var NON_CACHEABLE_KEYS = /* @__PURE__ */ Symbol.for(
|
|
3414
|
+
"rango:non-cacheable-keys"
|
|
3415
|
+
);
|
|
3416
|
+
function getNonCacheableKeys(variables) {
|
|
3417
|
+
if (!variables[NON_CACHEABLE_KEYS]) {
|
|
3418
|
+
variables[NON_CACHEABLE_KEYS] = /* @__PURE__ */ new Set();
|
|
3419
|
+
}
|
|
3420
|
+
return variables[NON_CACHEABLE_KEYS];
|
|
3421
|
+
}
|
|
3296
3422
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3297
|
-
function contextSet(variables, keyOrVar, value) {
|
|
3423
|
+
function contextSet(variables, keyOrVar, value, options) {
|
|
3298
3424
|
if (typeof keyOrVar === "string") {
|
|
3299
3425
|
if (FORBIDDEN_KEYS.has(keyOrVar)) {
|
|
3300
3426
|
throw new Error(
|
|
@@ -3302,8 +3428,14 @@ function contextSet(variables, keyOrVar, value) {
|
|
|
3302
3428
|
);
|
|
3303
3429
|
}
|
|
3304
3430
|
variables[keyOrVar] = value;
|
|
3431
|
+
if (options?.cache === false) {
|
|
3432
|
+
getNonCacheableKeys(variables).add(keyOrVar);
|
|
3433
|
+
}
|
|
3305
3434
|
} else {
|
|
3306
3435
|
variables[keyOrVar.key] = value;
|
|
3436
|
+
if (options?.cache === false) {
|
|
3437
|
+
getNonCacheableKeys(variables).add(keyOrVar.key);
|
|
3438
|
+
}
|
|
3307
3439
|
}
|
|
3308
3440
|
}
|
|
3309
3441
|
|
|
@@ -3326,6 +3458,7 @@ function encodePathParam(value) {
|
|
|
3326
3458
|
}
|
|
3327
3459
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3328
3460
|
let result = pattern;
|
|
3461
|
+
let hadOmittedOptional = false;
|
|
3329
3462
|
for (const [key, value] of Object.entries(params)) {
|
|
3330
3463
|
const escaped = escapeRegExp2(key);
|
|
3331
3464
|
result = result.replace(
|
|
@@ -3334,6 +3467,15 @@ function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
|
3334
3467
|
);
|
|
3335
3468
|
result = result.replace(`*${key}`, encode(value));
|
|
3336
3469
|
}
|
|
3470
|
+
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
3471
|
+
hadOmittedOptional = true;
|
|
3472
|
+
return "";
|
|
3473
|
+
});
|
|
3474
|
+
if (hadOmittedOptional) {
|
|
3475
|
+
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
3476
|
+
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3477
|
+
if (hadTrailingSlash && !result.endsWith("/")) result += "/";
|
|
3478
|
+
}
|
|
3337
3479
|
return result;
|
|
3338
3480
|
}
|
|
3339
3481
|
async function runWithConcurrency(items, concurrency, fn) {
|
|
@@ -3445,11 +3587,12 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3445
3587
|
for (const { manifest } of allManifests) {
|
|
3446
3588
|
if (!manifest.prerenderRoutes) continue;
|
|
3447
3589
|
const defs = manifest._prerenderDefs || {};
|
|
3590
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
3448
3591
|
for (const routeName of manifest.prerenderRoutes) {
|
|
3449
3592
|
const pattern = manifest.routeManifest[routeName];
|
|
3450
3593
|
if (!pattern) continue;
|
|
3451
3594
|
const def = defs[routeName];
|
|
3452
|
-
const isPassthroughRoute =
|
|
3595
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
3453
3596
|
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
3454
3597
|
if (!hasDynamic) {
|
|
3455
3598
|
entries.push({
|
|
@@ -3462,12 +3605,20 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3462
3605
|
if (def?.getParams) {
|
|
3463
3606
|
try {
|
|
3464
3607
|
const buildVars = {};
|
|
3608
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
3465
3609
|
const getParamsCtx = {
|
|
3466
3610
|
build: true,
|
|
3611
|
+
dev: !state.isBuildMode,
|
|
3467
3612
|
set: ((keyOrVar, value) => {
|
|
3468
3613
|
contextSet(buildVars, keyOrVar, value);
|
|
3469
3614
|
}),
|
|
3470
|
-
reverse: getParamsReverse
|
|
3615
|
+
reverse: getParamsReverse,
|
|
3616
|
+
get env() {
|
|
3617
|
+
if (buildEnv !== void 0) return buildEnv;
|
|
3618
|
+
throw new Error(
|
|
3619
|
+
"[rsc-router] ctx.env is not available during build-time getParams(). Configure buildEnv in your rango() plugin options to enable build-time env access."
|
|
3620
|
+
);
|
|
3621
|
+
}
|
|
3471
3622
|
};
|
|
3472
3623
|
const paramsList = await def.getParams(getParamsCtx);
|
|
3473
3624
|
const concurrency = def.options?.concurrency ?? 1;
|
|
@@ -3546,7 +3697,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3546
3697
|
entry.urlPath,
|
|
3547
3698
|
{},
|
|
3548
3699
|
entry.buildVars,
|
|
3549
|
-
entry.isPassthroughRoute
|
|
3700
|
+
entry.isPassthroughRoute,
|
|
3701
|
+
state.resolvedBuildEnv
|
|
3550
3702
|
);
|
|
3551
3703
|
if (!result) continue;
|
|
3552
3704
|
if (result.passthrough) {
|
|
@@ -3670,7 +3822,9 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3670
3822
|
const result = await routerInstance.renderStaticSegment(
|
|
3671
3823
|
def.handler,
|
|
3672
3824
|
def.$$id,
|
|
3673
|
-
def.$$routePrefix
|
|
3825
|
+
def.$$routePrefix,
|
|
3826
|
+
state.resolvedBuildEnv,
|
|
3827
|
+
!state.isBuildMode
|
|
3674
3828
|
);
|
|
3675
3829
|
if (result) {
|
|
3676
3830
|
const hasHandles = Object.keys(result.handles).length > 0;
|
|
@@ -3795,7 +3949,11 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3795
3949
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
3796
3950
|
continue;
|
|
3797
3951
|
}
|
|
3798
|
-
const manifest = generateManifestFull(
|
|
3952
|
+
const manifest = generateManifestFull(
|
|
3953
|
+
router.urlpatterns,
|
|
3954
|
+
routerMountIndex,
|
|
3955
|
+
router.__basename ? { urlPrefix: router.__basename } : void 0
|
|
3956
|
+
);
|
|
3799
3957
|
routerMountIndex++;
|
|
3800
3958
|
allManifests.push({ id, manifest });
|
|
3801
3959
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
@@ -3937,7 +4095,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3937
4095
|
}
|
|
3938
4096
|
|
|
3939
4097
|
// src/vite/discovery/route-types-writer.ts
|
|
3940
|
-
import { dirname as dirname3, basename, join as
|
|
4098
|
+
import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
|
|
3941
4099
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
3942
4100
|
function filterUserNamedRoutes(manifest) {
|
|
3943
4101
|
const filtered = {};
|
|
@@ -3958,7 +4116,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3958
4116
|
/\.(tsx?|jsx?)$/,
|
|
3959
4117
|
""
|
|
3960
4118
|
);
|
|
3961
|
-
const outPath =
|
|
4119
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3962
4120
|
try {
|
|
3963
4121
|
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
3964
4122
|
} catch {
|
|
@@ -3971,7 +4129,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3971
4129
|
/\.(tsx?|jsx?)$/,
|
|
3972
4130
|
""
|
|
3973
4131
|
);
|
|
3974
|
-
const outPath =
|
|
4132
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3975
4133
|
if (!existsSync5(outPath)) continue;
|
|
3976
4134
|
try {
|
|
3977
4135
|
const content = readFileSync4(outPath, "utf-8");
|
|
@@ -3988,7 +4146,7 @@ function writeRouteTypesFiles(state) {
|
|
|
3988
4146
|
const entryDir = dirname3(
|
|
3989
4147
|
resolve6(state.projectRoot, state.resolvedEntryPath)
|
|
3990
4148
|
);
|
|
3991
|
-
const oldCombinedPath =
|
|
4149
|
+
const oldCombinedPath = join2(entryDir, "named-routes.gen.ts");
|
|
3992
4150
|
if (existsSync5(oldCombinedPath)) {
|
|
3993
4151
|
unlinkSync2(oldCombinedPath);
|
|
3994
4152
|
console.log(
|
|
@@ -4013,7 +4171,7 @@ Set an explicit \`id\` on createRouter() or check the call site.`
|
|
|
4013
4171
|
}
|
|
4014
4172
|
const routerDir = dirname3(sourceFile);
|
|
4015
4173
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4016
|
-
const outPath =
|
|
4174
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4017
4175
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
4018
4176
|
let effectiveSearchSchemas = routeSearchSchemas;
|
|
4019
4177
|
if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
|
|
@@ -4078,7 +4236,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4078
4236
|
}
|
|
4079
4237
|
const routerDir = dirname3(sourceFile);
|
|
4080
4238
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
4081
|
-
const outPath =
|
|
4239
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4082
4240
|
const source = generateRouteTypesSource(
|
|
4083
4241
|
mergedRoutes,
|
|
4084
4242
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
@@ -4092,7 +4250,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
4092
4250
|
}
|
|
4093
4251
|
|
|
4094
4252
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
4095
|
-
import { dirname as dirname4, basename as basename2, join as
|
|
4253
|
+
import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
|
|
4096
4254
|
function generateRoutesManifestModule(state) {
|
|
4097
4255
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
4098
4256
|
if (hasManifest) {
|
|
@@ -4107,7 +4265,7 @@ function generateRoutesManifestModule(state) {
|
|
|
4107
4265
|
/\.(tsx?|jsx?)$/,
|
|
4108
4266
|
""
|
|
4109
4267
|
);
|
|
4110
|
-
const genPath =
|
|
4268
|
+
const genPath = join3(
|
|
4111
4269
|
routerDir,
|
|
4112
4270
|
`${routerBasename}.named-routes.gen.js`
|
|
4113
4271
|
).replaceAll("\\", "/");
|
|
@@ -4204,7 +4362,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4204
4362
|
/\.(tsx?|jsx?)$/,
|
|
4205
4363
|
""
|
|
4206
4364
|
);
|
|
4207
|
-
const genPath =
|
|
4365
|
+
const genPath = join3(
|
|
4208
4366
|
routerDir,
|
|
4209
4367
|
`${routerBasename}.named-routes.gen.js`
|
|
4210
4368
|
).replaceAll("\\", "/");
|
|
@@ -4244,48 +4402,45 @@ function postprocessBundle(state) {
|
|
|
4244
4402
|
);
|
|
4245
4403
|
const evictionTargets = [
|
|
4246
4404
|
{
|
|
4247
|
-
|
|
4405
|
+
infos: state.handlerChunkInfoMap.values(),
|
|
4248
4406
|
fnName: "Prerender",
|
|
4249
4407
|
brand: "prerenderHandler",
|
|
4250
4408
|
label: "handler code from RSC bundle"
|
|
4251
4409
|
},
|
|
4252
4410
|
{
|
|
4253
|
-
|
|
4411
|
+
infos: state.staticHandlerChunkInfoMap.values(),
|
|
4254
4412
|
fnName: "Static",
|
|
4255
4413
|
brand: "staticHandler",
|
|
4256
4414
|
label: "static handler code"
|
|
4257
4415
|
}
|
|
4258
4416
|
];
|
|
4259
4417
|
for (const target of evictionTargets) {
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4418
|
+
for (const info of target.infos) {
|
|
4419
|
+
const chunkPath = resolve7(state.projectRoot, "dist/rsc", info.fileName);
|
|
4420
|
+
try {
|
|
4421
|
+
const code = readFileSync5(chunkPath, "utf-8");
|
|
4422
|
+
const result = evictHandlerCode(
|
|
4423
|
+
code,
|
|
4424
|
+
info.exports,
|
|
4425
|
+
target.fnName,
|
|
4426
|
+
target.brand
|
|
4427
|
+
);
|
|
4428
|
+
if (result) {
|
|
4429
|
+
writeFileSync4(chunkPath, result.code);
|
|
4430
|
+
const savedKB = (result.savedBytes / 1024).toFixed(1);
|
|
4431
|
+
console.log(
|
|
4432
|
+
`[rsc-router] Evicted ${target.label} (${savedKB} KB saved): ${info.fileName}`
|
|
4433
|
+
);
|
|
4434
|
+
}
|
|
4435
|
+
} catch (replaceErr) {
|
|
4436
|
+
console.warn(
|
|
4437
|
+
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4279
4438
|
);
|
|
4280
4439
|
}
|
|
4281
|
-
} catch (replaceErr) {
|
|
4282
|
-
console.warn(
|
|
4283
|
-
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4284
|
-
);
|
|
4285
4440
|
}
|
|
4286
4441
|
}
|
|
4287
|
-
state.
|
|
4288
|
-
state.
|
|
4442
|
+
state.handlerChunkInfoMap.clear();
|
|
4443
|
+
state.staticHandlerChunkInfoMap.clear();
|
|
4289
4444
|
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
4290
4445
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4291
4446
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
@@ -4328,7 +4483,7 @@ function postprocessBundle(state) {
|
|
|
4328
4483
|
}
|
|
4329
4484
|
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
4330
4485
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4331
|
-
if (!rscCode.includes("
|
|
4486
|
+
if (!rscCode.includes("__static-manifest.js")) {
|
|
4332
4487
|
try {
|
|
4333
4488
|
const manifestEntries = [];
|
|
4334
4489
|
let totalBytes = copyStagedBuildAssets(
|
|
@@ -4397,8 +4552,67 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4397
4552
|
]
|
|
4398
4553
|
});
|
|
4399
4554
|
}
|
|
4555
|
+
async function resolveBuildEnv(option, factoryCtx) {
|
|
4556
|
+
if (!option) return null;
|
|
4557
|
+
if (option === "auto") {
|
|
4558
|
+
if (factoryCtx.preset !== "cloudflare") {
|
|
4559
|
+
throw new Error(
|
|
4560
|
+
'[rsc-router] buildEnv: "auto" is only supported with preset: "cloudflare". Use a factory function or plain object for other presets.'
|
|
4561
|
+
);
|
|
4562
|
+
}
|
|
4563
|
+
try {
|
|
4564
|
+
const userRequire = createRequire(
|
|
4565
|
+
resolve8(factoryCtx.root, "package.json")
|
|
4566
|
+
);
|
|
4567
|
+
const wranglerPath = userRequire.resolve("wrangler");
|
|
4568
|
+
const { getPlatformProxy } = await import(pathToFileURL(wranglerPath).href);
|
|
4569
|
+
const proxy = await getPlatformProxy();
|
|
4570
|
+
return {
|
|
4571
|
+
env: proxy.env,
|
|
4572
|
+
dispose: proxy.dispose
|
|
4573
|
+
};
|
|
4574
|
+
} catch (err) {
|
|
4575
|
+
throw new Error(
|
|
4576
|
+
`[rsc-router] buildEnv: "auto" requires wrangler to be installed.
|
|
4577
|
+
Install it with: pnpm add -D wrangler
|
|
4578
|
+
${err.message}`
|
|
4579
|
+
);
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
if (typeof option === "function") {
|
|
4583
|
+
return await option(factoryCtx);
|
|
4584
|
+
}
|
|
4585
|
+
return { env: option };
|
|
4586
|
+
}
|
|
4587
|
+
async function acquireBuildEnv(s, command, mode) {
|
|
4588
|
+
const option = s.opts?.buildEnv;
|
|
4589
|
+
if (!option) return false;
|
|
4590
|
+
const result = await resolveBuildEnv(option, {
|
|
4591
|
+
root: s.projectRoot,
|
|
4592
|
+
mode,
|
|
4593
|
+
command,
|
|
4594
|
+
preset: s.opts?.preset ?? "node"
|
|
4595
|
+
});
|
|
4596
|
+
if (!result) return false;
|
|
4597
|
+
s.resolvedBuildEnv = result.env;
|
|
4598
|
+
s.buildEnvDispose = result.dispose ?? null;
|
|
4599
|
+
return true;
|
|
4600
|
+
}
|
|
4601
|
+
async function releaseBuildEnv(s) {
|
|
4602
|
+
if (s.buildEnvDispose) {
|
|
4603
|
+
try {
|
|
4604
|
+
await s.buildEnvDispose();
|
|
4605
|
+
} catch (err) {
|
|
4606
|
+
console.warn(`[rsc-router] buildEnv dispose failed: ${err.message}`);
|
|
4607
|
+
}
|
|
4608
|
+
s.buildEnvDispose = null;
|
|
4609
|
+
}
|
|
4610
|
+
s.resolvedBuildEnv = void 0;
|
|
4611
|
+
}
|
|
4400
4612
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4401
4613
|
const s = createDiscoveryState(entryPath, opts);
|
|
4614
|
+
let viteCommand = "build";
|
|
4615
|
+
let viteMode = "production";
|
|
4402
4616
|
return {
|
|
4403
4617
|
name: "@rangojs/router:discovery",
|
|
4404
4618
|
config() {
|
|
@@ -4407,31 +4621,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4407
4621
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
|
|
4408
4622
|
}
|
|
4409
4623
|
};
|
|
4410
|
-
if (opts?.enableBuildPrerender) {
|
|
4411
|
-
config.environments = {
|
|
4412
|
-
rsc: {
|
|
4413
|
-
build: {
|
|
4414
|
-
rollupOptions: {
|
|
4415
|
-
output: {
|
|
4416
|
-
manualChunks(id) {
|
|
4417
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
4418
|
-
return "__prerender-handlers";
|
|
4419
|
-
}
|
|
4420
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
4421
|
-
return "__static-handlers";
|
|
4422
|
-
}
|
|
4423
|
-
}
|
|
4424
|
-
}
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
};
|
|
4429
|
-
}
|
|
4430
4624
|
return config;
|
|
4431
4625
|
},
|
|
4432
4626
|
configResolved(config) {
|
|
4433
4627
|
s.projectRoot = config.root;
|
|
4434
4628
|
s.isBuildMode = config.command === "build";
|
|
4629
|
+
viteCommand = config.command;
|
|
4630
|
+
viteMode = config.mode;
|
|
4435
4631
|
s.userResolveAlias = config.resolve.alias;
|
|
4436
4632
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4437
4633
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
@@ -4445,12 +4641,6 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4445
4641
|
s.resolvedEntryPath = entries[0];
|
|
4446
4642
|
}
|
|
4447
4643
|
}
|
|
4448
|
-
if (opts?.include || opts?.exclude) {
|
|
4449
|
-
s.scanFilter = createScanFilter(s.projectRoot, {
|
|
4450
|
-
include: opts.include,
|
|
4451
|
-
exclude: opts.exclude
|
|
4452
|
-
});
|
|
4453
|
-
}
|
|
4454
4644
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
4455
4645
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
4456
4646
|
writeCombinedRouteTypesWithTracking(s, { preserveIfLarger: true });
|
|
@@ -4482,6 +4672,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4482
4672
|
});
|
|
4483
4673
|
prerenderTempServer = null;
|
|
4484
4674
|
}
|
|
4675
|
+
releaseBuildEnv(s).catch(() => {
|
|
4676
|
+
});
|
|
4485
4677
|
});
|
|
4486
4678
|
async function getOrCreateTempServer() {
|
|
4487
4679
|
if (prerenderNodeRegistry) {
|
|
@@ -4512,6 +4704,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4512
4704
|
if (!rscEnv?.runner) {
|
|
4513
4705
|
s.devServerOrigin = getDevServerOrigin();
|
|
4514
4706
|
try {
|
|
4707
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4515
4708
|
const tempRscEnv = await getOrCreateTempServer();
|
|
4516
4709
|
if (tempRscEnv) {
|
|
4517
4710
|
await discoverRouters(s, tempRscEnv);
|
|
@@ -4527,6 +4720,7 @@ ${err.stack}`
|
|
|
4527
4720
|
return;
|
|
4528
4721
|
}
|
|
4529
4722
|
try {
|
|
4723
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4530
4724
|
const serverMod = await rscEnv.runner.import(
|
|
4531
4725
|
"@rangojs/router/server"
|
|
4532
4726
|
);
|
|
@@ -4613,7 +4807,10 @@ ${err.stack}`
|
|
|
4613
4807
|
pathname,
|
|
4614
4808
|
{},
|
|
4615
4809
|
void 0,
|
|
4616
|
-
wantPassthrough
|
|
4810
|
+
wantPassthrough,
|
|
4811
|
+
s.resolvedBuildEnv,
|
|
4812
|
+
true
|
|
4813
|
+
// devMode: check getParams for passthrough routes
|
|
4617
4814
|
);
|
|
4618
4815
|
if (!result) continue;
|
|
4619
4816
|
if (result.passthrough) continue;
|
|
@@ -4749,6 +4946,7 @@ ${err.stack}`
|
|
|
4749
4946
|
resetStagedBuildAssets(s.projectRoot);
|
|
4750
4947
|
s.prerenderManifestEntries = null;
|
|
4751
4948
|
s.staticManifestEntries = null;
|
|
4949
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4752
4950
|
let tempServer = null;
|
|
4753
4951
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4754
4952
|
try {
|
|
@@ -4788,6 +4986,7 @@ ${details}`
|
|
|
4788
4986
|
if (tempServer) {
|
|
4789
4987
|
await tempServer.close();
|
|
4790
4988
|
}
|
|
4989
|
+
await releaseBuildEnv(s);
|
|
4791
4990
|
}
|
|
4792
4991
|
},
|
|
4793
4992
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -4830,20 +5029,30 @@ ${details}`
|
|
|
4830
5029
|
}
|
|
4831
5030
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
4832
5031
|
return;
|
|
5032
|
+
s.handlerChunkInfoMap.clear();
|
|
5033
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
4833
5034
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
4834
5035
|
if (chunk.type !== "chunk") continue;
|
|
4835
|
-
if (
|
|
5036
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
4836
5037
|
const handlers = extractHandlerExportsFromChunk(
|
|
4837
5038
|
chunk.code,
|
|
4838
5039
|
s.resolvedPrerenderModules,
|
|
4839
5040
|
"Prerender",
|
|
4840
|
-
|
|
5041
|
+
false
|
|
4841
5042
|
);
|
|
4842
5043
|
if (handlers.length > 0) {
|
|
4843
|
-
|
|
5044
|
+
const existing = s.handlerChunkInfoMap.get(fileName);
|
|
5045
|
+
if (existing) {
|
|
5046
|
+
existing.exports.push(...handlers);
|
|
5047
|
+
} else {
|
|
5048
|
+
s.handlerChunkInfoMap.set(fileName, {
|
|
5049
|
+
fileName,
|
|
5050
|
+
exports: handlers
|
|
5051
|
+
});
|
|
5052
|
+
}
|
|
4844
5053
|
}
|
|
4845
5054
|
}
|
|
4846
|
-
if (
|
|
5055
|
+
if (s.resolvedStaticModules?.size) {
|
|
4847
5056
|
const handlers = extractHandlerExportsFromChunk(
|
|
4848
5057
|
chunk.code,
|
|
4849
5058
|
s.resolvedStaticModules,
|
|
@@ -4851,7 +5060,15 @@ ${details}`
|
|
|
4851
5060
|
false
|
|
4852
5061
|
);
|
|
4853
5062
|
if (handlers.length > 0) {
|
|
4854
|
-
|
|
5063
|
+
const existing = s.staticHandlerChunkInfoMap.get(fileName);
|
|
5064
|
+
if (existing) {
|
|
5065
|
+
existing.exports.push(...handlers);
|
|
5066
|
+
} else {
|
|
5067
|
+
s.staticHandlerChunkInfoMap.set(fileName, {
|
|
5068
|
+
fileName,
|
|
5069
|
+
exports: handlers
|
|
5070
|
+
});
|
|
5071
|
+
}
|
|
4855
5072
|
}
|
|
4856
5073
|
}
|
|
4857
5074
|
}
|
|
@@ -4878,8 +5095,16 @@ async function rango(options) {
|
|
|
4878
5095
|
const showBanner = resolvedOptions.banner ?? true;
|
|
4879
5096
|
const plugins = [];
|
|
4880
5097
|
const rangoAliases = getPackageAliases();
|
|
4881
|
-
const excludeDeps =
|
|
4882
|
-
|
|
5098
|
+
const excludeDeps = [
|
|
5099
|
+
...getExcludeDeps(),
|
|
5100
|
+
// The public browser entry re-exports the RSDW browser client.
|
|
5101
|
+
// Excluding both keeps Vite from freezing the unpatched bundle into
|
|
5102
|
+
// .vite/deps before our source transforms run.
|
|
5103
|
+
"@vitejs/plugin-rsc/browser",
|
|
5104
|
+
// Keep the browser RSDW client out of Vite's dep optimizer so our
|
|
5105
|
+
// cjs-to-esm transform can patch the real file.
|
|
5106
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.browser"
|
|
5107
|
+
];
|
|
4883
5108
|
const routerRef = { path: void 0 };
|
|
4884
5109
|
const prerenderEnabled = true;
|
|
4885
5110
|
if (preset === "cloudflare") {
|
|
@@ -4975,6 +5200,7 @@ async function rango(options) {
|
|
|
4975
5200
|
}
|
|
4976
5201
|
});
|
|
4977
5202
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
5203
|
+
plugins.push(performanceTracksPlugin());
|
|
4978
5204
|
plugins.push(
|
|
4979
5205
|
rsc({
|
|
4980
5206
|
entries: finalEntries,
|
|
@@ -4983,153 +5209,122 @@ async function rango(options) {
|
|
|
4983
5209
|
);
|
|
4984
5210
|
plugins.push(clientRefDedup());
|
|
4985
5211
|
} else {
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
const
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
5002
|
-
} else if (candidates.length > 1) {
|
|
5003
|
-
const list = candidates.map(
|
|
5004
|
-
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5005
|
-
).join("\n");
|
|
5006
|
-
throw new Error(
|
|
5007
|
-
`[rsc-router] Multiple routers found. Specify \`router\` to choose one:
|
|
5008
|
-
${list}`
|
|
5009
|
-
);
|
|
5010
|
-
}
|
|
5212
|
+
plugins.push({
|
|
5213
|
+
name: "@rangojs/router:auto-discover",
|
|
5214
|
+
config(userConfig) {
|
|
5215
|
+
if (routerRef.path) return;
|
|
5216
|
+
const root = userConfig.root ? resolve9(process.cwd(), userConfig.root) : process.cwd();
|
|
5217
|
+
const candidates = findRouterFiles(root);
|
|
5218
|
+
if (candidates.length === 1) {
|
|
5219
|
+
const abs = candidates[0];
|
|
5220
|
+
routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
5221
|
+
} else if (candidates.length > 1) {
|
|
5222
|
+
const list = candidates.map(
|
|
5223
|
+
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
5224
|
+
).join("\n");
|
|
5225
|
+
throw new Error(`[rsc-router] Multiple routers found:
|
|
5226
|
+
${list}`);
|
|
5011
5227
|
}
|
|
5012
|
-
}
|
|
5013
|
-
}
|
|
5014
|
-
const
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
resolve: {
|
|
5043
|
-
alias: rangoAliases
|
|
5044
|
-
},
|
|
5045
|
-
environments: {
|
|
5046
|
-
client: {
|
|
5047
|
-
build: {
|
|
5048
|
-
rollupOptions: {
|
|
5049
|
-
output: {
|
|
5050
|
-
manualChunks: getManualChunks
|
|
5051
|
-
}
|
|
5052
|
-
}
|
|
5053
|
-
},
|
|
5054
|
-
// Always exclude rsc-router modules, conditionally add virtual entry
|
|
5055
|
-
optimizeDeps: {
|
|
5056
|
-
// Pre-bundle React and rsc-html-stream to prevent late discovery
|
|
5057
|
-
// triggering ERR_OUTDATED_OPTIMIZED_DEP on cold starts
|
|
5058
|
-
include: [
|
|
5059
|
-
"react",
|
|
5060
|
-
"react-dom",
|
|
5061
|
-
"react/jsx-runtime",
|
|
5062
|
-
"react/jsx-dev-runtime",
|
|
5063
|
-
"rsc-html-stream/client"
|
|
5064
|
-
],
|
|
5065
|
-
exclude: excludeDeps,
|
|
5066
|
-
esbuildOptions: sharedEsbuildOptions,
|
|
5067
|
-
...useVirtualClient && {
|
|
5068
|
-
// Tell Vite to scan the virtual entry for dependencies
|
|
5069
|
-
entries: [VIRTUAL_IDS.browser]
|
|
5070
|
-
}
|
|
5071
|
-
}
|
|
5072
|
-
},
|
|
5073
|
-
...useVirtualSSR && {
|
|
5074
|
-
ssr: {
|
|
5075
|
-
optimizeDeps: {
|
|
5076
|
-
entries: [VIRTUAL_IDS.ssr],
|
|
5077
|
-
// Pre-bundle all SSR deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
5078
|
-
include: [
|
|
5079
|
-
"react",
|
|
5080
|
-
"react-dom",
|
|
5081
|
-
"react-dom/server.edge",
|
|
5082
|
-
"react-dom/static.edge",
|
|
5083
|
-
"react/jsx-runtime",
|
|
5084
|
-
"react/jsx-dev-runtime",
|
|
5085
|
-
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5086
|
-
],
|
|
5087
|
-
exclude: excludeDeps,
|
|
5088
|
-
esbuildOptions: sharedEsbuildOptions
|
|
5228
|
+
}
|
|
5229
|
+
});
|
|
5230
|
+
const finalEntries = {
|
|
5231
|
+
client: VIRTUAL_IDS.browser,
|
|
5232
|
+
ssr: VIRTUAL_IDS.ssr,
|
|
5233
|
+
rsc: VIRTUAL_IDS.rsc
|
|
5234
|
+
};
|
|
5235
|
+
const { default: rsc } = await import("@vitejs/plugin-rsc");
|
|
5236
|
+
let hasWarnedDuplicate = false;
|
|
5237
|
+
plugins.push({
|
|
5238
|
+
name: "@rangojs/router:rsc-integration",
|
|
5239
|
+
enforce: "pre",
|
|
5240
|
+
config() {
|
|
5241
|
+
return {
|
|
5242
|
+
optimizeDeps: {
|
|
5243
|
+
exclude: excludeDeps,
|
|
5244
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5245
|
+
},
|
|
5246
|
+
build: {
|
|
5247
|
+
rollupOptions: { onwarn }
|
|
5248
|
+
},
|
|
5249
|
+
resolve: {
|
|
5250
|
+
alias: rangoAliases
|
|
5251
|
+
},
|
|
5252
|
+
environments: {
|
|
5253
|
+
client: {
|
|
5254
|
+
build: {
|
|
5255
|
+
rollupOptions: {
|
|
5256
|
+
output: {
|
|
5257
|
+
manualChunks: getManualChunks
|
|
5089
5258
|
}
|
|
5090
5259
|
}
|
|
5091
5260
|
},
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5261
|
+
optimizeDeps: {
|
|
5262
|
+
include: [
|
|
5263
|
+
"react",
|
|
5264
|
+
"react-dom",
|
|
5265
|
+
"react/jsx-runtime",
|
|
5266
|
+
"react/jsx-dev-runtime",
|
|
5267
|
+
"rsc-html-stream/client"
|
|
5268
|
+
],
|
|
5269
|
+
exclude: excludeDeps,
|
|
5270
|
+
esbuildOptions: sharedEsbuildOptions,
|
|
5271
|
+
entries: [VIRTUAL_IDS.browser]
|
|
5272
|
+
}
|
|
5273
|
+
},
|
|
5274
|
+
ssr: {
|
|
5275
|
+
optimizeDeps: {
|
|
5276
|
+
entries: [VIRTUAL_IDS.ssr],
|
|
5277
|
+
include: [
|
|
5278
|
+
"react",
|
|
5279
|
+
"react-dom",
|
|
5280
|
+
"react-dom/server.edge",
|
|
5281
|
+
"react-dom/static.edge",
|
|
5282
|
+
"react/jsx-runtime",
|
|
5283
|
+
"react/jsx-dev-runtime",
|
|
5284
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
5285
|
+
],
|
|
5286
|
+
exclude: excludeDeps,
|
|
5287
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5288
|
+
}
|
|
5289
|
+
},
|
|
5290
|
+
rsc: {
|
|
5291
|
+
optimizeDeps: {
|
|
5292
|
+
entries: [VIRTUAL_IDS.rsc],
|
|
5293
|
+
include: [
|
|
5294
|
+
"react",
|
|
5295
|
+
"react/jsx-runtime",
|
|
5296
|
+
"react/jsx-dev-runtime",
|
|
5297
|
+
"@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
|
|
5298
|
+
],
|
|
5299
|
+
esbuildOptions: sharedEsbuildOptions
|
|
5106
5300
|
}
|
|
5107
5301
|
}
|
|
5108
|
-
};
|
|
5109
|
-
},
|
|
5110
|
-
configResolved(config) {
|
|
5111
|
-
if (showBanner) {
|
|
5112
|
-
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
5113
|
-
printBanner(mode, "node", rangoVersion);
|
|
5114
|
-
}
|
|
5115
|
-
const rscMinimalCount = config.plugins.filter(
|
|
5116
|
-
(p) => p.name === "rsc:minimal"
|
|
5117
|
-
).length;
|
|
5118
|
-
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5119
|
-
hasWarnedDuplicate = true;
|
|
5120
|
-
console.warn(
|
|
5121
|
-
"[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your config or use rango({ rsc: false }) for manual configuration."
|
|
5122
|
-
);
|
|
5123
5302
|
}
|
|
5303
|
+
};
|
|
5304
|
+
},
|
|
5305
|
+
configResolved(config) {
|
|
5306
|
+
if (showBanner) {
|
|
5307
|
+
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
5308
|
+
printBanner(mode, "node", rangoVersion);
|
|
5124
5309
|
}
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5310
|
+
const rscMinimalCount = config.plugins.filter(
|
|
5311
|
+
(p) => p.name === "rsc:minimal"
|
|
5312
|
+
).length;
|
|
5313
|
+
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
5314
|
+
hasWarnedDuplicate = true;
|
|
5315
|
+
console.warn(
|
|
5316
|
+
"[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
|
|
5317
|
+
);
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
});
|
|
5321
|
+
plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
|
|
5322
|
+
plugins.push(performanceTracksPlugin());
|
|
5323
|
+
plugins.push(
|
|
5324
|
+
rsc({
|
|
5325
|
+
entries: finalEntries
|
|
5326
|
+
})
|
|
5327
|
+
);
|
|
5133
5328
|
plugins.push(clientRefDedup());
|
|
5134
5329
|
}
|
|
5135
5330
|
plugins.push({
|
|
@@ -5157,18 +5352,16 @@ ${list}`
|
|
|
5157
5352
|
plugins.push(createVersionPlugin());
|
|
5158
5353
|
const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
|
|
5159
5354
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
plugins.push(createVersionInjectorPlugin(injectorEntryPath));
|
|
5355
|
+
if (preset === "cloudflare") {
|
|
5356
|
+
plugins.push(createVersionInjectorPlugin(void 0));
|
|
5163
5357
|
}
|
|
5164
5358
|
plugins.push(createCjsToEsmPlugin());
|
|
5165
5359
|
plugins.push(
|
|
5166
5360
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5167
5361
|
routerPathRef: discoveryRouterRef,
|
|
5168
5362
|
enableBuildPrerender: prerenderEnabled,
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
exclude: resolvedOptions.exclude
|
|
5363
|
+
buildEnv: options?.buildEnv,
|
|
5364
|
+
preset
|
|
5172
5365
|
})
|
|
5173
5366
|
);
|
|
5174
5367
|
return plugins;
|
|
@@ -5181,29 +5374,75 @@ function poke() {
|
|
|
5181
5374
|
apply: "serve",
|
|
5182
5375
|
configureServer(server) {
|
|
5183
5376
|
const stdin = process.stdin;
|
|
5184
|
-
const
|
|
5377
|
+
const debug = process.env.RANGO_POKE_DEBUG === "1";
|
|
5378
|
+
const triggerReload = (source) => {
|
|
5379
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
5380
|
+
server.config.logger.info(` browser reload (${source})`, {
|
|
5381
|
+
timestamp: true
|
|
5382
|
+
});
|
|
5383
|
+
};
|
|
5384
|
+
const toBuffer = (chunk) => {
|
|
5385
|
+
return typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5386
|
+
};
|
|
5387
|
+
const formatChunk = (chunk) => {
|
|
5388
|
+
const data = toBuffer(chunk);
|
|
5389
|
+
const hex = Array.from(data).map((byte) => `0x${byte.toString(16).padStart(2, "0")}`).join(" ");
|
|
5390
|
+
const ascii = Array.from(data).map((byte) => {
|
|
5391
|
+
if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
|
|
5392
|
+
if (byte === 10) return "\\n";
|
|
5393
|
+
if (byte === 13) return "\\r";
|
|
5394
|
+
if (byte === 9) return "\\t";
|
|
5395
|
+
return ".";
|
|
5396
|
+
}).join("");
|
|
5397
|
+
return `len=${data.length} hex=[${hex}] ascii="${ascii}"`;
|
|
5398
|
+
};
|
|
5399
|
+
const readCtrlR = (chunk) => {
|
|
5400
|
+
const data = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
5401
|
+
return data.length === 1 && data[0] === 18;
|
|
5402
|
+
};
|
|
5403
|
+
const readSubmittedCommands = (chunk) => {
|
|
5404
|
+
const text = toBuffer(chunk).toString("utf8").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
5405
|
+
if (!text.includes("\n")) return [];
|
|
5406
|
+
const lines = text.split("\n");
|
|
5407
|
+
lines.pop();
|
|
5408
|
+
return lines;
|
|
5409
|
+
};
|
|
5410
|
+
if (debug) {
|
|
5411
|
+
server.config.logger.info(
|
|
5412
|
+
` poke debug enabled (isTTY=${stdin.isTTY ? "yes" : "no"}, isRaw=${stdin.isTTY ? stdin.isRaw ? "yes" : "no" : "n/a"})`,
|
|
5413
|
+
{ timestamp: true }
|
|
5414
|
+
);
|
|
5415
|
+
}
|
|
5185
5416
|
if (stdin.isTTY) {
|
|
5186
|
-
|
|
5417
|
+
server.config.logger.info(
|
|
5418
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
5419
|
+
{ timestamp: true }
|
|
5420
|
+
);
|
|
5187
5421
|
}
|
|
5188
5422
|
const onData = (data) => {
|
|
5189
|
-
if (
|
|
5190
|
-
|
|
5191
|
-
process.emit("SIGINT", "SIGINT");
|
|
5192
|
-
return;
|
|
5193
|
-
}
|
|
5194
|
-
if (data[0] === 18) {
|
|
5195
|
-
server.hot.send({ type: "full-reload", path: "*" });
|
|
5196
|
-
server.config.logger.info(" browser reload (ctrl+r)", {
|
|
5423
|
+
if (debug) {
|
|
5424
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5197
5425
|
timestamp: true
|
|
5198
5426
|
});
|
|
5199
5427
|
}
|
|
5428
|
+
if (readCtrlR(data)) {
|
|
5429
|
+
triggerReload("ctrl+r");
|
|
5430
|
+
return;
|
|
5431
|
+
}
|
|
5432
|
+
for (const command of readSubmittedCommands(data)) {
|
|
5433
|
+
if (command === "e") {
|
|
5434
|
+
triggerReload("e+enter");
|
|
5435
|
+
return;
|
|
5436
|
+
}
|
|
5437
|
+
if (command === "\x1Br") {
|
|
5438
|
+
triggerReload("option+r+enter");
|
|
5439
|
+
return;
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5200
5442
|
};
|
|
5201
5443
|
stdin.on("data", onData);
|
|
5202
5444
|
server.httpServer?.on("close", () => {
|
|
5203
5445
|
stdin.off("data", onData);
|
|
5204
|
-
if (stdin.isTTY && previousRawMode !== null) {
|
|
5205
|
-
stdin.setRawMode(previousRawMode);
|
|
5206
|
-
}
|
|
5207
5446
|
});
|
|
5208
5447
|
}
|
|
5209
5448
|
};
|