@rangojs/router 0.0.0-experimental.20 → 0.0.0-experimental.204030a9

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 (293) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +242 -55
  3. package/dist/bin/rango.js +277 -99
  4. package/dist/vite/index.js +2929 -1132
  5. package/dist/vite/index.js.bak +5448 -0
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +68 -21
  8. package/skills/breadcrumbs/SKILL.md +252 -0
  9. package/skills/bundle-analysis/SKILL.md +159 -0
  10. package/skills/cache-guide/SKILL.md +243 -21
  11. package/skills/caching/SKILL.md +159 -10
  12. package/skills/composability/SKILL.md +27 -2
  13. package/skills/document-cache/SKILL.md +78 -55
  14. package/skills/handler-use/SKILL.md +364 -0
  15. package/skills/hooks/SKILL.md +262 -51
  16. package/skills/host-router/SKILL.md +243 -0
  17. package/skills/i18n/SKILL.md +276 -0
  18. package/skills/intercept/SKILL.md +46 -4
  19. package/skills/layout/SKILL.md +28 -7
  20. package/skills/links/SKILL.md +249 -17
  21. package/skills/loader/SKILL.md +291 -31
  22. package/skills/middleware/SKILL.md +49 -12
  23. package/skills/migrate-nextjs/SKILL.md +562 -0
  24. package/skills/migrate-react-router/SKILL.md +769 -0
  25. package/skills/mime-routes/SKILL.md +27 -0
  26. package/skills/observability/SKILL.md +137 -0
  27. package/skills/parallel/SKILL.md +197 -6
  28. package/skills/prerender/SKILL.md +125 -102
  29. package/skills/rango/SKILL.md +242 -23
  30. package/skills/react-compiler/SKILL.md +168 -0
  31. package/skills/response-routes/SKILL.md +66 -9
  32. package/skills/route/SKILL.md +91 -8
  33. package/skills/router-setup/SKILL.md +98 -8
  34. package/skills/server-actions/SKILL.md +751 -0
  35. package/skills/streams-and-websockets/SKILL.md +283 -0
  36. package/skills/testing/SKILL.md +511 -188
  37. package/skills/typesafety/SKILL.md +354 -50
  38. package/skills/use-cache/SKILL.md +34 -5
  39. package/skills/view-transitions/SKILL.md +294 -0
  40. package/src/__augment-tests__/augment.ts +81 -0
  41. package/src/__augment-tests__/augmented.check.ts +117 -0
  42. package/src/__internal.ts +92 -0
  43. package/src/browser/action-coordinator.ts +53 -36
  44. package/src/browser/app-shell.ts +52 -0
  45. package/src/browser/app-version.ts +14 -0
  46. package/src/browser/event-controller.ts +91 -70
  47. package/src/browser/history-state.ts +21 -0
  48. package/src/browser/index.ts +3 -3
  49. package/src/browser/link-interceptor.ts +4 -0
  50. package/src/browser/navigation-bridge.ts +183 -18
  51. package/src/browser/navigation-client.ts +187 -57
  52. package/src/browser/navigation-store.ts +75 -17
  53. package/src/browser/navigation-transaction.ts +21 -37
  54. package/src/browser/partial-update.ts +143 -40
  55. package/src/browser/prefetch/cache.ts +275 -28
  56. package/src/browser/prefetch/fetch.ts +191 -46
  57. package/src/browser/prefetch/policy.ts +6 -0
  58. package/src/browser/prefetch/queue.ts +123 -20
  59. package/src/browser/prefetch/resource-ready.ts +77 -0
  60. package/src/browser/rango-state.ts +53 -13
  61. package/src/browser/react/Link.tsx +98 -14
  62. package/src/browser/react/NavigationProvider.tsx +110 -33
  63. package/src/browser/react/context.ts +7 -2
  64. package/src/browser/react/filter-segment-order.ts +51 -7
  65. package/src/browser/react/index.ts +3 -0
  66. package/src/browser/react/location-state-shared.ts +175 -4
  67. package/src/browser/react/location-state.ts +39 -13
  68. package/src/browser/react/use-handle.ts +23 -64
  69. package/src/browser/react/use-navigation.ts +22 -2
  70. package/src/browser/react/use-params.ts +20 -8
  71. package/src/browser/react/use-reverse.ts +106 -0
  72. package/src/browser/react/use-router.ts +43 -10
  73. package/src/browser/react/use-segments.ts +11 -8
  74. package/src/browser/response-adapter.ts +25 -0
  75. package/src/browser/rsc-router.tsx +200 -75
  76. package/src/browser/scroll-restoration.ts +46 -39
  77. package/src/browser/segment-reconciler.ts +36 -9
  78. package/src/browser/segment-structure-assert.ts +2 -2
  79. package/src/browser/server-action-bridge.ts +31 -36
  80. package/src/browser/types.ts +81 -5
  81. package/src/build/collect-fallback-refs.ts +107 -0
  82. package/src/build/generate-manifest.ts +65 -40
  83. package/src/build/generate-route-types.ts +5 -0
  84. package/src/build/index.ts +2 -0
  85. package/src/build/route-trie.ts +69 -26
  86. package/src/build/route-types/codegen.ts +4 -4
  87. package/src/build/route-types/include-resolution.ts +9 -2
  88. package/src/build/route-types/per-module-writer.ts +7 -4
  89. package/src/build/route-types/router-processing.ts +278 -88
  90. package/src/build/route-types/scan-filter.ts +9 -2
  91. package/src/build/route-types/source-scan.ts +118 -0
  92. package/src/build/runtime-discovery.ts +9 -20
  93. package/src/cache/cache-runtime.ts +15 -11
  94. package/src/cache/cache-scope.ts +76 -49
  95. package/src/cache/cf/cf-cache-store.ts +501 -18
  96. package/src/cache/cf/index.ts +5 -1
  97. package/src/cache/document-cache.ts +17 -7
  98. package/src/cache/index.ts +1 -0
  99. package/src/cache/taint.ts +55 -0
  100. package/src/client.rsc.tsx +5 -1
  101. package/src/client.tsx +95 -284
  102. package/src/context-var.ts +72 -2
  103. package/src/debug.ts +2 -2
  104. package/src/decode-loader-results.ts +36 -0
  105. package/src/errors.ts +30 -1
  106. package/src/handle.ts +65 -12
  107. package/src/handles/breadcrumbs.ts +66 -0
  108. package/src/handles/index.ts +1 -0
  109. package/src/host/index.ts +2 -5
  110. package/src/host/router.ts +129 -57
  111. package/src/host/types.ts +31 -2
  112. package/src/host/utils.ts +1 -1
  113. package/src/href-client.ts +140 -20
  114. package/src/index.rsc.ts +15 -40
  115. package/src/index.ts +92 -76
  116. package/src/loader-store.ts +500 -0
  117. package/src/loader.rsc.ts +2 -5
  118. package/src/loader.ts +3 -10
  119. package/src/missing-id-error.ts +68 -0
  120. package/src/outlet-context.ts +1 -1
  121. package/src/prerender/store.ts +57 -15
  122. package/src/prerender.ts +141 -80
  123. package/src/response-utils.ts +37 -0
  124. package/src/reverse.ts +65 -15
  125. package/src/route-content-wrapper.tsx +6 -28
  126. package/src/route-definition/dsl-helpers.ts +435 -260
  127. package/src/route-definition/helper-factories.ts +29 -139
  128. package/src/route-definition/helpers-types.ts +110 -34
  129. package/src/route-definition/index.ts +3 -3
  130. package/src/route-definition/redirect.ts +11 -3
  131. package/src/route-definition/resolve-handler-use.ts +155 -0
  132. package/src/route-definition/use-item-types.ts +32 -0
  133. package/src/route-map-builder.ts +7 -1
  134. package/src/route-types.ts +37 -41
  135. package/src/router/basename.ts +14 -0
  136. package/src/router/content-negotiation.ts +113 -1
  137. package/src/router/error-handling.ts +1 -1
  138. package/src/router/find-match.ts +4 -2
  139. package/src/router/handler-context.ts +105 -39
  140. package/src/router/intercept-resolution.ts +15 -22
  141. package/src/router/lazy-includes.ts +12 -9
  142. package/src/router/loader-resolution.ts +175 -23
  143. package/src/router/logging.ts +5 -2
  144. package/src/router/manifest.ts +31 -16
  145. package/src/router/match-api.ts +129 -193
  146. package/src/router/match-handlers.ts +63 -20
  147. package/src/router/match-middleware/background-revalidation.ts +30 -2
  148. package/src/router/match-middleware/cache-lookup.ts +136 -106
  149. package/src/router/match-middleware/cache-store.ts +54 -10
  150. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  151. package/src/router/match-middleware/segment-resolution.ts +61 -5
  152. package/src/router/match-result.ts +124 -18
  153. package/src/router/metrics.ts +239 -14
  154. package/src/router/middleware-types.ts +61 -31
  155. package/src/router/middleware.ts +226 -124
  156. package/src/router/navigation-snapshot.ts +182 -0
  157. package/src/router/pattern-matching.ts +118 -19
  158. package/src/router/prerender-match.ts +114 -10
  159. package/src/router/preview-match.ts +32 -102
  160. package/src/router/request-classification.ts +286 -0
  161. package/src/router/revalidation.ts +85 -9
  162. package/src/router/route-snapshot.ts +245 -0
  163. package/src/router/router-context.ts +6 -1
  164. package/src/router/router-interfaces.ts +91 -29
  165. package/src/router/router-options.ts +89 -19
  166. package/src/router/router-registry.ts +2 -5
  167. package/src/router/segment-resolution/fresh.ts +240 -23
  168. package/src/router/segment-resolution/helpers.ts +30 -25
  169. package/src/router/segment-resolution/loader-cache.ts +1 -0
  170. package/src/router/segment-resolution/revalidation.ts +483 -289
  171. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  172. package/src/router/segment-wrappers.ts +2 -0
  173. package/src/router/substitute-pattern-params.ts +56 -0
  174. package/src/router/telemetry.ts +99 -0
  175. package/src/router/trie-matching.ts +38 -15
  176. package/src/router/types.ts +9 -0
  177. package/src/router/url-params.ts +49 -0
  178. package/src/router.ts +120 -32
  179. package/src/rsc/handler-context.ts +2 -2
  180. package/src/rsc/handler.ts +524 -370
  181. package/src/rsc/helpers.ts +91 -43
  182. package/src/rsc/index.ts +1 -21
  183. package/src/rsc/loader-fetch.ts +23 -3
  184. package/src/rsc/manifest-init.ts +5 -1
  185. package/src/rsc/origin-guard.ts +28 -10
  186. package/src/rsc/progressive-enhancement.ts +39 -10
  187. package/src/rsc/response-route-handler.ts +46 -53
  188. package/src/rsc/rsc-rendering.ts +69 -89
  189. package/src/rsc/runtime-warnings.ts +9 -10
  190. package/src/rsc/server-action.ts +39 -47
  191. package/src/rsc/ssr-setup.ts +144 -0
  192. package/src/rsc/types.ts +19 -3
  193. package/src/search-params.ts +20 -17
  194. package/src/segment-content-promise.ts +67 -0
  195. package/src/segment-loader-promise.ts +122 -0
  196. package/src/segment-system.tsx +219 -67
  197. package/src/serialize.ts +243 -0
  198. package/src/server/context.ts +285 -63
  199. package/src/server/cookie-store.ts +28 -4
  200. package/src/server/handle-store.ts +19 -0
  201. package/src/server/loader-registry.ts +9 -8
  202. package/src/server/request-context.ts +228 -65
  203. package/src/server.ts +6 -0
  204. package/src/ssr/index.tsx +9 -1
  205. package/src/static-handler.ts +19 -7
  206. package/src/testing/cache-status.ts +166 -0
  207. package/src/testing/collect-handle.ts +63 -0
  208. package/src/testing/dispatch.ts +440 -0
  209. package/src/testing/dom.entry.ts +22 -0
  210. package/src/testing/e2e/fixture.ts +154 -0
  211. package/src/testing/e2e/index.ts +149 -0
  212. package/src/testing/e2e/matchers.ts +51 -0
  213. package/src/testing/e2e/page-helpers.ts +272 -0
  214. package/src/testing/e2e/parity.ts +306 -0
  215. package/src/testing/e2e/server.ts +183 -0
  216. package/src/testing/flight-matchers.ts +104 -0
  217. package/src/testing/flight-runtime.d.ts +21 -0
  218. package/src/testing/flight.entry.ts +22 -0
  219. package/src/testing/flight.ts +182 -0
  220. package/src/testing/generated-routes.ts +223 -0
  221. package/src/testing/index.ts +98 -0
  222. package/src/testing/internal/context.ts +151 -0
  223. package/src/testing/render-route.tsx +536 -0
  224. package/src/testing/run-loader.ts +296 -0
  225. package/src/testing/run-middleware.ts +170 -0
  226. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  227. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  228. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  229. package/src/testing/vitest-stubs/version.ts +5 -0
  230. package/src/testing/vitest.ts +112 -0
  231. package/src/theme/index.ts +4 -13
  232. package/src/types/cache-types.ts +4 -4
  233. package/src/types/global-namespace.ts +39 -26
  234. package/src/types/handler-context.ts +197 -79
  235. package/src/types/index.ts +1 -0
  236. package/src/types/loader-types.ts +41 -15
  237. package/src/types/request-scope.ts +126 -0
  238. package/src/types/route-config.ts +17 -8
  239. package/src/types/route-entry.ts +19 -1
  240. package/src/types/segments.ts +37 -6
  241. package/src/urls/include-helper.ts +34 -67
  242. package/src/urls/index.ts +0 -3
  243. package/src/urls/path-helper-types.ts +50 -9
  244. package/src/urls/path-helper.ts +63 -63
  245. package/src/urls/pattern-types.ts +48 -19
  246. package/src/urls/response-types.ts +25 -22
  247. package/src/urls/type-extraction.ts +26 -116
  248. package/src/urls/urls-function.ts +1 -5
  249. package/src/use-loader.tsx +487 -44
  250. package/src/vite/debug.ts +185 -0
  251. package/src/vite/discovery/bundle-postprocess.ts +63 -91
  252. package/src/vite/discovery/discover-routers.ts +106 -53
  253. package/src/vite/discovery/discovery-errors.ts +194 -0
  254. package/src/vite/discovery/gate-state.ts +171 -0
  255. package/src/vite/discovery/prerender-collection.ts +222 -107
  256. package/src/vite/discovery/route-types-writer.ts +40 -84
  257. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  258. package/src/vite/discovery/state.ts +50 -13
  259. package/src/vite/discovery/virtual-module-codegen.ts +13 -23
  260. package/src/vite/index.ts +10 -3
  261. package/src/vite/plugin-types.ts +111 -72
  262. package/src/vite/plugins/cjs-to-esm.ts +8 -7
  263. package/src/vite/plugins/client-ref-dedup.ts +16 -0
  264. package/src/vite/plugins/client-ref-hashing.ts +28 -5
  265. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  266. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  267. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  268. package/src/vite/plugins/expose-action-id.ts +55 -33
  269. package/src/vite/plugins/expose-id-utils.ts +24 -8
  270. package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
  271. package/src/vite/plugins/expose-ids/handler-transform.ts +12 -35
  272. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  273. package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
  274. package/src/vite/plugins/expose-internal-ids.ts +544 -317
  275. package/src/vite/plugins/performance-tracks.ts +92 -0
  276. package/src/vite/plugins/refresh-cmd.ts +127 -0
  277. package/src/vite/plugins/use-cache-transform.ts +65 -50
  278. package/src/vite/plugins/version-injector.ts +39 -23
  279. package/src/vite/plugins/version-plugin.ts +72 -3
  280. package/src/vite/plugins/virtual-entries.ts +2 -2
  281. package/src/vite/rango.ts +265 -226
  282. package/src/vite/router-discovery.ts +924 -137
  283. package/src/vite/utils/ast-handler-extract.ts +15 -15
  284. package/src/vite/utils/banner.ts +4 -4
  285. package/src/vite/utils/bundle-analysis.ts +4 -2
  286. package/src/vite/utils/client-chunks.ts +190 -0
  287. package/src/vite/utils/forward-user-plugins.ts +193 -0
  288. package/src/vite/utils/manifest-utils.ts +21 -5
  289. package/src/vite/utils/package-resolution.ts +41 -1
  290. package/src/vite/utils/prerender-utils.ts +98 -5
  291. package/src/vite/utils/shared-utils.ts +109 -27
  292. package/src/browser/action-response-classifier.ts +0 -99
  293. package/src/route-definition/route-function.ts +0 -119
