@rangojs/router 0.0.0-experimental.cb54cbba → 0.0.0-experimental.debug-cache-2383ca26

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.
Files changed (65) hide show
  1. package/AGENTS.md +4 -0
  2. package/dist/bin/rango.js +8 -3
  3. package/dist/vite/index.js +139 -200
  4. package/package.json +15 -14
  5. package/skills/caching/SKILL.md +37 -4
  6. package/skills/parallel/SKILL.md +126 -0
  7. package/src/browser/event-controller.ts +5 -0
  8. package/src/browser/navigation-bridge.ts +1 -3
  9. package/src/browser/navigation-client.ts +60 -27
  10. package/src/browser/navigation-transaction.ts +11 -9
  11. package/src/browser/partial-update.ts +50 -9
  12. package/src/browser/prefetch/cache.ts +57 -5
  13. package/src/browser/prefetch/fetch.ts +30 -21
  14. package/src/browser/prefetch/queue.ts +53 -13
  15. package/src/browser/react/Link.tsx +9 -1
  16. package/src/browser/react/NavigationProvider.tsx +27 -0
  17. package/src/browser/rsc-router.tsx +109 -57
  18. package/src/browser/scroll-restoration.ts +31 -34
  19. package/src/browser/segment-reconciler.ts +6 -1
  20. package/src/browser/types.ts +9 -0
  21. package/src/build/route-types/router-processing.ts +12 -2
  22. package/src/cache/cache-runtime.ts +15 -11
  23. package/src/cache/cache-scope.ts +43 -3
  24. package/src/cache/cf/cf-cache-store.ts +453 -11
  25. package/src/cache/cf/index.ts +5 -1
  26. package/src/cache/document-cache.ts +17 -7
  27. package/src/cache/index.ts +1 -0
  28. package/src/debug.ts +2 -2
  29. package/src/route-definition/dsl-helpers.ts +32 -7
  30. package/src/route-definition/redirect.ts +2 -2
  31. package/src/route-map-builder.ts +7 -1
  32. package/src/router/find-match.ts +4 -2
  33. package/src/router/intercept-resolution.ts +2 -0
  34. package/src/router/lazy-includes.ts +4 -1
  35. package/src/router/logging.ts +5 -2
  36. package/src/router/manifest.ts +9 -3
  37. package/src/router/match-middleware/background-revalidation.ts +30 -2
  38. package/src/router/match-middleware/cache-lookup.ts +66 -9
  39. package/src/router/match-middleware/cache-store.ts +53 -10
  40. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  41. package/src/router/match-middleware/segment-resolution.ts +8 -5
  42. package/src/router/match-result.ts +22 -6
  43. package/src/router/metrics.ts +6 -1
  44. package/src/router/middleware.ts +2 -1
  45. package/src/router/router-context.ts +6 -1
  46. package/src/router/segment-resolution/fresh.ts +122 -15
  47. package/src/router/segment-resolution/loader-cache.ts +1 -0
  48. package/src/router/segment-resolution/revalidation.ts +347 -290
  49. package/src/router/segment-wrappers.ts +2 -0
  50. package/src/router.ts +5 -1
  51. package/src/segment-system.tsx +140 -4
  52. package/src/server/context.ts +90 -13
  53. package/src/server/request-context.ts +10 -4
  54. package/src/ssr/index.tsx +1 -0
  55. package/src/types/handler-context.ts +103 -17
  56. package/src/types/route-entry.ts +7 -0
  57. package/src/types/segments.ts +2 -0
  58. package/src/urls/path-helper.ts +1 -1
  59. package/src/vite/discovery/state.ts +0 -2
  60. package/src/vite/plugin-types.ts +0 -83
  61. package/src/vite/plugins/expose-action-id.ts +1 -3
  62. package/src/vite/plugins/version-plugin.ts +13 -1
  63. package/src/vite/rango.ts +144 -209
  64. package/src/vite/router-discovery.ts +0 -8
  65. package/src/vite/utils/banner.ts +3 -3
package/AGENTS.md CHANGED
@@ -3,3 +3,7 @@
3
3
  A file-system based React Server Components router.
4
4
 
