@rangojs/router 0.0.0-experimental.19 → 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/{CLAUDE.md → AGENTS.md} +4 -0
- package/README.md +122 -30
- package/dist/bin/rango.js +245 -63
- package/dist/vite/index.js +859 -418
- package/package.json +3 -3
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +49 -8
- package/skills/document-cache/SKILL.md +2 -2
- package/skills/hooks/SKILL.md +33 -31
- package/skills/host-router/SKILL.md +218 -0
- package/skills/links/SKILL.md +3 -1
- package/skills/loader/SKILL.md +72 -22
- package/skills/middleware/SKILL.md +2 -0
- package/skills/parallel/SKILL.md +126 -0
- package/skills/prerender/SKILL.md +112 -70
- package/skills/rango/SKILL.md +0 -1
- package/skills/route/SKILL.md +34 -4
- package/skills/router-setup/SKILL.md +95 -5
- package/skills/typesafety/SKILL.md +35 -23
- package/src/__internal.ts +92 -0
- package/src/bin/rango.ts +18 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +114 -18
- package/src/browser/navigation-client.ts +126 -44
- 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 +166 -27
- package/src/browser/prefetch/fetch.ts +52 -39
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +92 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/react/Link.tsx +70 -14
- 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 +143 -59
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +6 -1
- package/src/browser/server-action-bridge.ts +454 -436
- package/src/browser/types.ts +60 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/route-trie.ts +19 -3
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +346 -87
- 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.rsc.tsx +2 -1
- package/src/client.tsx +3 -102
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/host/index.ts +0 -3
- package/src/index.rsc.ts +8 -37
- package/src/index.ts +40 -66
- package/src/prerender/store.ts +57 -15
- 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 -3
- 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 +108 -25
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +4 -1
- package/src/router/loader-resolution.ts +123 -11
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +9 -3
- package/src/router/match-api.ts +125 -190
- 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 -15
- package/src/router/metrics.ts +238 -13
- package/src/router/middleware-types.ts +53 -12
- package/src/router/middleware.ts +172 -85
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +20 -5
- package/src/router/prerender-match.ts +114 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +27 -7
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +50 -5
- package/src/router/router-options.ts +50 -19
- package/src/router/segment-resolution/fresh.ts +200 -19
- package/src/router/segment-resolution/helpers.ts +30 -25
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +429 -301
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/trie-matching.ts +20 -2
- package/src/router/types.ts +1 -0
- package/src/router.ts +88 -15
- package/src/rsc/handler.ts +546 -359
- package/src/rsc/index.ts +0 -20
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +25 -8
- package/src/rsc/rsc-rendering.ts +35 -43
- package/src/rsc/server-action.ts +16 -10
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +10 -1
- package/src/search-params.ts +16 -13
- package/src/segment-system.tsx +140 -4
- package/src/server/context.ts +148 -16
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +182 -34
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/theme/index.ts +4 -13
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +149 -49
- package/src/types/loader-types.ts +36 -9
- package/src/types/route-config.ts +17 -8
- package/src/types/route-entry.ts +8 -1
- package/src/types/segments.ts +2 -5
- 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 +61 -89
- package/src/vite/discovery/discover-routers.ts +23 -5
- package/src/vite/discovery/prerender-collection.ts +48 -15
- package/src/vite/discovery/state.ts +17 -13
- package/src/vite/index.ts +8 -3
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- 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 +127 -0
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +174 -211
- package/src/vite/router-discovery.ts +169 -42
- package/src/vite/utils/banner.ts +3 -3
- package/src/vite/utils/prerender-utils.ts +78 -0
- package/src/vite/utils/shared-utils.ts +3 -2
- package/skills/testing/SKILL.md +0 -226
- package/src/route-definition/route-function.ts +0 -119
package/dist/vite/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/vite/rango.ts
|
|
2
2
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
3
|
-
import { resolve as
|
|
3
|
+
import { resolve as resolve9 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/vite/plugins/expose-action-id.ts
|
|
6
6
|
import MagicString from "magic-string";
|
|
@@ -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;
|
|
@@ -1585,6 +1585,53 @@ function warnOnNearMissDirectives(ast, fileId, warn) {
|
|
|
1585
1585
|
}
|
|
1586
1586
|
}
|
|
1587
1587
|
|
|
1588
|
+
// src/vite/plugins/client-ref-dedup.ts
|
|
1589
|
+
var CLIENT_IN_SERVER_PROXY_PREFIX = "virtual:vite-rsc/client-in-server-package-proxy/";
|
|
1590
|
+
function extractPackageName(absolutePath) {
|
|
1591
|
+
const marker = "/node_modules/";
|
|
1592
|
+
const idx = absolutePath.lastIndexOf(marker);
|
|
1593
|
+
if (idx === -1) return null;
|
|
1594
|
+
const afterModules = absolutePath.slice(idx + marker.length);
|
|
1595
|
+
if (afterModules.startsWith("@")) {
|
|
1596
|
+
const parts = afterModules.split("/");
|
|
1597
|
+
if (parts.length < 2 || !parts[1]) return null;
|
|
1598
|
+
return `${parts[0]}/${parts[1]}`;
|
|
1599
|
+
}
|
|
1600
|
+
const name = afterModules.split("/")[0];
|
|
1601
|
+
return name || null;
|
|
1602
|
+
}
|
|
1603
|
+
function clientRefDedup() {
|
|
1604
|
+
let clientExclude = [];
|
|
1605
|
+
return {
|
|
1606
|
+
name: "@rangojs/router:client-ref-dedup",
|
|
1607
|
+
enforce: "pre",
|
|
1608
|
+
apply: "serve",
|
|
1609
|
+
configResolved(config) {
|
|
1610
|
+
const clientEnv = config.environments?.["client"];
|
|
1611
|
+
clientExclude = clientEnv?.optimizeDeps?.exclude ?? config.optimizeDeps?.exclude ?? [];
|
|
1612
|
+
},
|
|
1613
|
+
resolveId(source, importer, options) {
|
|
1614
|
+
if (this.environment?.name !== "client") return;
|
|
1615
|
+
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
1616
|
+
if (!source.includes("/node_modules/")) return;
|
|
1617
|
+
if (!importer) return;
|
|
1618
|
+
const packageName = extractPackageName(source);
|
|
1619
|
+
if (!packageName) return;
|
|
1620
|
+
if (clientExclude.includes(packageName)) return;
|
|
1621
|
+
return `\0rango:dedup/${packageName}`;
|
|
1622
|
+
},
|
|
1623
|
+
load(id) {
|
|
1624
|
+
if (!id.startsWith("\0rango:dedup/")) return;
|
|
1625
|
+
const packageName = id.slice("\0rango:dedup/".length);
|
|
1626
|
+
return [
|
|
1627
|
+
`export * from ${JSON.stringify(packageName)};`,
|
|
1628
|
+
`import * as __all__ from ${JSON.stringify(packageName)};`,
|
|
1629
|
+
`export default __all__.default;`
|
|
1630
|
+
].join("\n");
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1588
1635
|
// src/vite/plugins/virtual-entries.ts
|
|
1589
1636
|
var VIRTUAL_ENTRY_BROWSER = `
|
|
1590
1637
|
import {
|
|
@@ -1698,7 +1745,7 @@ import { resolve } from "node:path";
|
|
|
1698
1745
|
// package.json
|
|
1699
1746
|
var package_default = {
|
|
1700
1747
|
name: "@rangojs/router",
|
|
1701
|
-
version: "0.0.0-experimental.
|
|
1748
|
+
version: "0.0.0-experimental.1fa245e2",
|
|
1702
1749
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
1703
1750
|
keywords: [
|
|
1704
1751
|
"react",
|
|
@@ -1729,7 +1776,7 @@ var package_default = {
|
|
|
1729
1776
|
"!src/**/*.test.tsx",
|
|
1730
1777
|
"dist",
|
|
1731
1778
|
"skills",
|
|
1732
|
-
"
|
|
1779
|
+
"AGENTS.md",
|
|
1733
1780
|
"README.md"
|
|
1734
1781
|
],
|
|
1735
1782
|
type: "module",
|
|
@@ -1840,7 +1887,7 @@ var package_default = {
|
|
|
1840
1887
|
"test:unit:watch": "vitest"
|
|
1841
1888
|
},
|
|
1842
1889
|
dependencies: {
|
|
1843
|
-
"@vitejs/plugin-rsc": "^0.5.
|
|
1890
|
+
"@vitejs/plugin-rsc": "^0.5.19",
|
|
1844
1891
|
"magic-string": "^0.30.17",
|
|
1845
1892
|
picomatch: "^4.0.3",
|
|
1846
1893
|
"rsc-html-stream": "^0.0.7"
|
|
@@ -2048,55 +2095,7 @@ declare global {
|
|
|
2048
2095
|
}
|
|
2049
2096
|
|
|
2050
2097
|
// src/build/route-types/scan-filter.ts
|
|
2051
|
-
import { join, relative } from "node:path";
|
|
2052
|
-
import { readdirSync } from "node:fs";
|
|
2053
2098
|
import picomatch from "picomatch";
|
|
2054
|
-
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
2055
|
-
"**/__tests__/**",
|
|
2056
|
-
"**/__mocks__/**",
|
|
2057
|
-
"**/dist/**",
|
|
2058
|
-
"**/coverage/**",
|
|
2059
|
-
"**/*.test.{ts,tsx,js,jsx}",
|
|
2060
|
-
"**/*.spec.{ts,tsx,js,jsx}"
|
|
2061
|
-
];
|
|
2062
|
-
function createScanFilter(root, opts) {
|
|
2063
|
-
const { include, exclude } = opts;
|
|
2064
|
-
const hasInclude = include && include.length > 0;
|
|
2065
|
-
const hasCustomExclude = exclude !== void 0;
|
|
2066
|
-
if (!hasInclude && !hasCustomExclude) return void 0;
|
|
2067
|
-
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE_PATTERNS;
|
|
2068
|
-
const includeMatcher = hasInclude ? picomatch(include) : null;
|
|
2069
|
-
const excludeMatcher = effectiveExclude.length > 0 ? picomatch(effectiveExclude) : null;
|
|
2070
|
-
return (absolutePath) => {
|
|
2071
|
-
const rel = relative(root, absolutePath);
|
|
2072
|
-
if (excludeMatcher && excludeMatcher(rel)) return false;
|
|
2073
|
-
if (includeMatcher) return includeMatcher(rel);
|
|
2074
|
-
return true;
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
function findTsFiles(dir, filter) {
|
|
2078
|
-
const results = [];
|
|
2079
|
-
let entries;
|
|
2080
|
-
try {
|
|
2081
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
2082
|
-
} catch (err) {
|
|
2083
|
-
console.warn(
|
|
2084
|
-
`[rsc-router] Failed to scan directory ${dir}: ${err.message}`
|
|
2085
|
-
);
|
|
2086
|
-
return results;
|
|
2087
|
-
}
|
|
2088
|
-
for (const entry of entries) {
|
|
2089
|
-
const fullPath = join(dir, entry.name);
|
|
2090
|
-
if (entry.isDirectory()) {
|
|
2091
|
-
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
2092
|
-
results.push(...findTsFiles(fullPath, filter));
|
|
2093
|
-
} else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
|
|
2094
|
-
if (filter && !filter(fullPath)) continue;
|
|
2095
|
-
results.push(fullPath);
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
return results;
|
|
2099
|
-
}
|
|
2100
2099
|
|
|
2101
2100
|
// src/build/route-types/per-module-writer.ts
|
|
2102
2101
|
import ts4 from "typescript";
|
|
@@ -2318,7 +2317,7 @@ function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSche
|
|
|
2318
2317
|
}
|
|
2319
2318
|
return routeMap;
|
|
2320
2319
|
}
|
|
2321
|
-
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut) {
|
|
2320
|
+
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
|
|
2322
2321
|
visited = visited ?? /* @__PURE__ */ new Set();
|
|
2323
2322
|
const realPath = resolve2(filePath);
|
|
2324
2323
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
@@ -2334,7 +2333,9 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2334
2333
|
return { routes: {}, searchSchemas: {} };
|
|
2335
2334
|
}
|
|
2336
2335
|
let block;
|
|
2337
|
-
if (
|
|
2336
|
+
if (inlineBlock) {
|
|
2337
|
+
block = inlineBlock;
|
|
2338
|
+
} else if (variableName) {
|
|
2338
2339
|
const extracted = extractUrlsBlockForVariable(source, variableName);
|
|
2339
2340
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
2340
2341
|
block = extracted;
|
|
@@ -2355,8 +2356,20 @@ function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagno
|
|
|
2355
2356
|
}
|
|
2356
2357
|
|
|
2357
2358
|
// src/build/route-types/router-processing.ts
|
|
2358
|
-
import {
|
|
2359
|
-
|
|
2359
|
+
import {
|
|
2360
|
+
readFileSync as readFileSync2,
|
|
2361
|
+
writeFileSync,
|
|
2362
|
+
existsSync as existsSync3,
|
|
2363
|
+
unlinkSync,
|
|
2364
|
+
readdirSync
|
|
2365
|
+
} from "node:fs";
|
|
2366
|
+
import {
|
|
2367
|
+
join,
|
|
2368
|
+
dirname as dirname2,
|
|
2369
|
+
resolve as resolve3,
|
|
2370
|
+
sep,
|
|
2371
|
+
basename as pathBasename
|
|
2372
|
+
} from "node:path";
|
|
2360
2373
|
import ts5 from "typescript";
|
|
2361
2374
|
function countPublicRouteEntries(source) {
|
|
2362
2375
|
const matches = source.matchAll(/^\s+(?:"([^"]+)"|([a-zA-Z_$][^:]*)):\s*["{]/gm) ?? [];
|
|
@@ -2369,7 +2382,79 @@ function countPublicRouteEntries(source) {
|
|
|
2369
2382
|
}
|
|
2370
2383
|
return count;
|
|
2371
2384
|
}
|
|
2372
|
-
|
|
2385
|
+
var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
2386
|
+
function isRoutableSourceFile(name) {
|
|
2387
|
+
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
2388
|
+
}
|
|
2389
|
+
function findRouterFilesRecursive(dir, filter, results) {
|
|
2390
|
+
let entries;
|
|
2391
|
+
try {
|
|
2392
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
2393
|
+
} catch (err) {
|
|
2394
|
+
console.warn(
|
|
2395
|
+
`[rsc-router] Failed to scan directory ${dir}: ${err.message}`
|
|
2396
|
+
);
|
|
2397
|
+
return;
|
|
2398
|
+
}
|
|
2399
|
+
const childDirs = [];
|
|
2400
|
+
const routerFilesInDir = [];
|
|
2401
|
+
for (const entry of entries) {
|
|
2402
|
+
const fullPath = join(dir, entry.name);
|
|
2403
|
+
if (entry.isDirectory()) {
|
|
2404
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
|
|
2405
|
+
continue;
|
|
2406
|
+
childDirs.push(fullPath);
|
|
2407
|
+
continue;
|
|
2408
|
+
}
|
|
2409
|
+
if (!isRoutableSourceFile(entry.name)) continue;
|
|
2410
|
+
if (filter && !filter(fullPath)) continue;
|
|
2411
|
+
try {
|
|
2412
|
+
const source = readFileSync2(fullPath, "utf-8");
|
|
2413
|
+
if (ROUTER_CALL_PATTERN.test(source)) {
|
|
2414
|
+
routerFilesInDir.push(fullPath);
|
|
2415
|
+
}
|
|
2416
|
+
} catch {
|
|
2417
|
+
continue;
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
if (routerFilesInDir.length > 0) {
|
|
2421
|
+
results.push(...routerFilesInDir);
|
|
2422
|
+
return;
|
|
2423
|
+
}
|
|
2424
|
+
for (const childDir of childDirs) {
|
|
2425
|
+
findRouterFilesRecursive(childDir, filter, results);
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
function findNestedRouterConflict(routerFiles) {
|
|
2429
|
+
const routerDirs = [
|
|
2430
|
+
...new Set(routerFiles.map((filePath) => dirname2(resolve3(filePath))))
|
|
2431
|
+
].sort((a, b) => a.length - b.length);
|
|
2432
|
+
for (let i = 0; i < routerDirs.length; i++) {
|
|
2433
|
+
const ancestorDir = routerDirs[i];
|
|
2434
|
+
const prefix = ancestorDir.endsWith(sep) ? ancestorDir : `${ancestorDir}${sep}`;
|
|
2435
|
+
for (let j = i + 1; j < routerDirs.length; j++) {
|
|
2436
|
+
const nestedDir = routerDirs[j];
|
|
2437
|
+
if (!nestedDir.startsWith(prefix)) continue;
|
|
2438
|
+
const ancestorFile = routerFiles.find(
|
|
2439
|
+
(filePath) => dirname2(resolve3(filePath)) === ancestorDir
|
|
2440
|
+
);
|
|
2441
|
+
const nestedFile = routerFiles.find(
|
|
2442
|
+
(filePath) => dirname2(resolve3(filePath)) === nestedDir
|
|
2443
|
+
);
|
|
2444
|
+
if (ancestorFile && nestedFile) {
|
|
2445
|
+
return { ancestor: ancestorFile, nested: nestedFile };
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
return null;
|
|
2450
|
+
}
|
|
2451
|
+
function formatNestedRouterConflictError(conflict, prefix = "[rsc-router]") {
|
|
2452
|
+
return `${prefix} Nested router roots are not supported.
|
|
2453
|
+
Router root: ${conflict.ancestor}
|
|
2454
|
+
Nested router: ${conflict.nested}
|
|
2455
|
+
Move the nested router into a sibling directory or configure it as a separate app root.`;
|
|
2456
|
+
}
|
|
2457
|
+
function extractUrlsFromRouter(code) {
|
|
2373
2458
|
const sourceFile = ts5.createSourceFile(
|
|
2374
2459
|
"router.tsx",
|
|
2375
2460
|
code,
|
|
@@ -2383,24 +2468,70 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2383
2468
|
const callee = node.expression;
|
|
2384
2469
|
return ts5.isIdentifier(callee) && callee.text === "createRouter";
|
|
2385
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
|
+
}
|
|
2386
2483
|
function visit(node) {
|
|
2387
2484
|
if (result) return;
|
|
2388
|
-
if (ts5.isCallExpression(node) &&
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
result = node.arguments[0].text;
|
|
2395
|
-
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) };
|
|
2396
2491
|
}
|
|
2492
|
+
return;
|
|
2397
2493
|
}
|
|
2398
2494
|
if (isCreateRouterCall(node)) {
|
|
2399
2495
|
const callExpr = node;
|
|
2400
|
-
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) {
|
|
2401
2532
|
if (ts5.isObjectLiteralExpression(arg)) {
|
|
2402
2533
|
for (const prop of arg.properties) {
|
|
2403
|
-
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)) {
|
|
2404
2535
|
result = prop.initializer.text;
|
|
2405
2536
|
return;
|
|
2406
2537
|
}
|
|
@@ -2413,6 +2544,19 @@ function extractUrlsVariableFromRouter(code) {
|
|
|
2413
2544
|
visit(sourceFile);
|
|
2414
2545
|
return result;
|
|
2415
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
|
+
}
|
|
2416
2560
|
function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
2417
2561
|
let routerSource;
|
|
2418
2562
|
try {
|
|
@@ -2420,39 +2564,49 @@ function buildCombinedRouteMapForRouterFile(routerFilePath) {
|
|
|
2420
2564
|
} catch {
|
|
2421
2565
|
return { routes: {}, searchSchemas: {} };
|
|
2422
2566
|
}
|
|
2423
|
-
const
|
|
2424
|
-
if (!
|
|
2567
|
+
const extraction = extractUrlsFromRouter(routerSource);
|
|
2568
|
+
if (!extraction) {
|
|
2425
2569
|
return { routes: {}, searchSchemas: {} };
|
|
2426
2570
|
}
|
|
2427
|
-
const
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
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);
|
|
2432
2595
|
}
|
|
2433
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
2434
2596
|
}
|
|
2435
|
-
|
|
2597
|
+
if (basename3) {
|
|
2598
|
+
result = applyBasenameToRoutes(result, basename3);
|
|
2599
|
+
}
|
|
2600
|
+
return result;
|
|
2436
2601
|
}
|
|
2437
2602
|
function findRouterFiles(root, filter) {
|
|
2438
|
-
const files = findTsFiles(root, filter);
|
|
2439
2603
|
const result = [];
|
|
2440
|
-
|
|
2441
|
-
if (filePath.includes(".gen.")) continue;
|
|
2442
|
-
try {
|
|
2443
|
-
const source = readFileSync2(filePath, "utf-8");
|
|
2444
|
-
if (/\bcreateRouter\s*[<(]/.test(source)) {
|
|
2445
|
-
result.push(filePath);
|
|
2446
|
-
}
|
|
2447
|
-
} catch {
|
|
2448
|
-
continue;
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2604
|
+
findRouterFilesRecursive(root, filter, result);
|
|
2451
2605
|
return result;
|
|
2452
2606
|
}
|
|
2453
2607
|
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
2454
2608
|
try {
|
|
2455
|
-
const oldCombinedPath =
|
|
2609
|
+
const oldCombinedPath = join(root, "src", "named-routes.gen.ts");
|
|
2456
2610
|
if (existsSync3(oldCombinedPath)) {
|
|
2457
2611
|
unlinkSync(oldCombinedPath);
|
|
2458
2612
|
console.log(
|
|
@@ -2463,32 +2617,26 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
|
|
|
2463
2617
|
}
|
|
2464
2618
|
const routerFilePaths = knownRouterFiles ?? findRouterFiles(root);
|
|
2465
2619
|
if (routerFilePaths.length === 0) return;
|
|
2620
|
+
const nestedRouterConflict = findNestedRouterConflict(routerFilePaths);
|
|
2621
|
+
if (nestedRouterConflict) {
|
|
2622
|
+
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
2623
|
+
}
|
|
2466
2624
|
for (const routerFilePath of routerFilePaths) {
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
routerSource
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
2477
|
-
if (imported) {
|
|
2478
|
-
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
2479
|
-
if (!targetFile) continue;
|
|
2480
|
-
result = buildCombinedRouteMapWithSearch(
|
|
2481
|
-
targetFile,
|
|
2482
|
-
imported.exportedName
|
|
2483
|
-
);
|
|
2484
|
-
} else {
|
|
2485
|
-
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;
|
|
2486
2634
|
}
|
|
2487
2635
|
const routerBasename = pathBasename(routerFilePath).replace(
|
|
2488
2636
|
/\.(tsx?|jsx?)$/,
|
|
2489
2637
|
""
|
|
2490
2638
|
);
|
|
2491
|
-
const outPath =
|
|
2639
|
+
const outPath = join(
|
|
2492
2640
|
dirname2(routerFilePath),
|
|
2493
2641
|
`${routerBasename}.named-routes.gen.ts`
|
|
2494
2642
|
);
|
|
@@ -2618,8 +2766,9 @@ function createVersionPlugin() {
|
|
|
2618
2766
|
let isDev = false;
|
|
2619
2767
|
let server = null;
|
|
2620
2768
|
const clientModuleSignatures = /* @__PURE__ */ new Map();
|
|
2769
|
+
let versionCounter = 0;
|
|
2621
2770
|
const bumpVersion = (reason) => {
|
|
2622
|
-
currentVersion = Date.now().toString(16);
|
|
2771
|
+
currentVersion = Date.now().toString(16) + String(++versionCounter);
|
|
2623
2772
|
console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
|
|
2624
2773
|
const rscEnv = server?.environments?.rsc;
|
|
2625
2774
|
const versionMod = rscEnv?.moduleGraph?.getModuleById(
|
|
@@ -2675,6 +2824,9 @@ function createVersionPlugin() {
|
|
|
2675
2824
|
if (!isDev) return;
|
|
2676
2825
|
const isRscModule = this.environment?.name === "rsc";
|
|
2677
2826
|
if (!isRscModule) return;
|
|
2827
|
+
if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2678
2830
|
if (isCodeModule(ctx.file)) {
|
|
2679
2831
|
const filePath = normalizeModuleId(ctx.file);
|
|
2680
2832
|
const previousSignature = clientModuleSignatures.get(filePath);
|
|
@@ -2704,6 +2856,68 @@ function createVersionPlugin() {
|
|
|
2704
2856
|
|
|
2705
2857
|
// src/vite/utils/shared-utils.ts
|
|
2706
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
|
|
2707
2921
|
var versionEsbuildPlugin = {
|
|
2708
2922
|
name: "@rangojs/router-version",
|
|
2709
2923
|
setup(build) {
|
|
@@ -2721,7 +2935,7 @@ var versionEsbuildPlugin = {
|
|
|
2721
2935
|
}
|
|
2722
2936
|
};
|
|
2723
2937
|
var sharedEsbuildOptions = {
|
|
2724
|
-
plugins: [versionEsbuildPlugin]
|
|
2938
|
+
plugins: [versionEsbuildPlugin, performanceTracksOptimizeDepsPlugin()]
|
|
2725
2939
|
};
|
|
2726
2940
|
function createVirtualEntriesPlugin(entries, routerPathRef) {
|
|
2727
2941
|
const virtualModules = {};
|
|
@@ -2804,11 +3018,11 @@ ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2
|
|
|
2804
3018
|
${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
|
|
2805
3019
|
${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
|
|
2806
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}
|
|
2807
|
-
${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}
|
|
2808
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}
|
|
2809
3023
|
${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
|
|
2810
|
-
${dim} * ${reset}${bold}\u2551 \
|
|
2811
|
-
${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}
|
|
2812
3026
|
|
|
2813
3027
|
v${version} \xB7 ${preset} \xB7 ${mode}
|
|
2814
3028
|
`;
|
|
@@ -2925,7 +3139,10 @@ function createCjsToEsmPlugin() {
|
|
|
2925
3139
|
|
|
2926
3140
|
// src/vite/router-discovery.ts
|
|
2927
3141
|
import { createServer as createViteServer } from "vite";
|
|
3142
|
+
import { resolve as resolve8 } from "node:path";
|
|
2928
3143
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3144
|
+
import { createRequire } from "node:module";
|
|
3145
|
+
import { pathToFileURL } from "node:url";
|
|
2929
3146
|
|
|
2930
3147
|
// src/vite/plugins/virtual-stub-plugin.ts
|
|
2931
3148
|
function createVirtualStubPlugin() {
|
|
@@ -2952,7 +3169,7 @@ function createVirtualStubPlugin() {
|
|
|
2952
3169
|
}
|
|
2953
3170
|
|
|
2954
3171
|
// src/vite/plugins/client-ref-hashing.ts
|
|
2955
|
-
import { relative
|
|
3172
|
+
import { relative } from "node:path";
|
|
2956
3173
|
import { createHash as createHash2 } from "node:crypto";
|
|
2957
3174
|
var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
2958
3175
|
var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
@@ -2965,10 +3182,10 @@ function computeProductionHash(projectRoot, refKey) {
|
|
|
2965
3182
|
const absPath = decodeURIComponent(
|
|
2966
3183
|
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
|
|
2967
3184
|
);
|
|
2968
|
-
toHash =
|
|
3185
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
2969
3186
|
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
2970
3187
|
const absPath = refKey.slice(FS_PREFIX.length - 1);
|
|
2971
|
-
toHash =
|
|
3188
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
2972
3189
|
} else if (refKey.startsWith("/")) {
|
|
2973
3190
|
toHash = refKey.slice(1);
|
|
2974
3191
|
} else {
|
|
@@ -3107,10 +3324,10 @@ function createDiscoveryState(entryPath, opts) {
|
|
|
3107
3324
|
perRouterTrieMap: /* @__PURE__ */ new Map(),
|
|
3108
3325
|
perRouterPrecomputedMap: /* @__PURE__ */ new Map(),
|
|
3109
3326
|
perRouterManifestDataMap: /* @__PURE__ */ new Map(),
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3327
|
+
prerenderManifestEntries: null,
|
|
3328
|
+
staticManifestEntries: null,
|
|
3329
|
+
handlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3330
|
+
staticHandlerChunkInfoMap: /* @__PURE__ */ new Map(),
|
|
3114
3331
|
rscEntryFileName: null,
|
|
3115
3332
|
resolvedPrerenderModules: void 0,
|
|
3116
3333
|
resolvedStaticModules: void 0,
|
|
@@ -3193,8 +3410,17 @@ function jsonParseExpression(value) {
|
|
|
3193
3410
|
}
|
|
3194
3411
|
|
|
3195
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
|
+
}
|
|
3196
3422
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3197
|
-
function contextSet(variables, keyOrVar, value) {
|
|
3423
|
+
function contextSet(variables, keyOrVar, value, options) {
|
|
3198
3424
|
if (typeof keyOrVar === "string") {
|
|
3199
3425
|
if (FORBIDDEN_KEYS.has(keyOrVar)) {
|
|
3200
3426
|
throw new Error(
|
|
@@ -3202,12 +3428,28 @@ function contextSet(variables, keyOrVar, value) {
|
|
|
3202
3428
|
);
|
|
3203
3429
|
}
|
|
3204
3430
|
variables[keyOrVar] = value;
|
|
3431
|
+
if (options?.cache === false) {
|
|
3432
|
+
getNonCacheableKeys(variables).add(keyOrVar);
|
|
3433
|
+
}
|
|
3205
3434
|
} else {
|
|
3206
3435
|
variables[keyOrVar.key] = value;
|
|
3436
|
+
if (options?.cache === false) {
|
|
3437
|
+
getNonCacheableKeys(variables).add(keyOrVar.key);
|
|
3438
|
+
}
|
|
3207
3439
|
}
|
|
3208
3440
|
}
|
|
3209
3441
|
|
|
3210
3442
|
// src/vite/utils/prerender-utils.ts
|
|
3443
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
3444
|
+
import {
|
|
3445
|
+
copyFileSync,
|
|
3446
|
+
existsSync as existsSync4,
|
|
3447
|
+
mkdirSync,
|
|
3448
|
+
rmSync,
|
|
3449
|
+
statSync,
|
|
3450
|
+
writeFileSync as writeFileSync2
|
|
3451
|
+
} from "node:fs";
|
|
3452
|
+
import { resolve as resolve5 } from "node:path";
|
|
3211
3453
|
function escapeRegExp2(str) {
|
|
3212
3454
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3213
3455
|
}
|
|
@@ -3216,6 +3458,7 @@ function encodePathParam(value) {
|
|
|
3216
3458
|
}
|
|
3217
3459
|
function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
3218
3460
|
let result = pattern;
|
|
3461
|
+
let hadOmittedOptional = false;
|
|
3219
3462
|
for (const [key, value] of Object.entries(params)) {
|
|
3220
3463
|
const escaped = escapeRegExp2(key);
|
|
3221
3464
|
result = result.replace(
|
|
@@ -3224,6 +3467,15 @@ function substituteRouteParams(pattern, params, encode = encodeURIComponent) {
|
|
|
3224
3467
|
);
|
|
3225
3468
|
result = result.replace(`*${key}`, encode(value));
|
|
3226
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
|
+
}
|
|
3227
3479
|
return result;
|
|
3228
3480
|
}
|
|
3229
3481
|
async function runWithConcurrency(items, concurrency, fn) {
|
|
@@ -3286,6 +3538,37 @@ function notifyOnError(registry, error, phase, routeKey, pathname, skipped) {
|
|
|
3286
3538
|
break;
|
|
3287
3539
|
}
|
|
3288
3540
|
}
|
|
3541
|
+
function getStagedAssetDir(projectRoot) {
|
|
3542
|
+
return resolve5(projectRoot, "node_modules/.rangojs-router-build/rsc-assets");
|
|
3543
|
+
}
|
|
3544
|
+
function resetStagedBuildAssets(projectRoot) {
|
|
3545
|
+
rmSync(getStagedAssetDir(projectRoot), { recursive: true, force: true });
|
|
3546
|
+
}
|
|
3547
|
+
function stageBuildAssetModule(projectRoot, prefix, exportValue) {
|
|
3548
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
3549
|
+
mkdirSync(stagedDir, { recursive: true });
|
|
3550
|
+
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
3551
|
+
const fileName = `${prefix}-${contentHash}.js`;
|
|
3552
|
+
const filePath = resolve5(stagedDir, fileName);
|
|
3553
|
+
if (!existsSync4(filePath)) {
|
|
3554
|
+
writeFileSync2(filePath, `export default ${exportValue};
|
|
3555
|
+
`);
|
|
3556
|
+
}
|
|
3557
|
+
return fileName;
|
|
3558
|
+
}
|
|
3559
|
+
function copyStagedBuildAssets(projectRoot, fileNames) {
|
|
3560
|
+
const stagedDir = getStagedAssetDir(projectRoot);
|
|
3561
|
+
const distAssetsDir = resolve5(projectRoot, "dist/rsc/assets");
|
|
3562
|
+
mkdirSync(distAssetsDir, { recursive: true });
|
|
3563
|
+
let totalBytes = 0;
|
|
3564
|
+
for (const fileName of new Set(fileNames)) {
|
|
3565
|
+
const stagedPath = resolve5(stagedDir, fileName);
|
|
3566
|
+
const distPath = resolve5(distAssetsDir, fileName);
|
|
3567
|
+
copyFileSync(stagedPath, distPath);
|
|
3568
|
+
totalBytes += statSync(stagedPath).size;
|
|
3569
|
+
}
|
|
3570
|
+
return totalBytes;
|
|
3571
|
+
}
|
|
3289
3572
|
|
|
3290
3573
|
// src/vite/discovery/prerender-collection.ts
|
|
3291
3574
|
async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
@@ -3304,11 +3587,12 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3304
3587
|
for (const { manifest } of allManifests) {
|
|
3305
3588
|
if (!manifest.prerenderRoutes) continue;
|
|
3306
3589
|
const defs = manifest._prerenderDefs || {};
|
|
3590
|
+
const passthroughSet = new Set(manifest.passthroughRoutes || []);
|
|
3307
3591
|
for (const routeName of manifest.prerenderRoutes) {
|
|
3308
3592
|
const pattern = manifest.routeManifest[routeName];
|
|
3309
3593
|
if (!pattern) continue;
|
|
3310
3594
|
const def = defs[routeName];
|
|
3311
|
-
const isPassthroughRoute =
|
|
3595
|
+
const isPassthroughRoute = passthroughSet.has(routeName);
|
|
3312
3596
|
const hasDynamic = pattern.includes(":") || pattern.includes("*");
|
|
3313
3597
|
if (!hasDynamic) {
|
|
3314
3598
|
entries.push({
|
|
@@ -3321,12 +3605,20 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3321
3605
|
if (def?.getParams) {
|
|
3322
3606
|
try {
|
|
3323
3607
|
const buildVars = {};
|
|
3608
|
+
const buildEnv = state.resolvedBuildEnv;
|
|
3324
3609
|
const getParamsCtx = {
|
|
3325
3610
|
build: true,
|
|
3611
|
+
dev: !state.isBuildMode,
|
|
3326
3612
|
set: ((keyOrVar, value) => {
|
|
3327
3613
|
contextSet(buildVars, keyOrVar, value);
|
|
3328
3614
|
}),
|
|
3329
|
-
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
|
+
}
|
|
3330
3622
|
};
|
|
3331
3623
|
const paramsList = await def.getParams(getParamsCtx);
|
|
3332
3624
|
const concurrency = def.options?.concurrency ?? 1;
|
|
@@ -3387,7 +3679,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3387
3679
|
`[rsc-router] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`
|
|
3388
3680
|
);
|
|
3389
3681
|
const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
|
|
3390
|
-
const
|
|
3682
|
+
const manifestEntries = {};
|
|
3391
3683
|
let doneCount = 0;
|
|
3392
3684
|
let skipCount = 0;
|
|
3393
3685
|
const startTotal = performance.now();
|
|
@@ -3405,7 +3697,8 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3405
3697
|
entry.urlPath,
|
|
3406
3698
|
{},
|
|
3407
3699
|
entry.buildVars,
|
|
3408
|
-
entry.isPassthroughRoute
|
|
3700
|
+
entry.isPassthroughRoute,
|
|
3701
|
+
state.resolvedBuildEnv
|
|
3409
3702
|
);
|
|
3410
3703
|
if (!result) continue;
|
|
3411
3704
|
if (result.passthrough) {
|
|
@@ -3417,18 +3710,30 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3417
3710
|
break;
|
|
3418
3711
|
}
|
|
3419
3712
|
const paramHash = hashParams(result.params || {});
|
|
3420
|
-
|
|
3713
|
+
const mainKey = `${result.routeName}/${paramHash}`;
|
|
3714
|
+
const mainValue = JSON.stringify({
|
|
3421
3715
|
segments: result.segments,
|
|
3422
3716
|
handles: result.handles
|
|
3423
|
-
};
|
|
3717
|
+
});
|
|
3718
|
+
manifestEntries[mainKey] = stageBuildAssetModule(
|
|
3719
|
+
state.projectRoot,
|
|
3720
|
+
"__pr",
|
|
3721
|
+
mainValue
|
|
3722
|
+
);
|
|
3424
3723
|
if (result.interceptSegments?.length) {
|
|
3425
|
-
|
|
3724
|
+
const interceptKey = `${result.routeName}/${paramHash}/i`;
|
|
3725
|
+
const interceptValue = JSON.stringify({
|
|
3426
3726
|
segments: [...result.segments, ...result.interceptSegments],
|
|
3427
3727
|
handles: {
|
|
3428
3728
|
...result.handles,
|
|
3429
3729
|
...result.interceptHandles || {}
|
|
3430
3730
|
}
|
|
3431
|
-
};
|
|
3731
|
+
});
|
|
3732
|
+
manifestEntries[interceptKey] = stageBuildAssetModule(
|
|
3733
|
+
state.projectRoot,
|
|
3734
|
+
"__pr",
|
|
3735
|
+
interceptValue
|
|
3736
|
+
);
|
|
3432
3737
|
}
|
|
3433
3738
|
const elapsed = (performance.now() - startUrl).toFixed(0);
|
|
3434
3739
|
console.log(
|
|
@@ -3472,7 +3777,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3472
3777
|
}
|
|
3473
3778
|
const totalElapsed = (performance.now() - startTotal).toFixed(0);
|
|
3474
3779
|
if (doneCount > 0) {
|
|
3475
|
-
state.
|
|
3780
|
+
state.prerenderManifestEntries = manifestEntries;
|
|
3476
3781
|
}
|
|
3477
3782
|
const parts = [`${doneCount} done`];
|
|
3478
3783
|
if (skipCount > 0) parts.push(`${skipCount} skipped`);
|
|
@@ -3483,7 +3788,7 @@ async function expandPrerenderRoutes(state, rscEnv, registry, allManifests) {
|
|
|
3483
3788
|
async function renderStaticHandlers(state, rscEnv, registry) {
|
|
3484
3789
|
if (!state.opts?.enableBuildPrerender || !state.isBuildMode || !state.resolvedStaticModules?.size)
|
|
3485
3790
|
return;
|
|
3486
|
-
const
|
|
3791
|
+
const manifestEntries = {};
|
|
3487
3792
|
let staticDone = 0;
|
|
3488
3793
|
let staticSkip = 0;
|
|
3489
3794
|
let totalStaticCount = 0;
|
|
@@ -3517,10 +3822,18 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3517
3822
|
const result = await routerInstance.renderStaticSegment(
|
|
3518
3823
|
def.handler,
|
|
3519
3824
|
def.$$id,
|
|
3520
|
-
def.$$routePrefix
|
|
3825
|
+
def.$$routePrefix,
|
|
3826
|
+
state.resolvedBuildEnv,
|
|
3827
|
+
!state.isBuildMode
|
|
3521
3828
|
);
|
|
3522
3829
|
if (result) {
|
|
3523
|
-
|
|
3830
|
+
const hasHandles = Object.keys(result.handles).length > 0;
|
|
3831
|
+
const exportValue = hasHandles ? JSON.stringify(result) : JSON.stringify(result.encoded);
|
|
3832
|
+
manifestEntries[def.$$id] = stageBuildAssetModule(
|
|
3833
|
+
state.projectRoot,
|
|
3834
|
+
"__st",
|
|
3835
|
+
exportValue
|
|
3836
|
+
);
|
|
3524
3837
|
const elapsed = (performance.now() - startHandler).toFixed(0);
|
|
3525
3838
|
console.log(
|
|
3526
3839
|
`[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`
|
|
@@ -3557,7 +3870,7 @@ async function renderStaticHandlers(state, rscEnv, registry) {
|
|
|
3557
3870
|
}
|
|
3558
3871
|
const totalStaticElapsed = (performance.now() - startStatic).toFixed(0);
|
|
3559
3872
|
if (staticDone > 0) {
|
|
3560
|
-
state.
|
|
3873
|
+
state.staticManifestEntries = manifestEntries;
|
|
3561
3874
|
}
|
|
3562
3875
|
const staticParts = [`${staticDone} done`];
|
|
3563
3876
|
if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
|
|
@@ -3574,8 +3887,7 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3574
3887
|
let registry = serverMod.RouterRegistry;
|
|
3575
3888
|
if (!registry || registry.size === 0) {
|
|
3576
3889
|
try {
|
|
3577
|
-
const
|
|
3578
|
-
const hostRegistry = hostMod.HostRouterRegistry;
|
|
3890
|
+
const hostRegistry = serverMod.HostRouterRegistry;
|
|
3579
3891
|
if (hostRegistry && hostRegistry.size > 0) {
|
|
3580
3892
|
console.log(
|
|
3581
3893
|
`[rsc-router] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
|
|
@@ -3615,6 +3927,14 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3615
3927
|
}
|
|
3616
3928
|
const buildMod = await rscEnv.runner.import("@rangojs/router/build");
|
|
3617
3929
|
const generateManifestFull = buildMod.generateManifestFull;
|
|
3930
|
+
const nestedRouterConflict = findNestedRouterConflict(
|
|
3931
|
+
[...registry.values()].map((router) => router.__sourceFile).filter(
|
|
3932
|
+
(sourceFile) => typeof sourceFile === "string"
|
|
3933
|
+
)
|
|
3934
|
+
);
|
|
3935
|
+
if (nestedRouterConflict) {
|
|
3936
|
+
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
3937
|
+
}
|
|
3618
3938
|
const newMergedRouteManifest = {};
|
|
3619
3939
|
const newMergedPrecomputedEntries = [];
|
|
3620
3940
|
const newPerRouterManifests = [];
|
|
@@ -3629,7 +3949,11 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3629
3949
|
if (!router.urlpatterns || !generateManifestFull) {
|
|
3630
3950
|
continue;
|
|
3631
3951
|
}
|
|
3632
|
-
const manifest = generateManifestFull(
|
|
3952
|
+
const manifest = generateManifestFull(
|
|
3953
|
+
router.urlpatterns,
|
|
3954
|
+
routerMountIndex,
|
|
3955
|
+
router.__basename ? { urlPrefix: router.__basename } : void 0
|
|
3956
|
+
);
|
|
3633
3957
|
routerMountIndex++;
|
|
3634
3958
|
allManifests.push({ id, manifest });
|
|
3635
3959
|
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
@@ -3771,8 +4095,8 @@ async function discoverRouters(state, rscEnv) {
|
|
|
3771
4095
|
}
|
|
3772
4096
|
|
|
3773
4097
|
// src/vite/discovery/route-types-writer.ts
|
|
3774
|
-
import { dirname as dirname3, basename, join as
|
|
3775
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
4098
|
+
import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
|
|
4099
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
3776
4100
|
function filterUserNamedRoutes(manifest) {
|
|
3777
4101
|
const filtered = {};
|
|
3778
4102
|
for (const [name, pattern] of Object.entries(manifest)) {
|
|
@@ -3792,7 +4116,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3792
4116
|
/\.(tsx?|jsx?)$/,
|
|
3793
4117
|
""
|
|
3794
4118
|
);
|
|
3795
|
-
const outPath =
|
|
4119
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3796
4120
|
try {
|
|
3797
4121
|
preContent.set(outPath, readFileSync4(outPath, "utf-8"));
|
|
3798
4122
|
} catch {
|
|
@@ -3805,8 +4129,8 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
|
|
|
3805
4129
|
/\.(tsx?|jsx?)$/,
|
|
3806
4130
|
""
|
|
3807
4131
|
);
|
|
3808
|
-
const outPath =
|
|
3809
|
-
if (!
|
|
4132
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
4133
|
+
if (!existsSync5(outPath)) continue;
|
|
3810
4134
|
try {
|
|
3811
4135
|
const content = readFileSync4(outPath, "utf-8");
|
|
3812
4136
|
if (content !== preContent.get(outPath)) {
|
|
@@ -3820,10 +4144,10 @@ function writeRouteTypesFiles(state) {
|
|
|
3820
4144
|
if (state.perRouterManifests.length === 0) return;
|
|
3821
4145
|
try {
|
|
3822
4146
|
const entryDir = dirname3(
|
|
3823
|
-
|
|
4147
|
+
resolve6(state.projectRoot, state.resolvedEntryPath)
|
|
3824
4148
|
);
|
|
3825
|
-
const oldCombinedPath =
|
|
3826
|
-
if (
|
|
4149
|
+
const oldCombinedPath = join2(entryDir, "named-routes.gen.ts");
|
|
4150
|
+
if (existsSync5(oldCombinedPath)) {
|
|
3827
4151
|
unlinkSync2(oldCombinedPath);
|
|
3828
4152
|
console.log(
|
|
3829
4153
|
`[rsc-router] Removed stale combined route types: ${oldCombinedPath}`
|
|
@@ -3847,7 +4171,7 @@ Set an explicit \`id\` on createRouter() or check the call site.`
|
|
|
3847
4171
|
}
|
|
3848
4172
|
const routerDir = dirname3(sourceFile);
|
|
3849
4173
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
3850
|
-
const outPath =
|
|
4174
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3851
4175
|
const userRoutes = filterUserNamedRoutes(routeManifest);
|
|
3852
4176
|
let effectiveSearchSchemas = routeSearchSchemas;
|
|
3853
4177
|
if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
|
|
@@ -3867,10 +4191,10 @@ Set an explicit \`id\` on createRouter() or check the call site.`
|
|
|
3867
4191
|
userRoutes,
|
|
3868
4192
|
effectiveSearchSchemas && Object.keys(effectiveSearchSchemas).length > 0 ? effectiveSearchSchemas : void 0
|
|
3869
4193
|
);
|
|
3870
|
-
const existing =
|
|
4194
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
3871
4195
|
if (existing !== source) {
|
|
3872
4196
|
markSelfGenWrite(state, outPath, source);
|
|
3873
|
-
|
|
4197
|
+
writeFileSync3(outPath, source);
|
|
3874
4198
|
console.log(`[rsc-router] Generated route types -> ${outPath}`);
|
|
3875
4199
|
}
|
|
3876
4200
|
}
|
|
@@ -3912,21 +4236,21 @@ function supplementGenFilesWithRuntimeRoutes(state) {
|
|
|
3912
4236
|
}
|
|
3913
4237
|
const routerDir = dirname3(sourceFile);
|
|
3914
4238
|
const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
3915
|
-
const outPath =
|
|
4239
|
+
const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
|
|
3916
4240
|
const source = generateRouteTypesSource(
|
|
3917
4241
|
mergedRoutes,
|
|
3918
4242
|
Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
|
|
3919
4243
|
);
|
|
3920
|
-
const existing =
|
|
4244
|
+
const existing = existsSync5(outPath) ? readFileSync4(outPath, "utf-8") : null;
|
|
3921
4245
|
if (existing !== source) {
|
|
3922
4246
|
markSelfGenWrite(state, outPath, source);
|
|
3923
|
-
|
|
4247
|
+
writeFileSync3(outPath, source);
|
|
3924
4248
|
}
|
|
3925
4249
|
}
|
|
3926
4250
|
}
|
|
3927
4251
|
|
|
3928
4252
|
// src/vite/discovery/virtual-module-codegen.ts
|
|
3929
|
-
import { dirname as dirname4, basename as basename2, join as
|
|
4253
|
+
import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
|
|
3930
4254
|
function generateRoutesManifestModule(state) {
|
|
3931
4255
|
const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
|
|
3932
4256
|
if (hasManifest) {
|
|
@@ -3941,7 +4265,7 @@ function generateRoutesManifestModule(state) {
|
|
|
3941
4265
|
/\.(tsx?|jsx?)$/,
|
|
3942
4266
|
""
|
|
3943
4267
|
);
|
|
3944
|
-
const genPath =
|
|
4268
|
+
const genPath = join3(
|
|
3945
4269
|
routerDir,
|
|
3946
4270
|
`${routerBasename}.named-routes.gen.js`
|
|
3947
4271
|
).replaceAll("\\", "/");
|
|
@@ -4038,7 +4362,7 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4038
4362
|
/\.(tsx?|jsx?)$/,
|
|
4039
4363
|
""
|
|
4040
4364
|
);
|
|
4041
|
-
const genPath =
|
|
4365
|
+
const genPath = join3(
|
|
4042
4366
|
routerDir,
|
|
4043
4367
|
`${routerBasename}.named-routes.gen.js`
|
|
4044
4368
|
).replaceAll("\\", "/");
|
|
@@ -4065,100 +4389,90 @@ function generatePerRouterModule(state, routerId) {
|
|
|
4065
4389
|
}
|
|
4066
4390
|
|
|
4067
4391
|
// src/vite/discovery/bundle-postprocess.ts
|
|
4068
|
-
import { resolve as
|
|
4069
|
-
import {
|
|
4070
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync } from "node:fs";
|
|
4392
|
+
import { resolve as resolve7 } from "node:path";
|
|
4393
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6 } from "node:fs";
|
|
4071
4394
|
function postprocessBundle(state) {
|
|
4072
|
-
const hasPrerenderData = state.
|
|
4073
|
-
const hasStaticData = state.
|
|
4395
|
+
const hasPrerenderData = state.prerenderManifestEntries && Object.keys(state.prerenderManifestEntries).length > 0;
|
|
4396
|
+
const hasStaticData = state.staticManifestEntries && Object.keys(state.staticManifestEntries).length > 0;
|
|
4074
4397
|
if (!hasPrerenderData && !hasStaticData) return;
|
|
4075
|
-
const rscEntryPath =
|
|
4398
|
+
const rscEntryPath = resolve7(
|
|
4076
4399
|
state.projectRoot,
|
|
4077
4400
|
"dist/rsc",
|
|
4078
4401
|
state.rscEntryFileName ?? "index.js"
|
|
4079
4402
|
);
|
|
4080
4403
|
const evictionTargets = [
|
|
4081
4404
|
{
|
|
4082
|
-
|
|
4405
|
+
infos: state.handlerChunkInfoMap.values(),
|
|
4083
4406
|
fnName: "Prerender",
|
|
4084
4407
|
brand: "prerenderHandler",
|
|
4085
4408
|
label: "handler code from RSC bundle"
|
|
4086
4409
|
},
|
|
4087
4410
|
{
|
|
4088
|
-
|
|
4411
|
+
infos: state.staticHandlerChunkInfoMap.values(),
|
|
4089
4412
|
fnName: "Static",
|
|
4090
4413
|
brand: "staticHandler",
|
|
4091
4414
|
label: "static handler code"
|
|
4092
4415
|
}
|
|
4093
4416
|
];
|
|
4094
4417
|
for (const target of evictionTargets) {
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
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}`
|
|
4114
4438
|
);
|
|
4115
4439
|
}
|
|
4116
|
-
} catch (replaceErr) {
|
|
4117
|
-
console.warn(
|
|
4118
|
-
`[rsc-router] Failed to evict ${target.label}: ${replaceErr.message}`
|
|
4119
|
-
);
|
|
4120
4440
|
}
|
|
4121
4441
|
}
|
|
4122
|
-
state.
|
|
4123
|
-
state.
|
|
4124
|
-
if (hasPrerenderData &&
|
|
4442
|
+
state.handlerChunkInfoMap.clear();
|
|
4443
|
+
state.staticHandlerChunkInfoMap.clear();
|
|
4444
|
+
if (hasPrerenderData && existsSync6(rscEntryPath)) {
|
|
4125
4445
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4126
4446
|
if (!rscCode.includes("__prerender-manifest.js")) {
|
|
4127
4447
|
try {
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4448
|
+
let totalBytes = copyStagedBuildAssets(
|
|
4449
|
+
state.projectRoot,
|
|
4450
|
+
Object.values(state.prerenderManifestEntries)
|
|
4451
|
+
);
|
|
4452
|
+
const manifestMap = {};
|
|
4453
|
+
for (const [key, assetFileName] of Object.entries(
|
|
4454
|
+
state.prerenderManifestEntries
|
|
4134
4455
|
)) {
|
|
4135
|
-
|
|
4136
|
-
const contentHash = createHash4("sha256").update(entryJson).digest("hex").slice(0, 8);
|
|
4137
|
-
const assetFileName = `__pr-${contentHash}.js`;
|
|
4138
|
-
const assetPath = resolve6(assetsDir, assetFileName);
|
|
4139
|
-
const assetCode = `export default ${entryJson};
|
|
4140
|
-
`;
|
|
4141
|
-
writeFileSync3(assetPath, assetCode);
|
|
4142
|
-
totalBytes += Buffer.byteLength(assetCode);
|
|
4143
|
-
manifestEntries.push(
|
|
4144
|
-
`${JSON.stringify(key)}:()=>import("./assets/${assetFileName}")`
|
|
4145
|
-
);
|
|
4456
|
+
manifestMap[key] = `./assets/${assetFileName}`;
|
|
4146
4457
|
}
|
|
4147
|
-
const manifestCode =
|
|
4148
|
-
|
|
4149
|
-
|
|
4458
|
+
const manifestCode = [
|
|
4459
|
+
`const m=JSON.parse('${JSON.stringify(manifestMap).replace(/'/g, "\\'")}');`,
|
|
4460
|
+
`export function loadPrerenderAsset(s){return import(s)}`,
|
|
4461
|
+
`export default m;`,
|
|
4462
|
+
""
|
|
4463
|
+
].join("\n");
|
|
4464
|
+
const manifestPath = resolve7(
|
|
4150
4465
|
state.projectRoot,
|
|
4151
4466
|
"dist/rsc/__prerender-manifest.js"
|
|
4152
4467
|
);
|
|
4153
|
-
|
|
4468
|
+
writeFileSync4(manifestPath, manifestCode);
|
|
4154
4469
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
4155
|
-
const injection = `
|
|
4156
|
-
globalThis.__PRERENDER_MANIFEST = __pm;
|
|
4470
|
+
const injection = `globalThis.__loadPrerenderManifestModule = () => import("./__prerender-manifest.js");
|
|
4157
4471
|
`;
|
|
4158
|
-
|
|
4472
|
+
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4159
4473
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4160
4474
|
console.log(
|
|
4161
|
-
`[rsc-router] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.
|
|
4475
|
+
`[rsc-router] Wrote prerender assets (${totalKB} KB total, ${Object.keys(state.prerenderManifestEntries).length} entries)`
|
|
4162
4476
|
);
|
|
4163
4477
|
} catch (err) {
|
|
4164
4478
|
throw new Error(
|
|
@@ -4167,44 +4481,36 @@ globalThis.__PRERENDER_MANIFEST = __pm;
|
|
|
4167
4481
|
}
|
|
4168
4482
|
}
|
|
4169
4483
|
}
|
|
4170
|
-
if (hasStaticData &&
|
|
4484
|
+
if (hasStaticData && existsSync6(rscEntryPath)) {
|
|
4171
4485
|
const rscCode = readFileSync5(rscEntryPath, "utf-8");
|
|
4172
|
-
if (!rscCode.includes("
|
|
4486
|
+
if (!rscCode.includes("__static-manifest.js")) {
|
|
4173
4487
|
try {
|
|
4174
|
-
const assetsDir = resolve6(state.projectRoot, "dist/rsc/assets");
|
|
4175
|
-
mkdirSync(assetsDir, { recursive: true });
|
|
4176
4488
|
const manifestEntries = [];
|
|
4177
|
-
let totalBytes =
|
|
4178
|
-
|
|
4179
|
-
state.
|
|
4489
|
+
let totalBytes = copyStagedBuildAssets(
|
|
4490
|
+
state.projectRoot,
|
|
4491
|
+
Object.values(state.staticManifestEntries)
|
|
4492
|
+
);
|
|
4493
|
+
for (const [handlerId, assetFileName] of Object.entries(
|
|
4494
|
+
state.staticManifestEntries
|
|
4180
4495
|
)) {
|
|
4181
|
-
const hasHandles = Object.keys(handles).length > 0;
|
|
4182
|
-
const exportValue = hasHandles ? JSON.stringify({ encoded, handles }) : JSON.stringify(encoded);
|
|
4183
|
-
const contentHash = createHash4("sha256").update(exportValue).digest("hex").slice(0, 8);
|
|
4184
|
-
const assetFileName = `__st-${contentHash}.js`;
|
|
4185
|
-
const assetPath = resolve6(assetsDir, assetFileName);
|
|
4186
|
-
const assetCode = `export default ${exportValue};
|
|
4187
|
-
`;
|
|
4188
|
-
writeFileSync3(assetPath, assetCode);
|
|
4189
|
-
totalBytes += Buffer.byteLength(assetCode);
|
|
4190
4496
|
manifestEntries.push(
|
|
4191
4497
|
`${JSON.stringify(handlerId)}:()=>import("./assets/${assetFileName}")`
|
|
4192
4498
|
);
|
|
4193
4499
|
}
|
|
4194
4500
|
const manifestCode = `const m={${manifestEntries.join(",")}};globalThis.__STATIC_MANIFEST=m;export default m;
|
|
4195
4501
|
`;
|
|
4196
|
-
const manifestPath =
|
|
4502
|
+
const manifestPath = resolve7(
|
|
4197
4503
|
state.projectRoot,
|
|
4198
4504
|
"dist/rsc/__static-manifest.js"
|
|
4199
4505
|
);
|
|
4200
|
-
|
|
4506
|
+
writeFileSync4(manifestPath, manifestCode);
|
|
4201
4507
|
totalBytes += Buffer.byteLength(manifestCode);
|
|
4202
4508
|
const injection = `import "./__static-manifest.js";
|
|
4203
4509
|
`;
|
|
4204
|
-
|
|
4510
|
+
writeFileSync4(rscEntryPath, injection + rscCode);
|
|
4205
4511
|
const totalKB = (totalBytes / 1024).toFixed(1);
|
|
4206
4512
|
console.log(
|
|
4207
|
-
`[rsc-router] Wrote static assets (${totalKB} KB total, ${Object.keys(state.
|
|
4513
|
+
`[rsc-router] Wrote static assets (${totalKB} KB total, ${Object.keys(state.staticManifestEntries).length} entries)`
|
|
4208
4514
|
);
|
|
4209
4515
|
} catch (err) {
|
|
4210
4516
|
throw new Error(
|
|
@@ -4246,8 +4552,67 @@ async function createTempRscServer(state, options = {}) {
|
|
|
4246
4552
|
]
|
|
4247
4553
|
});
|
|
4248
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
|
+
}
|
|
4249
4612
|
function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
4250
4613
|
const s = createDiscoveryState(entryPath, opts);
|
|
4614
|
+
let viteCommand = "build";
|
|
4615
|
+
let viteMode = "production";
|
|
4251
4616
|
return {
|
|
4252
4617
|
name: "@rangojs/router:discovery",
|
|
4253
4618
|
config() {
|
|
@@ -4256,31 +4621,13 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4256
4621
|
__RANGO_DEBUG__: JSON.stringify(!!process.env.INTERNAL_RANGO_DEBUG)
|
|
4257
4622
|
}
|
|
4258
4623
|
};
|
|
4259
|
-
if (opts?.enableBuildPrerender) {
|
|
4260
|
-
config.environments = {
|
|
4261
|
-
rsc: {
|
|
4262
|
-
build: {
|
|
4263
|
-
rollupOptions: {
|
|
4264
|
-
output: {
|
|
4265
|
-
manualChunks(id) {
|
|
4266
|
-
if (s.resolvedPrerenderModules?.has(id)) {
|
|
4267
|
-
return "__prerender-handlers";
|
|
4268
|
-
}
|
|
4269
|
-
if (s.resolvedStaticModules?.has(id)) {
|
|
4270
|
-
return "__static-handlers";
|
|
4271
|
-
}
|
|
4272
|
-
}
|
|
4273
|
-
}
|
|
4274
|
-
}
|
|
4275
|
-
}
|
|
4276
|
-
}
|
|
4277
|
-
};
|
|
4278
|
-
}
|
|
4279
4624
|
return config;
|
|
4280
4625
|
},
|
|
4281
4626
|
configResolved(config) {
|
|
4282
4627
|
s.projectRoot = config.root;
|
|
4283
4628
|
s.isBuildMode = config.command === "build";
|
|
4629
|
+
viteCommand = config.command;
|
|
4630
|
+
viteMode = config.mode;
|
|
4284
4631
|
s.userResolveAlias = config.resolve.alias;
|
|
4285
4632
|
if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
|
|
4286
4633
|
s.resolvedEntryPath = opts.routerPathRef.path;
|
|
@@ -4294,12 +4641,6 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4294
4641
|
s.resolvedEntryPath = entries[0];
|
|
4295
4642
|
}
|
|
4296
4643
|
}
|
|
4297
|
-
if (opts?.include || opts?.exclude) {
|
|
4298
|
-
s.scanFilter = createScanFilter(s.projectRoot, {
|
|
4299
|
-
include: opts.include,
|
|
4300
|
-
exclude: opts.exclude
|
|
4301
|
-
});
|
|
4302
|
-
}
|
|
4303
4644
|
if (opts?.staticRouteTypesGeneration !== false) {
|
|
4304
4645
|
s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
|
|
4305
4646
|
writeCombinedRouteTypesWithTracking(s, { preserveIfLarger: true });
|
|
@@ -4319,8 +4660,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4319
4660
|
if (globalThis.__rscRouterDiscoveryActive) return;
|
|
4320
4661
|
s.devServer = server;
|
|
4321
4662
|
let resolveDiscovery;
|
|
4322
|
-
const discoveryPromise = new Promise((
|
|
4323
|
-
resolveDiscovery =
|
|
4663
|
+
const discoveryPromise = new Promise((resolve10) => {
|
|
4664
|
+
resolveDiscovery = resolve10;
|
|
4324
4665
|
});
|
|
4325
4666
|
const getDevServerOrigin = () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, "") || `http://localhost:${server.config.server.port || 5173}`;
|
|
4326
4667
|
let prerenderTempServer = null;
|
|
@@ -4331,6 +4672,8 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4331
4672
|
});
|
|
4332
4673
|
prerenderTempServer = null;
|
|
4333
4674
|
}
|
|
4675
|
+
releaseBuildEnv(s).catch(() => {
|
|
4676
|
+
});
|
|
4334
4677
|
});
|
|
4335
4678
|
async function getOrCreateTempServer() {
|
|
4336
4679
|
if (prerenderNodeRegistry) {
|
|
@@ -4361,6 +4704,7 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
|
|
|
4361
4704
|
if (!rscEnv?.runner) {
|
|
4362
4705
|
s.devServerOrigin = getDevServerOrigin();
|
|
4363
4706
|
try {
|
|
4707
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4364
4708
|
const tempRscEnv = await getOrCreateTempServer();
|
|
4365
4709
|
if (tempRscEnv) {
|
|
4366
4710
|
await discoverRouters(s, tempRscEnv);
|
|
@@ -4376,6 +4720,7 @@ ${err.stack}`
|
|
|
4376
4720
|
return;
|
|
4377
4721
|
}
|
|
4378
4722
|
try {
|
|
4723
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4379
4724
|
const serverMod = await rscEnv.runner.import(
|
|
4380
4725
|
"@rangojs/router/server"
|
|
4381
4726
|
);
|
|
@@ -4395,8 +4740,8 @@ ${err.stack}`
|
|
|
4395
4740
|
resolveDiscovery();
|
|
4396
4741
|
}
|
|
4397
4742
|
};
|
|
4398
|
-
s.discoveryDone = new Promise((
|
|
4399
|
-
setTimeout(() => discover().then(
|
|
4743
|
+
s.discoveryDone = new Promise((resolve10) => {
|
|
4744
|
+
setTimeout(() => discover().then(resolve10, resolve10), 0);
|
|
4400
4745
|
});
|
|
4401
4746
|
let mainRegistry = null;
|
|
4402
4747
|
const propagateDiscoveryState = async (rscEnv) => {
|
|
@@ -4462,7 +4807,10 @@ ${err.stack}`
|
|
|
4462
4807
|
pathname,
|
|
4463
4808
|
{},
|
|
4464
4809
|
void 0,
|
|
4465
|
-
wantPassthrough
|
|
4810
|
+
wantPassthrough,
|
|
4811
|
+
s.resolvedBuildEnv,
|
|
4812
|
+
true
|
|
4813
|
+
// devMode: check getParams for passthrough routes
|
|
4466
4814
|
);
|
|
4467
4815
|
if (!result) continue;
|
|
4468
4816
|
if (result.passthrough) continue;
|
|
@@ -4563,6 +4911,16 @@ ${err.stack}`
|
|
|
4563
4911
|
const hasCreateRouter = /\bcreateRouter\s*[<(]/.test(source);
|
|
4564
4912
|
if (!hasUrls && !hasCreateRouter) return;
|
|
4565
4913
|
if (hasCreateRouter) {
|
|
4914
|
+
const nestedRouterConflict = findNestedRouterConflict([
|
|
4915
|
+
...s.cachedRouterFiles ?? [],
|
|
4916
|
+
resolve8(filePath)
|
|
4917
|
+
]);
|
|
4918
|
+
if (nestedRouterConflict) {
|
|
4919
|
+
server.config.logger.error(
|
|
4920
|
+
formatNestedRouterConflictError(nestedRouterConflict)
|
|
4921
|
+
);
|
|
4922
|
+
return;
|
|
4923
|
+
}
|
|
4566
4924
|
s.cachedRouterFiles = void 0;
|
|
4567
4925
|
}
|
|
4568
4926
|
scheduleRouteRegeneration();
|
|
@@ -4585,6 +4943,10 @@ ${err.stack}`
|
|
|
4585
4943
|
async buildStart() {
|
|
4586
4944
|
if (!s.isBuildMode) return;
|
|
4587
4945
|
if (s.mergedRouteManifest !== null) return;
|
|
4946
|
+
resetStagedBuildAssets(s.projectRoot);
|
|
4947
|
+
s.prerenderManifestEntries = null;
|
|
4948
|
+
s.staticManifestEntries = null;
|
|
4949
|
+
await acquireBuildEnv(s, viteCommand, viteMode);
|
|
4588
4950
|
let tempServer = null;
|
|
4589
4951
|
globalThis.__rscRouterDiscoveryActive = true;
|
|
4590
4952
|
try {
|
|
@@ -4624,6 +4986,7 @@ ${details}`
|
|
|
4624
4986
|
if (tempServer) {
|
|
4625
4987
|
await tempServer.close();
|
|
4626
4988
|
}
|
|
4989
|
+
await releaseBuildEnv(s);
|
|
4627
4990
|
}
|
|
4628
4991
|
},
|
|
4629
4992
|
// Virtual module: provides the pre-generated route manifest as a JS module
|
|
@@ -4666,20 +5029,30 @@ ${details}`
|
|
|
4666
5029
|
}
|
|
4667
5030
|
if (!s.resolvedPrerenderModules?.size && !s.resolvedStaticModules?.size)
|
|
4668
5031
|
return;
|
|
5032
|
+
s.handlerChunkInfoMap.clear();
|
|
5033
|
+
s.staticHandlerChunkInfoMap.clear();
|
|
4669
5034
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
4670
5035
|
if (chunk.type !== "chunk") continue;
|
|
4671
|
-
if (
|
|
5036
|
+
if (s.resolvedPrerenderModules?.size) {
|
|
4672
5037
|
const handlers = extractHandlerExportsFromChunk(
|
|
4673
5038
|
chunk.code,
|
|
4674
5039
|
s.resolvedPrerenderModules,
|
|
4675
5040
|
"Prerender",
|
|
4676
|
-
|
|
5041
|
+
false
|
|
4677
5042
|
);
|
|
4678
5043
|
if (handlers.length > 0) {
|
|
4679
|
-
|
|
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
|
+
}
|
|
4680
5053
|
}
|
|
4681
5054
|
}
|
|
4682
|
-
if (
|
|
5055
|
+
if (s.resolvedStaticModules?.size) {
|
|
4683
5056
|
const handlers = extractHandlerExportsFromChunk(
|
|
4684
5057
|
chunk.code,
|
|
4685
5058
|
s.resolvedStaticModules,
|
|
@@ -4687,7 +5060,15 @@ ${details}`
|
|
|
4687
5060
|
false
|
|
4688
5061
|
);
|
|
4689
5062
|
if (handlers.length > 0) {
|
|
4690
|
-
|
|
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
|
+
}
|
|
4691
5072
|
}
|
|
4692
5073
|
}
|
|
4693
5074
|
}
|
|
@@ -4714,8 +5095,16 @@ async function rango(options) {
|
|
|
4714
5095
|
const showBanner = resolvedOptions.banner ?? true;
|
|
4715
5096
|
const plugins = [];
|
|
4716
5097
|
const rangoAliases = getPackageAliases();
|
|
4717
|
-
const excludeDeps =
|
|
4718
|
-
|
|
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
|
+
];
|
|
4719
5108
|
const routerRef = { path: void 0 };
|
|
4720
5109
|
const prerenderEnabled = true;
|
|
4721
5110
|
if (preset === "cloudflare") {
|
|
@@ -4811,160 +5200,132 @@ async function rango(options) {
|
|
|
4811
5200
|
}
|
|
4812
5201
|
});
|
|
4813
5202
|
plugins.push(createVirtualEntriesPlugin(finalEntries));
|
|
5203
|
+
plugins.push(performanceTracksPlugin());
|
|
4814
5204
|
plugins.push(
|
|
4815
5205
|
rsc({
|
|
4816
5206
|
entries: finalEntries,
|
|
4817
5207
|
serverHandler: false
|
|
4818
5208
|
})
|
|
4819
5209
|
);
|
|
5210
|
+
plugins.push(clientRefDedup());
|
|
4820
5211
|
} else {
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
const
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
|
|
4837
|
-
} else if (candidates.length > 1) {
|
|
4838
|
-
const list = candidates.map(
|
|
4839
|
-
(f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
|
|
4840
|
-
).join("\n");
|
|
4841
|
-
throw new Error(
|
|
4842
|
-
`[rsc-router] Multiple routers found. Specify \`router\` to choose one:
|
|
4843
|
-
${list}`
|
|
4844
|
-
);
|
|
4845
|
-
}
|
|
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}`);
|
|
4846
5227
|
}
|
|
4847
|
-
}
|
|
4848
|
-
}
|
|
4849
|
-
const
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
resolve: {
|
|
4878
|
-
alias: rangoAliases
|
|
4879
|
-
},
|
|
4880
|
-
environments: {
|
|
4881
|
-
client: {
|
|
4882
|
-
build: {
|
|
4883
|
-
rollupOptions: {
|
|
4884
|
-
output: {
|
|
4885
|
-
manualChunks: getManualChunks
|
|
4886
|
-
}
|
|
4887
|
-
}
|
|
4888
|
-
},
|
|
4889
|
-
// Always exclude rsc-router modules, conditionally add virtual entry
|
|
4890
|
-
optimizeDeps: {
|
|
4891
|
-
// Pre-bundle React and rsc-html-stream to prevent late discovery
|
|
4892
|
-
// triggering ERR_OUTDATED_OPTIMIZED_DEP on cold starts
|
|
4893
|
-
include: [
|
|
4894
|
-
"react",
|
|
4895
|
-
"react-dom",
|
|
4896
|
-
"react/jsx-runtime",
|
|
4897
|
-
"react/jsx-dev-runtime",
|
|
4898
|
-
"rsc-html-stream/client"
|
|
4899
|
-
],
|
|
4900
|
-
exclude: excludeDeps,
|
|
4901
|
-
esbuildOptions: sharedEsbuildOptions,
|
|
4902
|
-
...useVirtualClient && {
|
|
4903
|
-
// Tell Vite to scan the virtual entry for dependencies
|
|
4904
|
-
entries: [VIRTUAL_IDS.browser]
|
|
4905
|
-
}
|
|
4906
|
-
}
|
|
4907
|
-
},
|
|
4908
|
-
...useVirtualSSR && {
|
|
4909
|
-
ssr: {
|
|
4910
|
-
optimizeDeps: {
|
|
4911
|
-
entries: [VIRTUAL_IDS.ssr],
|
|
4912
|
-
// Pre-bundle all SSR deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
|
|
4913
|
-
include: [
|
|
4914
|
-
"react",
|
|
4915
|
-
"react-dom",
|
|
4916
|
-
"react-dom/server.edge",
|
|
4917
|
-
"react-dom/static.edge",
|
|
4918
|
-
"react/jsx-runtime",
|
|
4919
|
-
"react/jsx-dev-runtime",
|
|
4920
|
-
"@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
|
|
4921
|
-
],
|
|
4922
|
-
exclude: excludeDeps,
|
|
4923
|
-
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
|
|
4924
5258
|
}
|
|
4925
5259
|
}
|
|
4926
5260
|
},
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
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
|
|
4941
5300
|
}
|
|
4942
5301
|
}
|
|
4943
|
-
};
|
|
4944
|
-
},
|
|
4945
|
-
configResolved(config) {
|
|
4946
|
-
if (showBanner) {
|
|
4947
|
-
const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
|
|
4948
|
-
printBanner(mode, "node", rangoVersion);
|
|
4949
|
-
}
|
|
4950
|
-
const rscMinimalCount = config.plugins.filter(
|
|
4951
|
-
(p) => p.name === "rsc:minimal"
|
|
4952
|
-
).length;
|
|
4953
|
-
if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
|
|
4954
|
-
hasWarnedDuplicate = true;
|
|
4955
|
-
console.warn(
|
|
4956
|
-
"[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your config or use rango({ rsc: false }) for manual configuration."
|
|
4957
|
-
);
|
|
4958
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);
|
|
4959
5309
|
}
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
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
|
+
);
|
|
5328
|
+
plugins.push(clientRefDedup());
|
|
4968
5329
|
}
|
|
4969
5330
|
plugins.push({
|
|
4970
5331
|
name: "@rangojs/router:client-component-hmr",
|
|
@@ -4991,22 +5352,102 @@ ${list}`
|
|
|
4991
5352
|
plugins.push(createVersionPlugin());
|
|
4992
5353
|
const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
|
|
4993
5354
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
plugins.push(createVersionInjectorPlugin(injectorEntryPath));
|
|
5355
|
+
if (preset === "cloudflare") {
|
|
5356
|
+
plugins.push(createVersionInjectorPlugin(void 0));
|
|
4997
5357
|
}
|
|
4998
5358
|
plugins.push(createCjsToEsmPlugin());
|
|
4999
5359
|
plugins.push(
|
|
5000
5360
|
createRouterDiscoveryPlugin(discoveryEntryPath, {
|
|
5001
5361
|
routerPathRef: discoveryRouterRef,
|
|
5002
5362
|
enableBuildPrerender: prerenderEnabled,
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
exclude: resolvedOptions.exclude
|
|
5363
|
+
buildEnv: options?.buildEnv,
|
|
5364
|
+
preset
|
|
5006
5365
|
})
|
|
5007
5366
|
);
|
|
5008
5367
|
return plugins;
|
|
5009
5368
|
}
|
|
5369
|
+
|
|
5370
|
+
// src/vite/plugins/refresh-cmd.ts
|
|
5371
|
+
function poke() {
|
|
5372
|
+
return {
|
|
5373
|
+
name: "vite-plugin-poke",
|
|
5374
|
+
apply: "serve",
|
|
5375
|
+
configureServer(server) {
|
|
5376
|
+
const stdin = process.stdin;
|
|
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
|
+
}
|
|
5416
|
+
if (stdin.isTTY) {
|
|
5417
|
+
server.config.logger.info(
|
|
5418
|
+
" poke ready: press e + enter to reload browser (ctrl+r also works when available)",
|
|
5419
|
+
{ timestamp: true }
|
|
5420
|
+
);
|
|
5421
|
+
}
|
|
5422
|
+
const onData = (data) => {
|
|
5423
|
+
if (debug) {
|
|
5424
|
+
server.config.logger.info(` poke stdin ${formatChunk(data)}`, {
|
|
5425
|
+
timestamp: true
|
|
5426
|
+
});
|
|
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
|
+
}
|
|
5442
|
+
};
|
|
5443
|
+
stdin.on("data", onData);
|
|
5444
|
+
server.httpServer?.on("close", () => {
|
|
5445
|
+
stdin.off("data", onData);
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5448
|
+
};
|
|
5449
|
+
}
|
|
5010
5450
|
export {
|
|
5451
|
+
poke,
|
|
5011
5452
|
rango
|
|
5012
5453
|
};
|