@@ -13,12 +13,17 @@ import {
13
13
  runWithConcurrency,
14
14
  groupByConcurrency,
15
15
  notifyOnError,
16
+ stageBuildAssetModule,
16
17
  } from "../utils/prerender-utils.js";
17
18
  import type { DiscoveryState } from "./state.js";
19
+ import { createRangoDebugger, NS } from "../debug.js";
20
+
21
+ const debug = createRangoDebugger(NS.prerender);
18
22
 
19
23
  /**
20
24
  * Expand prerender routes into concrete URLs and render them via the
21
- * RSC runner. Stores collected data in state.prerenderCollectedData.
25
+ * RSC runner. Stages asset modules and stores key-to-file entries in
26
+ * state.prerenderManifestEntries.
22
27
  */
23
28
  export async function expandPrerenderRoutes(
24
29
  state: DiscoveryState,
@@ -28,6 +33,12 @@ export async function expandPrerenderRoutes(
28
33
  ): Promise<void> {
29
34
  if (!state.opts?.enableBuildPrerender || !state.isBuildMode) return;
30
35
 
36
+ const overallStart = debug ? performance.now() : 0;
37
+ debug?.(
38
+ "expandPrerenderRoutes: start (%d router manifest(s))",
39
+ allManifests.length,
40
+ );
41
+
31
42
  type PrerenderEntry = {
32
43
  urlPath: string;
33
44
  routeName: string;
@@ -49,108 +60,177 @@ export async function expandPrerenderRoutes(
49
60
  return substituteRouteParams(pattern, params);
50
61
  };
51
62
 
63
+ let resolvedRoutes = 0;
64
+ let totalDynamic = 0;
65
+
66
+ // Count dynamic routes upfront for progress reporting
52
67
  for (const { manifest } of allManifests) {
53
68
  if (!manifest.prerenderRoutes) continue;
54
- const defs = manifest._prerenderDefs || {};
55
69
  for (const routeName of manifest.prerenderRoutes) {
56
70
  const pattern = manifest.routeManifest[routeName];
57
- if (!pattern) continue;
58
- const def = defs[routeName];
59
- const isPassthroughRoute = !!def?.options?.passthrough;
60
- const hasDynamic = pattern.includes(":") || pattern.includes("*");
61
- if (!hasDynamic) {
62
- // Static route: use pattern directly (strip trailing slash for URL)
63
- entries.push({
64
- urlPath: pattern.replace(/\/$/, "") || "/",
65
- routeName,
66
- concurrency: 1,
67
- isPassthroughRoute,
68
- });
69
- } else {
70
- // Dynamic route: call getParams() to enumerate param combinations
71
- if (def?.getParams) {
72
- try {
73
- const buildVars: Record<string, any> = {};
74
- const getParamsCtx = {
75
- build: true as const,
76
- set: ((keyOrVar: any, value: any) => {
77
- contextSet(buildVars, keyOrVar, value);
78
- }) as any,
79
- reverse: getParamsReverse,
80
- };
81
- const paramsList = await def.getParams(getParamsCtx);
82
- const concurrency = def.options?.concurrency ?? 1;
83
- const hasBuildVars =
84
- Object.keys(buildVars).length > 0 ||
85
- Object.getOwnPropertySymbols(buildVars).length > 0;
86
- for (const params of paramsList) {
87
- let url = substituteRouteParams(
88
- pattern,
89
- params as Record<string, string>,
90
- encodePathParam,
71
+ if (pattern && (pattern.includes(":") || pattern.includes("*"))) {
72
+ totalDynamic++;
73
+ }
74
+ }
75
+ }
76
+
77
+ // Periodic progress log so long getParams() calls don't look stalled
78
+ const paramsStart = performance.now();
79
+ const progressInterval =
80
+ totalDynamic > 0
81
+ ? setInterval(() => {
82
+ const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
83
+ console.log(
84
+ `[rango] Resolving prerender params... ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
85
+ );
86
+ }, 5000)
87
+ : undefined;
88
+
89
+ try {
90
+ for (const { manifest } of allManifests) {
91
+ if (!manifest.prerenderRoutes) continue;
92
+ const defs = manifest._prerenderDefs || {};
93
+ const passthroughSet = new Set(manifest.passthroughRoutes || []);
94
+ for (const routeName of manifest.prerenderRoutes) {
95
+ const pattern = manifest.routeManifest[routeName];
96
+ if (!pattern) continue;
97
+ const def = defs[routeName];
98
+ const isPassthroughRoute = passthroughSet.has(routeName);
99
+ const hasDynamic = pattern.includes(":") || pattern.includes("*");
100
+ if (!hasDynamic) {
101
+ // Static route: use pattern directly (strip trailing slash for URL)
102
+ entries.push({
103
+ urlPath: pattern.replace(/\/$/, "") || "/",
104
+ routeName,
105
+ concurrency: 1,
106
+ isPassthroughRoute,
107
+ });
108
+ } else {
109
+ // Dynamic route: call getParams() to enumerate param combinations
110
+ if (def?.getParams) {
111
+ const getParamsStart = debug ? performance.now() : 0;
112
+ try {
113
+ const buildVars: Record<string, any> = {};
114
+ const buildEnv = state.resolvedBuildEnv;
115
+ const getParamsCtx = {
116
+ build: true as const,
117
+ dev: !state.isBuildMode,
118
+ set: ((keyOrVar: any, value: any) => {
119
+ contextSet(buildVars, keyOrVar, value);
120
+ }) as any,
121
+ reverse: getParamsReverse,
122
+ get env() {
123
+ if (buildEnv !== undefined) return buildEnv;
124
+ throw new Error(
125
+ "[rango] ctx.env is not available during build-time getParams(). " +
126
+ "Configure buildEnv in your rango() plugin options to enable build-time env access.",
127
+ );
128
+ },
129
+ };
130
+ const paramsList = await def.getParams(getParamsCtx);
131
+ debug?.(
132
+ "getParams %s -> %d params (%sms)",
133
+ routeName,
134
+ paramsList.length,
135
+ (performance.now() - getParamsStart).toFixed(1),
91
136
  );
92
- // Anonymous wildcard fallback: use conventional keys if provided
93
- if (url.includes("*")) {
94
- const wildcardValue =
95
- (params as Record<string, string>)["*"] ??
96
- (params as Record<string, string>).splat;
97
- if (wildcardValue !== undefined) {
98
- url = url.replace(/\*[^/]*$/, encodePathParam(wildcardValue));
137
+ const concurrency = def.options?.concurrency ?? 1;
138
+ const hasBuildVars =
139
+ Object.keys(buildVars).length > 0 ||
140
+ Object.getOwnPropertySymbols(buildVars).length > 0;
141
+ for (const params of paramsList) {
142
+ let url = substituteRouteParams(
143
+ pattern,
144
+ params as Record<string, string>,
145
+ encodePathParam,
146
+ );
147
+ // Anonymous wildcard fallback: use conventional keys if provided
148
+ if (url.includes("*")) {
149
+ const wildcardValue =
150
+ (params as Record<string, string>)["*"] ??
151
+ (params as Record<string, string>).splat;
152
+ if (wildcardValue !== undefined) {
153
+ url = url.replace(
154
+ /\*[^/]*$/,
155
+ encodePathParam(wildcardValue),
156
+ );
157
+ }
99
158
  }
159
+ entries.push({
160
+ urlPath: url.replace(/\/$/, "") || "/",
161
+ routeName,
162
+ concurrency,
163
+ ...(hasBuildVars ? { buildVars } : {}),
164
+ isPassthroughRoute,
165
+ });
100
166
  }
101
- entries.push({
102
- urlPath: url.replace(/\/$/, "") || "/",
103
- routeName,
104
- concurrency,
105
- ...(hasBuildVars ? { buildVars } : {}),
106
- isPassthroughRoute,
107
- });
108
- }
109
- } catch (err: any) {
110
- // Skip in getParams() skips the entire route
111
- if (err.name === "Skip") {
112
- console.log(
113
- `[rsc-router] SKIP route "${routeName}" - ${err.message}`,
114
- );
115
- notifyOnError(
116
- registry,
117
- err,
118
- "prerender",
119
- routeName,
120
- undefined,
121
- true,
167
+ resolvedRoutes++;
168
+ } catch (err: any) {
169
+ resolvedRoutes++;
170
+ // Skip in getParams() skips the entire route
171
+ if (err.name === "Skip") {
172
+ console.log(
173
+ `[rango] SKIP route "${routeName}" - ${err.message}`,
174
+ );
175
+ notifyOnError(
176
+ registry,
177
+ err,
178
+ "prerender",
179
+ routeName,
180
+ undefined,
181
+ true,
182
+ );
183
+ continue;
184
+ }
185
+ // Regular error: fail the build
186
+ console.error(
187
+ `[rango] Failed to get params for prerender route "${routeName}": ${err.message}`,
122
188
  );
123
- continue;
189
+ notifyOnError(registry, err, "prerender", routeName);
190
+ throw err;
124
191
  }
125
- // Regular error: fail the build
126
- console.error(
127
- `[rsc-router] Failed to get params for prerender route "${routeName}": ${err.message}`,
192
+ } else {
193
+ console.warn(
194
+ `[rango] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
128
195
  );
129
- notifyOnError(registry, err, "prerender", routeName);
130
- throw err;
131
196
  }
132
- } else {
133
- console.warn(
134
- `[rsc-router] Dynamic prerender route "${routeName}" has no getParams(), skipping`,
135
- );
136
197
  }
137
198
  }
138
199
  }
200
+ } finally {
201
+ if (progressInterval) {
202
+ clearInterval(progressInterval);
203
+ const elapsed = ((performance.now() - paramsStart) / 1000).toFixed(1);
204
+ console.log(
205
+ `[rango] Resolved prerender params: ${resolvedRoutes}/${totalDynamic} routes (${elapsed}s)`,
206
+ );
207
+ }
139
208
  }
140
209
 
141
- if (entries.length === 0) return;
210
+ if (entries.length === 0) {
211
+ debug?.(
212
+ "no prerender entries (done in %sms)",
213
+ (performance.now() - overallStart).toFixed(1),
214
+ );
215
+ return;
216
+ }
142
217
 
143
218
  // Determine the max concurrency for the log header
144
219
  const maxConcurrency = Math.max(...entries.map((e) => e.concurrency));
145
220
  const concurrencyNote =
146
221
  maxConcurrency > 1 ? ` (concurrency: ${maxConcurrency})` : "";
147
222
  console.log(
148
- `[rsc-router] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`,
223
+ `[rango] Pre-rendering ${entries.length} URL(s)${concurrencyNote}...`,
224
+ );
225
+ debug?.(
226
+ "prerender loop: %d entries, max concurrency %d",
227
+ entries.length,
228
+ maxConcurrency,
149
229
  );
150
230
 
151
231
  const { hashParams } = await rscEnv.runner.import("@rangojs/router/build");
152
232
 
153
- const collectedData: Record<string, any> = {};
233
+ const manifestEntries: Record<string, string> = {};
154
234
  let doneCount = 0;
155
235
  let skipCount = 0;
156
236
  const startTotal = performance.now();
@@ -173,6 +253,7 @@ export async function expandPrerenderRoutes(
173
253
  {},
174
254
  entry.buildVars,
175
255
  entry.isPassthroughRoute,
256
+ state.resolvedBuildEnv,
176
257
  );
177
258
  if (!result) continue;
178
259
 
@@ -180,29 +261,41 @@ export async function expandPrerenderRoutes(
180
261
  if (result.passthrough) {
181
262
  const elapsed = (performance.now() - startUrl).toFixed(0);
182
263
  console.log(
183
- `[rsc-router] PASS ${entry.urlPath.padEnd(40)} (${elapsed}ms) - live fallback`,
264
+ `[rango] PASS ${entry.urlPath.padEnd(40)} (${elapsed}ms) - live fallback`,
184
265
  );
185
266
  doneCount++;
186
267
  break;
187
268
  }
188
269
 
189
270
  const paramHash = hashParams(result.params || {});
190
- collectedData[`${result.routeName}/${paramHash}`] = {
271
+ const mainKey = `${result.routeName}/${paramHash}`;
272
+ const mainValue = JSON.stringify({
191
273
  segments: result.segments,
192
274
  handles: result.handles,
193
- };
275
+ });
276
+ manifestEntries[mainKey] = stageBuildAssetModule(
277
+ state.projectRoot,
278
+ "__pr",
279
+ mainValue,
280
+ );
194
281
  if (result.interceptSegments?.length) {
195
- collectedData[`${result.routeName}/${paramHash}/i`] = {
282
+ const interceptKey = `${result.routeName}/${paramHash}/i`;
283
+ const interceptValue = JSON.stringify({
196
284
  segments: [...result.segments, ...result.interceptSegments],
197
285
  handles: {
198
286
  ...result.handles,
199
287
  ...(result.interceptHandles || {}),
200
288
  },
201
- };
289
+ });
290
+ manifestEntries[interceptKey] = stageBuildAssetModule(
291
+ state.projectRoot,
292
+ "__pr",
293
+ interceptValue,
294
+ );
202
295
  }
203
296
  const elapsed = (performance.now() - startUrl).toFixed(0);
204
297
  console.log(
205
- `[rsc-router] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`,
298
+ `[rango] OK ${entry.urlPath.padEnd(40)} (${elapsed}ms)`,
206
299
  );
207
300
  doneCount++;
208
301
  break;
@@ -210,7 +303,7 @@ export async function expandPrerenderRoutes(
210
303
  if (err.name === "Skip") {
211
304
  const elapsed = (performance.now() - startUrl).toFixed(0);
212
305
  console.log(
213
- `[rsc-router] SKIP ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
306
+ `[rango] SKIP ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
214
307
  );
215
308
  skipCount++;
216
309
  notifyOnError(
@@ -226,7 +319,7 @@ export async function expandPrerenderRoutes(
226
319
  // Regular error: log, notify, and fail the build
227
320
  const elapsed = (performance.now() - startUrl).toFixed(0);
228
321
  console.error(
229
- `[rsc-router] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
322
+ `[rango] FAIL ${entry.urlPath.padEnd(40)} (${elapsed}ms) - ${err.message}`,
230
323
  );
231
324
  notifyOnError(
232
325
  registry,
@@ -244,19 +337,27 @@ export async function expandPrerenderRoutes(
244
337
 
245
338
  const totalElapsed = (performance.now() - startTotal).toFixed(0);
246
339
  if (doneCount > 0) {
247
- state.prerenderCollectedData = collectedData;
340
+ state.prerenderManifestEntries = manifestEntries;
248
341
  }
249
342
  const parts = [`${doneCount} done`];
250
343
  if (skipCount > 0) parts.push(`${skipCount} skipped`);
251
344
  console.log(
252
- `[rsc-router] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`,
345
+ `[rango] Pre-render complete: ${parts.join(", ")} (${totalElapsed}ms total)`,
346
+ );
347
+ debug?.(
348
+ "expandPrerenderRoutes done: %d done, %d skipped, %sms (overall %sms)",
349
+ doneCount,
350
+ skipCount,
351
+ totalElapsed,
352
+ (performance.now() - overallStart).toFixed(1),
253
353
  );
254
354
  }
255
355
 
256
356
  /**
257
357
  * Render Static handlers at build time. Each Static handler is called
258
358
  * with a synthetic BuildContext and its output is RSC-serialized.
259
- * Stores collected data in state.staticCollectedData.
359
+ * Stages asset modules and stores handlerId-to-file entries in
360
+ * state.staticManifestEntries.
260
361
  */
261
362
  export async function renderStaticHandlers(
262
363
  state: DiscoveryState,
@@ -270,10 +371,13 @@ export async function renderStaticHandlers(
270
371
  )
271
372
  return;
272
373
 
273
- const collected: Record<
274
- string,
275
- { encoded: string; handles: Record<string, unknown[]> }
276
- > = {};
374
+ const overallStart = debug ? performance.now() : 0;
375
+ debug?.(
376
+ "renderStaticHandlers: start (%d static module(s))",
377
+ state.resolvedStaticModules.size,
378
+ );
379
+
380
+ const manifestEntries: Record<string, string> = {};
277
381
  let staticDone = 0;
278
382
  let staticSkip = 0;
279
383
  let totalStaticCount = 0;
@@ -283,9 +387,7 @@ export async function renderStaticHandlers(
283
387
  totalStaticCount += exportNames.length;
284
388
  }
285
389
  const startStatic = performance.now();
286
- console.log(
287
- `[rsc-router] Rendering ${totalStaticCount} static handler(s)...`,
288
- );
390
+ console.log(`[rango] Rendering ${totalStaticCount} static handler(s)...`);
289
391
 
290
392
  for (const [moduleId, exportNames] of state.resolvedStaticModules) {
291
393
  let mod: any;
@@ -293,7 +395,7 @@ export async function renderStaticHandlers(
293
395
  mod = await rscEnv!.runner.import(moduleId);
294
396
  } catch (err: any) {
295
397
  console.error(
296
- `[rsc-router] Failed to import static module ${moduleId}: ${err.message}`,
398
+ `[rango] Failed to import static module ${moduleId}: ${err.message}`,
297
399
  );
298
400
  notifyOnError(registry, err, "static");
299
401
  throw err;
@@ -314,13 +416,21 @@ export async function renderStaticHandlers(
314
416
  def.handler,
315
417
  def.$$id,
316
418
  (def as any).$$routePrefix,
419
+ state.resolvedBuildEnv,
420
+ !state.isBuildMode,
317
421
  );
318
422
  if (result) {
319
- collected[def.$$id] = result;
320
- const elapsed = (performance.now() - startHandler).toFixed(0);
321
- console.log(
322
- `[rsc-router] OK ${name.padEnd(40)} (${elapsed}ms)`,
423
+ const hasHandles = Object.keys(result.handles).length > 0;
424
+ const exportValue = hasHandles
425
+ ? JSON.stringify(result)
426
+ : JSON.stringify(result.encoded);
427
+ manifestEntries[def.$$id] = stageBuildAssetModule(
428
+ state.projectRoot,
429
+ "__st",
430
+ exportValue,
323
431
  );
432
+ const elapsed = (performance.now() - startHandler).toFixed(0);
433
+ console.log(`[rango] OK ${name.padEnd(40)} (${elapsed}ms)`);
324
434
  staticDone++;
325
435
  handled = true;
326
436
  break;
@@ -329,7 +439,7 @@ export async function renderStaticHandlers(
329
439
  if (err.name === "Skip") {
330
440
  const elapsed = (performance.now() - startHandler).toFixed(0);
331
441
  console.log(
332
- `[rsc-router] SKIP ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
442
+ `[rango] SKIP ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
333
443
  );
334
444
  staticSkip++;
335
445
  notifyOnError(registry, err, "static", undefined, undefined, true);
@@ -339,27 +449,32 @@ export async function renderStaticHandlers(
339
449
  // Regular error: log, notify, and fail the build
340
450
  const elapsed = (performance.now() - startHandler).toFixed(0);
341
451
  console.error(
342
- `[rsc-router] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
452
+ `[rango] FAIL ${name.padEnd(40)} (${elapsed}ms) - ${err.message}`,
343
453
  );
344
454
  notifyOnError(registry, err, "static");
345
455
  throw err;
346
456
  }
347
457
  }
348
458
  if (!handled) {
349
- console.warn(
350
- `[rsc-router] No router could render static handler "${name}"`,
351
- );
459
+ console.warn(`[rango] No router could render static handler "${name}"`);
352
460
  }
353
461
  }
354
462
  }
355
463
 
356
464
  const totalStaticElapsed = (performance.now() - startStatic).toFixed(0);
357
465
  if (staticDone > 0) {
358
- state.staticCollectedData = collected;
466
+ state.staticManifestEntries = manifestEntries;
359
467
  }
360
468
  const staticParts = [`${staticDone} done`];
361
469
  if (staticSkip > 0) staticParts.push(`${staticSkip} skipped`);
362
470
  console.log(
363
- `[rsc-router] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`,
471
+ `[rango] Static render complete: ${staticParts.join(", ")} (${totalStaticElapsed}ms total)`,
472
+ );
473
+ debug?.(
474
+ "renderStaticHandlers done: %d done, %d skipped, %sms (overall %sms)",
475
+ staticDone,
476
+ staticSkip,
477
+ totalStaticElapsed,
478
+ (performance.now() - overallStart).toFixed(1),
364
479
  );
365
480
  }