5
5
  Run `/rango` to understand the API. Detailed guides for each feature are in the `skills/` directory (e.g. `node_modules/@rangojs/router/skills/loader`, `skills/caching`, `skills/middleware`, etc.).
6
+
7
+ ## Development rules
8
+
9
+ - Always commit generated files (e.g. `*.gen.ts`) alongside the source changes that produced them.
package/dist/bin/rango.js CHANGED
@@ -601,7 +601,7 @@ function countPublicRouteEntries(source) {
601
601
  return count;
602
602
  }
603
603
  function isRoutableSourceFile(name) {
604
- return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.");
604
+ return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
605
605
  }
606
606
  function findRouterFilesRecursive(dir, filter, results) {
607
607
  let entries;
@@ -618,7 +618,8 @@ function findRouterFilesRecursive(dir, filter, results) {
618
618
  for (const entry of entries) {
619
619
  const fullPath = join2(dir, entry.name);
620
620
  if (entry.isDirectory()) {
621
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
621
+ if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
622
+ continue;
622
623
  childDirs.push(fullPath);
623
624
  continue;
624
625
  }
@@ -1062,8 +1063,9 @@ function createVersionPlugin() {
1062
1063
  let isDev = false;
1063
1064
  let server = null;
1064
1065
  const clientModuleSignatures = /* @__PURE__ */ new Map();
1066
+ let versionCounter = 0;
1065
1067
  const bumpVersion = (reason) => {
1066
- currentVersion = Date.now().toString(16);
1068
+ currentVersion = Date.now().toString(16) + String(++versionCounter);
1067
1069
  console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
1068
1070
  const rscEnv = server?.environments?.rsc;
1069
1071
  const versionMod = rscEnv?.moduleGraph?.getModuleById(
@@ -1119,6 +1121,9 @@ function createVersionPlugin() {
1119
1121
  if (!isDev) return;
1120
1122
  const isRscModule = this.environment?.name === "rsc";
1121
1123
  if (!isRscModule) return;
1124
+ if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
1125
+ return;
1126
+ }
1122
1127
  if (isCodeModule(ctx.file)) {
1123
1128
  const filePath = normalizeModuleId(ctx.file);
1124
1129
  const previousSignature = clientModuleSignatures.get(filePath);
@@ -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.\nThe RSC plugin should be included automatically. If you disabled it with\nrango({ rsc: false }), add rsc() before rango() in your config."
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.cb54cbba",
1748
+ version: "0.0.0-experimental.debug-cache-2383ca26",
1749
1749
  description: "Django-inspired RSC router with composable URL patterns",
1750
1750
  keywords: [
1751
1751
  "react",
@@ -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";
@@ -2386,7 +2362,7 @@ import {
2386
2362
  readdirSync
2387
2363
  } from "node:fs";
2388
2364
  import {
2389
- join as join2,
2365
+ join,
2390
2366
  dirname as dirname2,
2391
2367
  resolve as resolve3,
2392
2368
  sep,
@@ -2406,7 +2382,7 @@ function countPublicRouteEntries(source) {
2406
2382
  }
2407
2383
  var ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
2408
2384
  function isRoutableSourceFile(name) {
2409
- return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.");
2385
+ return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
2410
2386
  }
2411
2387
  function findRouterFilesRecursive(dir, filter, results) {
2412
2388
  let entries;
@@ -2421,9 +2397,10 @@ function findRouterFilesRecursive(dir, filter, results) {
2421
2397
  const childDirs = [];
2422
2398
  const routerFilesInDir = [];
2423
2399
  for (const entry of entries) {
2424
- const fullPath = join2(dir, entry.name);
2400
+ const fullPath = join(dir, entry.name);
2425
2401
  if (entry.isDirectory()) {
2426
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
2402
+ if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
2403
+ continue;
2427
2404
  childDirs.push(fullPath);
2428
2405
  continue;
2429
2406
  }
@@ -2547,7 +2524,7 @@ function findRouterFiles(root, filter) {
2547
2524
  }
2548
2525
  function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2549
2526
  try {
2550
- const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
2527
+ const oldCombinedPath = join(root, "src", "named-routes.gen.ts");
2551
2528
  if (existsSync3(oldCombinedPath)) {
2552
2529
  unlinkSync(oldCombinedPath);
2553
2530
  console.log(
@@ -2587,7 +2564,7 @@ function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
2587
2564
  /\.(tsx?|jsx?)$/,
2588
2565
  ""
2589
2566
  );
2590
- const outPath = join2(
2567
+ const outPath = join(
2591
2568
  dirname2(routerFilePath),
2592
2569
  `${routerBasename}.named-routes.gen.ts`
2593
2570
  );
@@ -2717,8 +2694,9 @@ function createVersionPlugin() {
2717
2694
  let isDev = false;
2718
2695
  let server = null;
2719
2696
  const clientModuleSignatures = /* @__PURE__ */ new Map();
2697
+ let versionCounter = 0;
2720
2698
  const bumpVersion = (reason) => {
2721
- currentVersion = Date.now().toString(16);
2699
+ currentVersion = Date.now().toString(16) + String(++versionCounter);
2722
2700
  console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
2723
2701
  const rscEnv = server?.environments?.rsc;
2724
2702
  const versionMod = rscEnv?.moduleGraph?.getModuleById(
@@ -2774,6 +2752,9 @@ function createVersionPlugin() {
2774
2752
  if (!isDev) return;
2775
2753
  const isRscModule = this.environment?.name === "rsc";
2776
2754
  if (!isRscModule) return;
2755
+ if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
2756
+ return;
2757
+ }
2777
2758
  if (isCodeModule(ctx.file)) {
2778
2759
  const filePath = normalizeModuleId(ctx.file);
2779
2760
  const previousSignature = clientModuleSignatures.get(filePath);
@@ -2903,11 +2884,11 @@ ${dim} \u2571${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2
2903
2884
  ${dim} ${reset}${bold}\u2551 \u2551${reset} ${bold}\u2554\u2550\u2557${reset}${dim} * \u2727. \u2571${reset}
2904
2885
  ${dim} ${reset}${bold}\u2554\u2557 \u2551 \u2551 \u2551 \u2551${reset}${dim} * \u2571${reset}
2905
2886
  ${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} ${reset}${bold}\u2550\u2563\u2551 \u2551 \u2560\u2550\u255D \u2551 \u2560\u2566\u255D\u2560\u2550\u2563\u2551\u2551\u2551\u2551 \u2566\u2551 \u2551${reset}${dim} * \u2727${reset}
2887
+ ${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
2888
  ${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
2889
  ${dim} ${reset}${bold}\u255A\u2550\u2550\u2557 \u2551${reset}${dim} * RSC Wrangler \u2727 \u2726${reset}
2909
- ${dim} * ${reset}${bold}\u2551 \u2560\u2550${reset}${dim} * \u2727. \u2571${reset}
2910
- ${bold}\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2569\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
2890
+ ${dim} * ${reset}${bold}\u2551 \u2551${reset}${dim} * \u2727. \u2571${reset}
2891
+ ${dim} ${reset}${bold}\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550${reset}${dim} \u2726 *${reset}
2911
2892
 
2912
2893
  v${version} \xB7 ${preset} \xB7 ${mode}
2913
2894
  `;
@@ -3052,7 +3033,7 @@ function createVirtualStubPlugin() {
3052
3033
  }
3053
3034
 
3054
3035
  // src/vite/plugins/client-ref-hashing.ts
3055
- import { relative as relative2 } from "node:path";
3036
+ import { relative } from "node:path";
3056
3037
  import { createHash as createHash2 } from "node:crypto";
3057
3038
  var CLIENT_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-package-proxy/";
3058
3039
  var CLIENT_IN_SERVER_PKG_PROXY_PREFIX = "/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
@@ -3065,10 +3046,10 @@ function computeProductionHash(projectRoot, refKey) {
3065
3046
  const absPath = decodeURIComponent(
3066
3047
  refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length)
3067
3048
  );
3068
- toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
3049
+ toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
3069
3050
  } else if (refKey.startsWith(FS_PREFIX)) {
3070
3051
  const absPath = refKey.slice(FS_PREFIX.length - 1);
3071
- toHash = relative2(projectRoot, absPath).replaceAll("\\", "/");
3052
+ toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
3072
3053
  } else if (refKey.startsWith("/")) {
3073
3054
  toHash = refKey.slice(1);
3074
3055
  } else {
@@ -3937,7 +3918,7 @@ async function discoverRouters(state, rscEnv) {
3937
3918
  }
3938
3919
 
3939
3920
  // src/vite/discovery/route-types-writer.ts
3940
- import { dirname as dirname3, basename, join as join3, resolve as resolve6 } from "node:path";
3921
+ import { dirname as dirname3, basename, join as join2, resolve as resolve6 } from "node:path";
3941
3922
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync2 } from "node:fs";
3942
3923
  function filterUserNamedRoutes(manifest) {
3943
3924
  const filtered = {};
@@ -3958,7 +3939,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
3958
3939
  /\.(tsx?|jsx?)$/,
3959
3940
  ""
3960
3941
  );
3961
- const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
3942
+ const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
3962
3943
  try {
3963
3944
  preContent.set(outPath, readFileSync4(outPath, "utf-8"));
3964
3945
  } catch {
@@ -3971,7 +3952,7 @@ function writeCombinedRouteTypesWithTracking(state, opts) {
3971
3952
  /\.(tsx?|jsx?)$/,
3972
3953
  ""
3973
3954
  );
3974
- const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
3955
+ const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
3975
3956
  if (!existsSync5(outPath)) continue;
3976
3957
  try {
3977
3958
  const content = readFileSync4(outPath, "utf-8");
@@ -3988,7 +3969,7 @@ function writeRouteTypesFiles(state) {
3988
3969
  const entryDir = dirname3(
3989
3970
  resolve6(state.projectRoot, state.resolvedEntryPath)
3990
3971
  );
3991
- const oldCombinedPath = join3(entryDir, "named-routes.gen.ts");
3972
+ const oldCombinedPath = join2(entryDir, "named-routes.gen.ts");
3992
3973
  if (existsSync5(oldCombinedPath)) {
3993
3974
  unlinkSync2(oldCombinedPath);
3994
3975
  console.log(
@@ -4013,7 +3994,7 @@ Set an explicit \`id\` on createRouter() or check the call site.`
4013
3994
  }
4014
3995
  const routerDir = dirname3(sourceFile);
4015
3996
  const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4016
- const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
3997
+ const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4017
3998
  const userRoutes = filterUserNamedRoutes(routeManifest);
4018
3999
  let effectiveSearchSchemas = routeSearchSchemas;
4019
4000
  if ((!effectiveSearchSchemas || Object.keys(effectiveSearchSchemas).length === 0) && sourceFile) {
@@ -4078,7 +4059,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
4078
4059
  }
4079
4060
  const routerDir = dirname3(sourceFile);
4080
4061
  const routerBasename = basename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
4081
- const outPath = join3(routerDir, `${routerBasename}.named-routes.gen.ts`);
4062
+ const outPath = join2(routerDir, `${routerBasename}.named-routes.gen.ts`);
4082
4063
  const source = generateRouteTypesSource(
4083
4064
  mergedRoutes,
4084
4065
  Object.keys(mergedSearchSchemas).length > 0 ? mergedSearchSchemas : void 0
@@ -4092,7 +4073,7 @@ function supplementGenFilesWithRuntimeRoutes(state) {
4092
4073
  }
4093
4074
 
4094
4075
  // src/vite/discovery/virtual-module-codegen.ts
4095
- import { dirname as dirname4, basename as basename2, join as join4 } from "node:path";
4076
+ import { dirname as dirname4, basename as basename2, join as join3 } from "node:path";
4096
4077
  function generateRoutesManifestModule(state) {
4097
4078
  const hasManifest = state.mergedRouteManifest && Object.keys(state.mergedRouteManifest).length > 0;
4098
4079
  if (hasManifest) {
@@ -4107,7 +4088,7 @@ function generateRoutesManifestModule(state) {
4107
4088
  /\.(tsx?|jsx?)$/,
4108
4089
  ""
4109
4090
  );
4110
- const genPath = join4(
4091
+ const genPath = join3(
4111
4092
  routerDir,
4112
4093
  `${routerBasename}.named-routes.gen.js`
4113
4094
  ).replaceAll("\\", "/");
@@ -4204,7 +4185,7 @@ function generatePerRouterModule(state, routerId) {
4204
4185
  /\.(tsx?|jsx?)$/,
4205
4186
  ""
4206
4187
  );
4207
- const genPath = join4(
4188
+ const genPath = join3(
4208
4189
  routerDir,
4209
4190
  `${routerBasename}.named-routes.gen.js`
4210
4191
  ).replaceAll("\\", "/");
@@ -4445,12 +4426,6 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
4445
4426
  s.resolvedEntryPath = entries[0];
4446
4427
  }
4447
4428
  }
4448
- if (opts?.include || opts?.exclude) {
4449
- s.scanFilter = createScanFilter(s.projectRoot, {
4450
- include: opts.include,
4451
- exclude: opts.exclude
4452
- });
4453
- }
4454
4429
  if (opts?.staticRouteTypesGeneration !== false) {
4455
4430
  s.cachedRouterFiles = findRouterFiles(s.projectRoot, s.scanFilter);
4456
4431
  writeCombinedRouteTypesWithTracking(s, { preserveIfLarger: true });
@@ -4879,7 +4854,6 @@ async function rango(options) {
4879
4854
  const plugins = [];
4880
4855
  const rangoAliases = getPackageAliases();
4881
4856
  const excludeDeps = getExcludeDeps();
4882
- let rscEntryPath = null;
4883
4857
  const routerRef = { path: void 0 };
4884
4858
  const prerenderEnabled = true;
4885
4859
  if (preset === "cloudflare") {
@@ -4983,153 +4957,121 @@ async function rango(options) {
4983
4957
  );
4984
4958
  plugins.push(clientRefDedup());
4985
4959
  } else {
4986
- const nodeOptions = resolvedOptions;
4987
- routerRef.path = nodeOptions.router;
4988
- if (!routerRef.path) {
4989
- plugins.push({
4990
- name: "@rangojs/router:auto-discover",
4991
- config(userConfig) {
4992
- if (routerRef.path) return;
4993
- const root = userConfig.root ? resolve9(process.cwd(), userConfig.root) : process.cwd();
4994
- const filter = createScanFilter(root, {
4995
- include: resolvedOptions.include,
4996
- exclude: resolvedOptions.exclude
4997
- });
4998
- const candidates = findRouterFiles(root, filter);
4999
- if (candidates.length === 1) {
5000
- const abs = candidates[0];
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
- }
4960
+ plugins.push({
4961
+ name: "@rangojs/router:auto-discover",
4962
+ config(userConfig) {
4963
+ if (routerRef.path) return;
4964
+ const root = userConfig.root ? resolve9(process.cwd(), userConfig.root) : process.cwd();
4965
+ const candidates = findRouterFiles(root);
4966
+ if (candidates.length === 1) {
4967
+ const abs = candidates[0];
4968
+ routerRef.path = (abs.startsWith(root) ? "./" + abs.slice(root.length + 1) : abs).replaceAll("\\", "/");
4969
+ } else if (candidates.length > 1) {
4970
+ const list = candidates.map(
4971
+ (f) => " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f)
4972
+ ).join("\n");
4973
+ throw new Error(`[rsc-router] Multiple routers found:
4974
+ ${list}`);
5011
4975
  }
5012
- });
5013
- }
5014
- const rscOption = nodeOptions.rsc ?? true;
5015
- if (rscOption !== false) {
5016
- const { default: rsc } = await import("@vitejs/plugin-rsc");
5017
- const userEntries = typeof rscOption === "boolean" ? {} : rscOption.entries || {};
5018
- const finalEntries = {
5019
- client: userEntries.client ?? VIRTUAL_IDS.browser,
5020
- ssr: userEntries.ssr ?? VIRTUAL_IDS.ssr,
5021
- rsc: userEntries.rsc ?? VIRTUAL_IDS.rsc
5022
- };
5023
- rscEntryPath = userEntries.rsc ?? null;
5024
- let hasWarnedDuplicate = false;
5025
- plugins.push({
5026
- name: "@rangojs/router:rsc-integration",
5027
- enforce: "pre",
5028
- config() {
5029
- const useVirtualClient = finalEntries.client === VIRTUAL_IDS.browser;
5030
- const useVirtualSSR = finalEntries.ssr === VIRTUAL_IDS.ssr;
5031
- const useVirtualRSC = finalEntries.rsc === VIRTUAL_IDS.rsc;
5032
- return {
5033
- // Exclude rsc-router modules from optimization to prevent module duplication
5034
- // This ensures the same Context instance is used by both browser entry and RSC proxy modules
5035
- optimizeDeps: {
5036
- exclude: excludeDeps,
5037
- esbuildOptions: sharedEsbuildOptions
5038
- },
5039
- build: {
5040
- rollupOptions: { onwarn }
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
4976
+ }
4977
+ });
4978
+ const finalEntries = {
4979
+ client: VIRTUAL_IDS.browser,
4980
+ ssr: VIRTUAL_IDS.ssr,
4981
+ rsc: VIRTUAL_IDS.rsc
4982
+ };
4983
+ const { default: rsc } = await import("@vitejs/plugin-rsc");
4984
+ let hasWarnedDuplicate = false;
4985
+ plugins.push({
4986
+ name: "@rangojs/router:rsc-integration",
4987
+ enforce: "pre",
4988
+ config() {
4989
+ return {
4990
+ optimizeDeps: {
4991
+ exclude: excludeDeps,
4992
+ esbuildOptions: sharedEsbuildOptions
4993
+ },
4994
+ build: {
4995
+ rollupOptions: { onwarn }
4996
+ },
4997
+ resolve: {
4998
+ alias: rangoAliases
4999
+ },
5000
+ environments: {
5001
+ client: {
5002
+ build: {
5003
+ rollupOptions: {
5004
+ output: {
5005
+ manualChunks: getManualChunks
5089
5006
  }
5090
5007
  }
5091
5008
  },
5092
- ...useVirtualRSC && {
5093
- rsc: {
5094
- optimizeDeps: {
5095
- entries: [VIRTUAL_IDS.rsc],
5096
- // Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
5097
- include: [
5098
- "react",
5099
- "react/jsx-runtime",
5100
- "react/jsx-dev-runtime",
5101
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
5102
- ],
5103
- esbuildOptions: sharedEsbuildOptions
5104
- }
5105
- }
5009
+ optimizeDeps: {
5010
+ include: [
5011
+ "react",
5012
+ "react-dom",
5013
+ "react/jsx-runtime",
5014
+ "react/jsx-dev-runtime",
5015
+ "rsc-html-stream/client"
5016
+ ],
5017
+ exclude: excludeDeps,
5018
+ esbuildOptions: sharedEsbuildOptions,
5019
+ entries: [VIRTUAL_IDS.browser]
5020
+ }
5021
+ },
5022
+ ssr: {
5023
+ optimizeDeps: {
5024
+ entries: [VIRTUAL_IDS.ssr],
5025
+ include: [
5026
+ "react",
5027
+ "react-dom",
5028
+ "react-dom/server.edge",
5029
+ "react-dom/static.edge",
5030
+ "react/jsx-runtime",
5031
+ "react/jsx-dev-runtime",
5032
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge"
5033
+ ],
5034
+ exclude: excludeDeps,
5035
+ esbuildOptions: sharedEsbuildOptions
5036
+ }
5037
+ },
5038
+ rsc: {
5039
+ optimizeDeps: {
5040
+ entries: [VIRTUAL_IDS.rsc],
5041
+ include: [
5042
+ "react",
5043
+ "react/jsx-runtime",
5044
+ "react/jsx-dev-runtime",
5045
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge"
5046
+ ],
5047
+ esbuildOptions: sharedEsbuildOptions
5106
5048
  }
5107
5049
  }
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
5050
  }
5051
+ };
5052
+ },
5053
+ configResolved(config) {
5054
+ if (showBanner) {
5055
+ const mode = config.command === "serve" ? process.argv.includes("preview") ? "preview" : "dev" : "build";
5056
+ printBanner(mode, "node", rangoVersion);
5124
5057
  }
5125
- });
5126
- plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
5127
- plugins.push(
5128
- rsc({
5129
- entries: finalEntries
5130
- })
5131
- );
5132
- }
5058
+ const rscMinimalCount = config.plugins.filter(
5059
+ (p) => p.name === "rsc:minimal"
5060
+ ).length;
5061
+ if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
5062
+ hasWarnedDuplicate = true;
5063
+ console.warn(
5064
+ "[rsc-router] Duplicate @vitejs/plugin-rsc detected. Remove rsc() from your vite config \u2014 rango() includes it automatically."
5065
+ );
5066
+ }
5067
+ }
5068
+ });
5069
+ plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
5070
+ plugins.push(
5071
+ rsc({
5072
+ entries: finalEntries
5073
+ })
5074
+ );
5133
5075
  plugins.push(clientRefDedup());
5134
5076
  }
5135
5077
  plugins.push({
@@ -5157,18 +5099,15 @@ ${list}`
5157
5099
  plugins.push(createVersionPlugin());
5158
5100
  const discoveryEntryPath = preset !== "cloudflare" ? routerRef.path : void 0;
5159
5101
  const discoveryRouterRef = preset !== "cloudflare" ? routerRef : void 0;
5160
- const injectorEntryPath = rscEntryPath ?? (preset === "cloudflare" ? void 0 : null);
5161
- if (injectorEntryPath !== null) {
5162
- plugins.push(createVersionInjectorPlugin(injectorEntryPath));
5102
+ if (preset === "cloudflare") {
5103
+ plugins.push(createVersionInjectorPlugin(void 0));
5163
5104
  }
5164
5105
  plugins.push(createCjsToEsmPlugin());
5165
5106
  plugins.push(
5166
5107
  createRouterDiscoveryPlugin(discoveryEntryPath, {
5167
5108
  routerPathRef: discoveryRouterRef,
5168
5109
  enableBuildPrerender: prerenderEnabled,
5169
- staticRouteTypesGeneration: resolvedOptions.staticRouteTypesGeneration,
5170
- include: resolvedOptions.include,
5171
- exclude: resolvedOptions.exclude
5110
+ staticRouteTypesGeneration: resolvedOptions.staticRouteTypesGeneration
5172
5111
  })
5173
5112
  );
5174
5113
  return plugins;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.0.0-experimental.cb54cbba",
3
+ "version": "0.0.0-experimental.debug-cache-2383ca26",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -132,6 +132,15 @@
132
132
  "access": "public",
133
133
  "tag": "experimental"
134
134
  },
135
+ "scripts": {
136
+ "build": "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
137
+ "prepublishOnly": "pnpm build",
138
+ "typecheck": "tsc --noEmit",
139
+ "test": "playwright test",
140
+ "test:ui": "playwright test --ui",
141
+ "test:unit": "vitest run",
142
+ "test:unit:watch": "vitest"
143
+ },
135
144
  "dependencies": {
136
145
  "@vitejs/plugin-rsc": "^0.5.14",
137
146
  "magic-string": "^0.30.17",
@@ -141,12 +150,12 @@
141
150
  "devDependencies": {
142
151
  "@playwright/test": "^1.49.1",
143
152
  "@types/node": "^24.10.1",
144
- "@types/react": "^19.2.7",
145
- "@types/react-dom": "^19.2.3",
153
+ "@types/react": "catalog:",
154
+ "@types/react-dom": "catalog:",
146
155
  "esbuild": "^0.27.0",
147
156
  "jiti": "^2.6.1",
148
- "react": "^19.2.4",
149
- "react-dom": "^19.2.4",
157
+ "react": "catalog:",
158
+ "react-dom": "catalog:",
150
159
  "tinyexec": "^0.3.2",
151
160
  "typescript": "^5.3.0",
152
161
  "vitest": "^4.0.0"
@@ -164,13 +173,5 @@
164
173
  "vite": {
165
174
  "optional": true
166
175
  }
167
- },
168
- "scripts": {
169
- "build": "pnpm dlx esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && pnpm dlx esbuild src/bin/rango.ts --bundle --format=esm --outfile=dist/bin/rango.js --platform=node --packages=external --banner:js='#!/usr/bin/env node' && chmod +x dist/bin/rango.js",
170
- "typecheck": "tsc --noEmit",
171
- "test": "playwright test",
172
- "test:ui": "playwright test --ui",
173
- "test:unit": "vitest run",
174
- "test:unit:watch": "vitest"
175
176
  }
176
- }
177
+ }