@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650

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 (356) hide show
  1. package/README.md +24 -9
  2. package/dist/bin/rango.js +157 -63
  3. package/dist/testing/vitest.js +82 -0
  4. package/dist/vite/index.js +1584 -639
  5. package/package.json +71 -21
  6. package/skills/api-client/SKILL.md +211 -0
  7. package/skills/breadcrumbs/SKILL.md +60 -0
  8. package/skills/bundle-analysis/SKILL.md +159 -0
  9. package/skills/cache-guide/SKILL.md +222 -30
  10. package/skills/caching/SKILL.md +263 -8
  11. package/skills/composability/SKILL.md +27 -2
  12. package/skills/css/SKILL.md +76 -0
  13. package/skills/document-cache/SKILL.md +78 -55
  14. package/skills/handler-use/SKILL.md +3 -1
  15. package/skills/hooks/SKILL.md +235 -28
  16. package/skills/host-router/SKILL.md +122 -22
  17. package/skills/i18n/SKILL.md +276 -0
  18. package/skills/intercept/SKILL.md +29 -5
  19. package/skills/layout/SKILL.md +13 -9
  20. package/skills/links/SKILL.md +173 -17
  21. package/skills/loader/SKILL.md +170 -23
  22. package/skills/middleware/SKILL.md +16 -10
  23. package/skills/migrate-nextjs/SKILL.md +38 -16
  24. package/skills/mime-routes/SKILL.md +27 -0
  25. package/skills/observability/SKILL.md +137 -0
  26. package/skills/parallel/SKILL.md +11 -7
  27. package/skills/prerender/SKILL.md +14 -33
  28. package/skills/rango/SKILL.md +250 -25
  29. package/skills/react-compiler/SKILL.md +168 -0
  30. package/skills/response-routes/SKILL.md +114 -47
  31. package/skills/route/SKILL.md +42 -5
  32. package/skills/router-setup/SKILL.md +3 -3
  33. package/skills/server-actions/SKILL.md +78 -42
  34. package/skills/tailwind/SKILL.md +27 -3
  35. package/skills/testing/SKILL.md +129 -0
  36. package/skills/testing/bindings.md +89 -0
  37. package/skills/testing/cache-prerender.md +124 -0
  38. package/skills/testing/client-components.md +122 -0
  39. package/skills/testing/e2e-parity.md +125 -0
  40. package/skills/testing/flight.md +92 -0
  41. package/skills/testing/handles.md +129 -0
  42. package/skills/testing/loader.md +128 -0
  43. package/skills/testing/middleware.md +99 -0
  44. package/skills/testing/render-handler.md +121 -0
  45. package/skills/testing/response-routes.md +95 -0
  46. package/skills/testing/reverse-and-types.md +84 -0
  47. package/skills/testing/server-actions.md +107 -0
  48. package/skills/testing/server-tree.md +128 -0
  49. package/skills/testing/setup.md +120 -0
  50. package/skills/typesafety/SKILL.md +316 -26
  51. package/skills/use-cache/SKILL.md +36 -5
  52. package/skills/vercel/SKILL.md +107 -0
  53. package/skills/view-transitions/SKILL.md +294 -0
  54. package/src/__augment-tests__/augment.ts +81 -0
  55. package/src/__augment-tests__/augmented.check.ts +116 -0
  56. package/src/__internal.ts +0 -65
  57. package/src/browser/action-coordinator.ts +53 -36
  58. package/src/browser/action-fence.ts +47 -0
  59. package/src/browser/app-shell.ts +14 -27
  60. package/src/browser/cookie-name.ts +140 -0
  61. package/src/browser/event-controller.ts +37 -143
  62. package/src/browser/history-state.ts +21 -0
  63. package/src/browser/index.ts +3 -3
  64. package/src/browser/invalidate-client-cache.ts +52 -0
  65. package/src/browser/navigation-bridge.ts +30 -59
  66. package/src/browser/navigation-client.ts +96 -84
  67. package/src/browser/navigation-store-handle.ts +38 -0
  68. package/src/browser/navigation-store.ts +32 -82
  69. package/src/browser/navigation-transaction.ts +9 -59
  70. package/src/browser/partial-update.ts +60 -127
  71. package/src/browser/prefetch/cache.ts +82 -72
  72. package/src/browser/prefetch/fetch.ts +108 -33
  73. package/src/browser/prefetch/queue.ts +6 -3
  74. package/src/browser/rango-state.ts +157 -115
  75. package/src/browser/react/Link.tsx +0 -2
  76. package/src/browser/react/NavigationProvider.tsx +41 -48
  77. package/src/browser/react/ScrollRestoration.tsx +10 -6
  78. package/src/browser/react/filter-segment-order.ts +0 -2
  79. package/src/browser/react/index.ts +0 -48
  80. package/src/browser/react/location-state-shared.ts +166 -8
  81. package/src/browser/react/location-state.ts +39 -14
  82. package/src/browser/react/use-action.ts +6 -15
  83. package/src/browser/react/use-handle.ts +17 -14
  84. package/src/browser/react/use-link-status.ts +0 -4
  85. package/src/browser/react/use-navigation.ts +0 -3
  86. package/src/browser/react/use-params.ts +11 -11
  87. package/src/browser/react/use-reverse.ts +106 -0
  88. package/src/browser/react/use-router.ts +20 -5
  89. package/src/browser/react/use-search-params.ts +0 -5
  90. package/src/browser/react/use-segments.ts +0 -13
  91. package/src/browser/response-adapter.ts +52 -1
  92. package/src/browser/rsc-router.tsx +70 -34
  93. package/src/browser/scroll-restoration.ts +22 -14
  94. package/src/browser/segment-structure-assert.ts +2 -2
  95. package/src/browser/server-action-bridge.ts +168 -44
  96. package/src/browser/types.ts +36 -21
  97. package/src/browser/validate-redirect-origin.ts +43 -16
  98. package/src/build/collect-fallback-refs.ts +107 -0
  99. package/src/build/generate-manifest.ts +60 -35
  100. package/src/build/generate-route-types.ts +3 -0
  101. package/src/build/index.ts +8 -2
  102. package/src/build/prefix-tree-utils.ts +123 -0
  103. package/src/build/route-trie.ts +89 -10
  104. package/src/build/route-types/codegen.ts +4 -4
  105. package/src/build/route-types/include-resolution.ts +1 -1
  106. package/src/build/route-types/param-extraction.ts +6 -3
  107. package/src/build/route-types/per-module-writer.ts +7 -4
  108. package/src/build/route-types/router-processing.ts +122 -22
  109. package/src/build/route-types/scan-filter.ts +1 -1
  110. package/src/build/route-types/source-scan.ts +118 -0
  111. package/src/build/runtime-discovery.ts +9 -20
  112. package/src/cache/cache-error.ts +104 -0
  113. package/src/cache/cache-policy.ts +68 -28
  114. package/src/cache/cache-runtime.ts +134 -32
  115. package/src/cache/cache-scope.ts +100 -74
  116. package/src/cache/cache-tag.ts +98 -0
  117. package/src/cache/cf/cf-cache-store.ts +2255 -238
  118. package/src/cache/cf/index.ts +6 -16
  119. package/src/cache/document-cache.ts +61 -20
  120. package/src/cache/handle-snapshot.ts +63 -0
  121. package/src/cache/index.ts +22 -20
  122. package/src/cache/memory-segment-store.ts +136 -37
  123. package/src/cache/profile-registry.ts +6 -30
  124. package/src/cache/read-through-swr.ts +41 -11
  125. package/src/cache/segment-codec.ts +0 -16
  126. package/src/cache/tag-invalidation.ts +230 -0
  127. package/src/cache/types.ts +33 -100
  128. package/src/cache/vercel/index.ts +11 -0
  129. package/src/cache/vercel/vercel-cache-store.ts +799 -0
  130. package/src/client.rsc.tsx +6 -21
  131. package/src/client.tsx +25 -61
  132. package/src/component-utils.ts +19 -0
  133. package/src/context-var.ts +17 -5
  134. package/src/decode-loader-results.ts +36 -0
  135. package/src/defer.ts +196 -0
  136. package/src/deps/ssr.ts +0 -1
  137. package/src/errors.ts +30 -4
  138. package/src/handle.ts +31 -23
  139. package/src/handles/MetaTags.tsx +0 -14
  140. package/src/handles/breadcrumbs.ts +16 -5
  141. package/src/handles/meta.ts +0 -39
  142. package/src/host/cookie-handler.ts +0 -36
  143. package/src/host/errors.ts +0 -24
  144. package/src/host/index.ts +8 -2
  145. package/src/host/pattern-matcher.ts +7 -50
  146. package/src/host/router.ts +107 -99
  147. package/src/host/testing.ts +40 -27
  148. package/src/host/types.ts +37 -4
  149. package/src/host/utils.ts +1 -1
  150. package/src/href-client.ts +137 -22
  151. package/src/index.rsc.ts +63 -9
  152. package/src/index.ts +64 -9
  153. package/src/internal-debug.ts +2 -4
  154. package/src/loader-store.ts +500 -0
  155. package/src/loader.rsc.ts +20 -13
  156. package/src/loader.ts +12 -11
  157. package/src/missing-id-error.ts +68 -0
  158. package/src/network-error-thrower.tsx +1 -6
  159. package/src/outlet-provider.tsx +1 -5
  160. package/src/prerender/param-hash.ts +10 -11
  161. package/src/prerender/store.ts +32 -37
  162. package/src/prerender.ts +61 -6
  163. package/src/redirect-origin.ts +100 -0
  164. package/src/response-utils.ts +9 -0
  165. package/src/reverse.ts +65 -40
  166. package/src/root-error-boundary.tsx +1 -19
  167. package/src/route-content-wrapper.tsx +7 -72
  168. package/src/route-definition/dsl-helpers.ts +244 -281
  169. package/src/route-definition/helper-factories.ts +29 -139
  170. package/src/route-definition/helpers-types.ts +40 -17
  171. package/src/route-definition/redirect.ts +43 -9
  172. package/src/route-definition/resolve-handler-use.ts +6 -0
  173. package/src/route-definition/use-item-types.ts +32 -0
  174. package/src/route-map-builder.ts +0 -16
  175. package/src/route-types.ts +19 -41
  176. package/src/router/basename.ts +14 -0
  177. package/src/router/content-negotiation.ts +15 -15
  178. package/src/router/error-handling.ts +13 -17
  179. package/src/router/find-match.ts +44 -23
  180. package/src/router/handler-context.ts +4 -41
  181. package/src/router/intercept-resolution.ts +14 -19
  182. package/src/router/lazy-includes.ts +9 -46
  183. package/src/router/loader-resolution.ts +91 -46
  184. package/src/router/logging.ts +0 -6
  185. package/src/router/manifest.ts +18 -29
  186. package/src/router/match-api.ts +0 -20
  187. package/src/router/match-context.ts +0 -22
  188. package/src/router/match-handlers.ts +57 -58
  189. package/src/router/match-middleware/background-revalidation.ts +0 -7
  190. package/src/router/match-middleware/cache-lookup.ts +150 -271
  191. package/src/router/match-middleware/cache-store.ts +3 -33
  192. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  193. package/src/router/match-middleware/segment-resolution.ts +0 -22
  194. package/src/router/match-pipelines.ts +1 -42
  195. package/src/router/match-result.ts +31 -80
  196. package/src/router/metrics.ts +0 -34
  197. package/src/router/middleware-types.ts +5 -112
  198. package/src/router/middleware.ts +118 -133
  199. package/src/router/navigation-snapshot.ts +0 -51
  200. package/src/router/params-util.ts +23 -0
  201. package/src/router/pattern-matching.ts +62 -67
  202. package/src/router/prerender-match.ts +99 -63
  203. package/src/router/preview-match.ts +3 -1
  204. package/src/router/request-classification.ts +28 -62
  205. package/src/router/revalidation.ts +50 -56
  206. package/src/router/route-snapshot.ts +0 -1
  207. package/src/router/router-context.ts +0 -27
  208. package/src/router/router-interfaces.ts +68 -35
  209. package/src/router/router-options.ts +55 -1
  210. package/src/router/router-registry.ts +2 -5
  211. package/src/router/segment-resolution/fresh.ts +44 -63
  212. package/src/router/segment-resolution/helpers.ts +34 -0
  213. package/src/router/segment-resolution/loader-cache.ts +40 -37
  214. package/src/router/segment-resolution/revalidation.ts +203 -285
  215. package/src/router/segment-resolution/static-store.ts +19 -5
  216. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  217. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  218. package/src/router/segment-resolution.ts +4 -1
  219. package/src/router/segment-wrappers.ts +0 -3
  220. package/src/router/state-cookie-name.ts +33 -0
  221. package/src/router/substitute-pattern-params.ts +56 -0
  222. package/src/router/telemetry-otel.ts +0 -20
  223. package/src/router/telemetry.ts +96 -19
  224. package/src/router/timeout.ts +0 -20
  225. package/src/router/trie-matching.ts +87 -48
  226. package/src/router/types.ts +9 -63
  227. package/src/router/url-params.ts +0 -5
  228. package/src/router.ts +80 -41
  229. package/src/rsc/handler-context.ts +3 -2
  230. package/src/rsc/handler.ts +83 -78
  231. package/src/rsc/helpers.ts +93 -5
  232. package/src/rsc/index.ts +1 -1
  233. package/src/rsc/json-route-result.ts +38 -0
  234. package/src/rsc/manifest-init.ts +28 -41
  235. package/src/rsc/origin-guard.ts +39 -25
  236. package/src/rsc/progressive-enhancement.ts +12 -1
  237. package/src/rsc/redirect-guard.ts +99 -0
  238. package/src/rsc/response-error.ts +79 -12
  239. package/src/rsc/response-route-handler.ts +76 -62
  240. package/src/rsc/rsc-rendering.ts +41 -60
  241. package/src/rsc/runtime-warnings.ts +23 -10
  242. package/src/rsc/server-action.ts +62 -67
  243. package/src/rsc/ssr-setup.ts +16 -0
  244. package/src/rsc/types.ts +10 -5
  245. package/src/runtime-env.ts +18 -0
  246. package/src/search-params.ts +4 -20
  247. package/src/segment-loader-promise.ts +14 -2
  248. package/src/segment-system.tsx +199 -142
  249. package/src/serialize.ts +243 -0
  250. package/src/server/context.ts +150 -51
  251. package/src/server/cookie-store.ts +80 -5
  252. package/src/server/handle-store.ts +7 -24
  253. package/src/server/loader-registry.ts +5 -24
  254. package/src/server/request-context.ts +165 -87
  255. package/src/ssr/index.tsx +14 -14
  256. package/src/static-handler.ts +10 -13
  257. package/src/testing/cache-status.ts +162 -0
  258. package/src/testing/collect-handle.ts +40 -0
  259. package/src/testing/dispatch.ts +618 -0
  260. package/src/testing/dom.entry.ts +22 -0
  261. package/src/testing/e2e/fixture.ts +188 -0
  262. package/src/testing/e2e/index.ts +128 -0
  263. package/src/testing/e2e/matchers.ts +35 -0
  264. package/src/testing/e2e/page-helpers.ts +272 -0
  265. package/src/testing/e2e/parity.ts +387 -0
  266. package/src/testing/e2e/server.ts +195 -0
  267. package/src/testing/flight-matchers.ts +97 -0
  268. package/src/testing/flight-normalize.ts +11 -0
  269. package/src/testing/flight-runtime.d.ts +57 -0
  270. package/src/testing/flight-tree.ts +682 -0
  271. package/src/testing/flight.entry.ts +52 -0
  272. package/src/testing/flight.ts +232 -0
  273. package/src/testing/generated-routes.ts +183 -0
  274. package/src/testing/index.ts +99 -0
  275. package/src/testing/internal/context.ts +348 -0
  276. package/src/testing/internal/flight-client-globals.ts +30 -0
  277. package/src/testing/internal/seed-vars.ts +54 -0
  278. package/src/testing/render-handler.ts +330 -0
  279. package/src/testing/render-route.tsx +566 -0
  280. package/src/testing/run-loader.ts +378 -0
  281. package/src/testing/run-middleware.ts +205 -0
  282. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  283. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  284. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  285. package/src/testing/vitest-stubs/version.ts +5 -0
  286. package/src/testing/vitest.ts +305 -0
  287. package/src/theme/ThemeProvider.tsx +0 -52
  288. package/src/theme/ThemeScript.tsx +0 -6
  289. package/src/theme/constants.ts +0 -12
  290. package/src/theme/index.ts +0 -7
  291. package/src/theme/theme-context.ts +1 -5
  292. package/src/theme/theme-script.ts +0 -14
  293. package/src/theme/use-theme.ts +0 -3
  294. package/src/types/boundaries.ts +0 -35
  295. package/src/types/cache-types.ts +13 -4
  296. package/src/types/error-types.ts +30 -90
  297. package/src/types/global-namespace.ts +54 -41
  298. package/src/types/handler-context.ts +97 -22
  299. package/src/types/index.ts +1 -10
  300. package/src/types/loader-types.ts +6 -3
  301. package/src/types/request-scope.ts +0 -19
  302. package/src/types/route-config.ts +6 -50
  303. package/src/types/route-entry.ts +0 -6
  304. package/src/types/segments.ts +18 -14
  305. package/src/urls/include-helper.ts +9 -56
  306. package/src/urls/index.ts +1 -11
  307. package/src/urls/path-helper-types.ts +19 -5
  308. package/src/urls/path-helper.ts +17 -106
  309. package/src/urls/pattern-types.ts +36 -19
  310. package/src/urls/response-types.ts +20 -19
  311. package/src/urls/type-extraction.ts +58 -139
  312. package/src/urls/urls-function.ts +1 -18
  313. package/src/use-loader.tsx +292 -107
  314. package/src/vite/debug.ts +1 -0
  315. package/src/vite/discovery/bundle-postprocess.ts +8 -7
  316. package/src/vite/discovery/discover-routers.ts +95 -82
  317. package/src/vite/discovery/discovery-errors.ts +194 -0
  318. package/src/vite/discovery/prerender-collection.ts +26 -34
  319. package/src/vite/discovery/route-types-writer.ts +40 -84
  320. package/src/vite/discovery/state.ts +39 -1
  321. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  322. package/src/vite/index.ts +4 -0
  323. package/src/vite/plugin-types.ts +185 -10
  324. package/src/vite/plugins/cjs-to-esm.ts +3 -18
  325. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  326. package/src/vite/plugins/client-ref-hashing.ts +12 -11
  327. package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
  328. package/src/vite/plugins/expose-action-id.ts +4 -75
  329. package/src/vite/plugins/expose-id-utils.ts +3 -54
  330. package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
  331. package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
  332. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
  333. package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
  334. package/src/vite/plugins/expose-internal-ids.ts +57 -67
  335. package/src/vite/plugins/performance-tracks.ts +9 -16
  336. package/src/vite/plugins/refresh-cmd.ts +1 -1
  337. package/src/vite/plugins/use-cache-transform.ts +26 -49
  338. package/src/vite/plugins/vercel-output.ts +258 -0
  339. package/src/vite/plugins/version-injector.ts +2 -32
  340. package/src/vite/plugins/version-plugin.ts +32 -23
  341. package/src/vite/plugins/virtual-entries.ts +35 -17
  342. package/src/vite/rango.ts +148 -115
  343. package/src/vite/router-discovery.ts +220 -68
  344. package/src/vite/utils/ast-handler-extract.ts +15 -31
  345. package/src/vite/utils/bundle-analysis.ts +10 -15
  346. package/src/vite/utils/client-chunks.ts +184 -0
  347. package/src/vite/utils/forward-user-plugins.ts +171 -0
  348. package/src/vite/utils/manifest-utils.ts +4 -59
  349. package/src/vite/utils/package-resolution.ts +1 -73
  350. package/src/vite/utils/prerender-utils.ts +0 -34
  351. package/src/vite/utils/shared-utils.ts +95 -43
  352. package/src/browser/action-response-classifier.ts +0 -99
  353. package/src/browser/react/use-client-cache.ts +0 -58
  354. package/src/browser/shallow.ts +0 -40
  355. package/src/handles/index.ts +0 -7
  356. package/src/router/middleware-cookies.ts +0 -55
@@ -8,33 +8,249 @@ argument-hint:
8
8
 
9
9
  Django-inspired RSC router with composable URL patterns, type-safe href, and server components.
10
10
 
11
+ This page is the mental model to read **before** the catalog. A flat list of
12
+ skills gives nothing to slot details into, so a reader free-associates from local
13
+ vocabulary — which is exactly how `revalidate()` gets misread as caching. Start
14
+ with the shape, then pick a primitive.
15
+
16
+ ## The shape of rango (read first)
17
+
18
+ - **Routes are expressed, not configured.** The `urls()` tree shows where every
19
+ route, layout, loader, and cache lives. No file-system convention, no hunting.
20
+ - **Two freshness axes, orthogonal:**
21
+ - _stored-value freshness_ — `"use cache"`, `cache()`, loader `cache()`
22
+ (SWR is first-class where the store supports it; `"use cache"` ships a
23
+ default SWR window; see `/cache-guide`)
24
+ - _client-update selection_ — `revalidate()`
25
+ - **Loaders are the live data layer** — fresh every request by default, even
26
+ inside a cached render. They run **in parallel** right after middleware and
27
+ **stream**, so data latency overlaps first paint instead of blocking it (a
28
+ cache hit streams UI instantly while loaders resolve fresh alongside). Opt into
29
+ caching explicitly. See `/loader` → "Parallel and streaming".
30
+ - **One identity, one store** — loaders, handles, cached fns, and actions are all
31
+ `path#export`; all caches share one store. Entries expire by TTL/SWR, and are
32
+ tagged via `cache({ tags })` or runtime `cacheTag(...tags)`; built-in stores
33
+ index by tag and invalidate via `updateTag(...tags)` (awaitable, read-your-own-writes)
34
+ or `revalidateTag(...tags)` (background, non-blocking).
35
+ - **Type-safe end to end** — route names, params, search schemas, loader return
36
+ types, context vars, and `href` / `reverse` are checked at compile time
37
+ (`/typesafety`).
38
+ - **See where time goes** — turn on `debugPerformance` early (router option, or
39
+ `ctx.debugPerformance()` in middleware for per-request opt-in). It prints a
40
+ per-request waterfall + `Server-Timing` header; loaders should overlap the
41
+ render bar, not serialize after it. For production, wire `telemetry` to a
42
+ console, OpenTelemetry, or custom sink. See `/observability`.
43
+
44
+ Most features are **just-in-time**: the core is `urls()`, `path()`, `layout()`,
45
+ `include()`, and `reverse()`. Caching, parallel routes, intercepts, prerender,
46
+ i18n, themes, and the rest are opt-in — reach for them when a requirement
47
+ appears, not up front.
48
+
49
+ ## Composability: structure vs config
50
+
51
+ - `path()` / `include()` are **structure** — they define URLs and must stay
52
+ visible in `urls()`. They cannot be hidden in a factory. `include()` composes
53
+ whole modules (separation of real concerns); `path()` places a leaf.
54
+ - Everything else — `cache`, `loader`, `loading`, `middleware`, `revalidate`,
55
+ `parallel`, `intercept`, `errorBoundary`, … — is **config**. It attaches to a
56
+ node via its `use` callback, is importable, and extracts into factories that
57
+ return arrays (`withAuth()`, `withCaching()`), flattened automatically.
58
+
59
+ To decide where something can live: **does it define a URL? structure, stays in
60
+ `urls()`. Does it modify a node? config, compose freely.**
61
+
62
+ ## Pick a primitive
63
+
64
+ | I need to… | Use | Skill |
65
+ | ------------------------------------- | -------------------------------- | ----------------------- |
66
+ | render data fresh every request | `loader()` + `useLoader()` | /loader |
67
+ | cache a rendered subtree | `cache()` on a segment | /caching |
68
+ | cache one function/component's result | `"use cache"` | /use-cache |
69
+ | cache a loader's data | `loader(L, () => [cache()])` | /loader, /caching |
70
+ | re-render a segment after an action | `revalidate()` | /loader |
71
+ | mutate | `"use server"` action | /server-actions |
72
+ | debug a slow request | `debugPerformance` / telemetry | /observability |
73
+ | share config across routes | factory returning a helper array | /composability |
74
+ | compose a sub-app / module | `include()` | /route |
75
+ | modal / soft navigation | `intercept()` | /intercept |
76
+ | pre-render a route at build time | `Prerender(...)` wrapper | /prerender |
77
+ | stream SSE / upgrade a WebSocket | `path.stream()` / `path.any()` | /streams-and-websockets |
78
+
79
+ ## Invariants
80
+
81
+ - `path()`/`include()` are always visible in `urls()`; config helpers are extractable.
82
+ - **Cache decides freshness; `revalidate()` decides client-update.** Orthogonal; compose.
83
+ - Loaders resolve fresh every request (even inside `cache()`) and never run twice/request.
84
+ - Inside `"use cache"`: `cookies()`/`headers()` and `ctx` side-effects
85
+ (`set`/`header`/`setTheme`/`onResponse`/`setLocationState`) throw; `ctx.use(Handle)`
86
+ is captured on miss and replayed on hit. (The non-cacheable read guard is a
87
+ separate `cache()`-boundary check — see the correctness bullet below.)
88
+ - One identity `path#export` (`functionId`/`$$id`/`actionId`); one store. Freshness
89
+ is TTL/SWR expiry plus tag-based invalidation: tag via `cache({ tags })` /
90
+ `cacheTag(...tags)`, then `updateTag(...tags)` (awaitable) or `revalidateTag(...tags)`
91
+ (background). Built-in stores index by tag.
92
+ - `useLoader` / `useHandle` / `useFetchLoader` are client-only.
93
+ - Caches are correctness-first: persistent store keys are version-segmented (no
94
+ cross-deploy drift), the forward/back cache is mutation-aware, and
95
+ `createVar({ cache: false })` throws on a **direct** read inside a `cache()`
96
+ boundary (a deliberately non-propagating guard). See `/cache-guide` →
97
+ "Correctness & invalidation".
98
+ - Nested caches: the outer cache window bounds the inner — an inner shorter TTL
99
+ only applies when the enclosing cache recomputes; put a value in a loader if it
100
+ must be fresher. See `/cache-guide` → "Combining Both".
101
+
102
+ ## Don't confuse
103
+
104
+ - `revalidate()` ≠ cache invalidation — partial-render selection vs value freshness.
105
+ - host router `.lazy()` (lazy import of a handler/sub-app) vs `.map()` (inline Response).
106
+ - `cache()` (segment, in the DSL) vs `"use cache"` (function/component directive).
107
+ - `loader()` registration (server) vs `useLoader()` consumption (client).
108
+
109
+ ### Coming from another framework (false friends)
110
+
111
+ Same words, different jobs — this is the most common source of the
112
+ `revalidate()`-is-caching misread.
113
+
114
+ | You may know | Maps to Rango axis | Watch out |
115
+ | --------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
116
+ | Next.js `export const revalidate = N` | **Axis 1** (cache) | Same word, opposite meaning. Next's `revalidate` is time-based cache expiry; Rango's `revalidate()` is **axis 2**. Use `cache({ ttl })` for the Next behavior. |
117
+ | Next.js `revalidateTag` / `updateTag` | **Axis 1** (cache) | Cache busting by tag. Tag via `cache({ tags })` / `cacheTag(...tags)`; invalidate with `updateTag(...tags)` (awaitable, read-your-own-writes) or `revalidateTag(...tags)` (background, non-blocking). Built-in stores index by tag. No `revalidatePath` (path-based busting); use tags. |
118
+ | React Router / Remix `shouldRevalidate` | **Axis 2** | This is the correct mental model for Rango's `revalidate()`. |
119
+ | HTTP `Cache-Control` / ISR | **Axis 1** | Edge/document layer — see `/document-cache`. Separate from both `cache()` and `revalidate()`. |
120
+ | Remix/RR `loader` | live data | Like Rango loaders, fresh per request — but Rango loaders run in parallel and stream (latency overlaps first paint), and can opt into caching on demand. |
121
+
122
+ See `/cache-guide` for the axis-1 decision guide, `/loader` and `/route` for
123
+ `revalidate()` (axis 2), and `/document-cache` for the edge layer.
124
+
125
+ ## Canonical shape
126
+
127
+ ```ts
128
+ export const urlpatterns = urls(({ path, layout, loader, loading, cache, revalidate }) => [
129
+ layout(<ShopLayout />, () => [ // structure: wraps children
130
+ loader(CartLoader, () => [ // config: live data
131
+ // partial-render axis: re-run on cart actions, defer otherwise.
132
+ // ctx.isAction() matches by reference (rename-safe), not by string.
133
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
134
+ ]),
135
+ path("/shop/:slug", ProductPage, { name: "product" }, () => [ // structure: leaf
136
+ loader(ProductLoader, () => [cache({ ttl: 60 })]), // config: cache loader DATA
137
+ loading(<ProductSkeleton />), // config
138
+ withRecs(), // composed factory (config array)
139
+ ]),
140
+ ]),
141
+ ]);
142
+ ```
143
+
144
+ One tree, both axes visible: structure (`layout`/`path`) vs config (everything
145
+ else), freshness (`cache`) vs client-update (`revalidate`). Actions are matched
146
+ by reference with `ctx.isAction(Action)` (rename-safe, where `CartActions` is an
147
+ `import * as CartActions from "./actions/cart"`); see `/typesafety` → "Stable
148
+ identity".
149
+
150
+ The predicate arg carries the action's full context, not just its identity. Match
151
+ _which_ action with `ctx.isAction(addToCart)` (rename-safe); branch on _what it
152
+ returned_ with `ctx.actionResult` — the value your `"use server"` function
153
+ returned, for outcome-conditional revalidation. The arg also exposes `actionId`
154
+ (raw `path#export`), `actionUrl`, `formData`, `method`, and `stale` (cross-tab
155
+ `_rsc_stale` signal). All are `undefined` on plain navigation (no action).
156
+
157
+ Two idioms, picked by what an _unrelated_ action should do. `ctx.isAction()`
158
+ returns a raw boolean, so combine it with `|| undefined` to **defer** ("mine,
159
+ else let the default decide": `ctx.isAction(CartActions) || undefined`) or leave
160
+ it bare to **suppress** ("mine only": `ctx.isAction(CartActions)`). Prefer the
161
+ defer form unless a sibling segment must own the unrelated-action decision.
162
+
163
+ ```ts
164
+ // re-render only when checkout actually succeeded; defer otherwise
165
+ revalidate((ctx) => (ctx.isAction(checkout) && ctx.actionResult?.ok) || undefined),
166
+ ```
167
+
168
+ **The source is the source of truth.** Structure, types, and update policy are
169
+ visible and local in the tree — read top-down, no hidden global model to hold in
170
+ your head. A snippet earns its place only if, from the code alone, you can answer:
171
+ _what URLs exist and who owns them?_ (composition), _can I trust this reference
172
+ without leaving the call site?_ (type-safety), _what re-renders after this
173
+ action?_ (partial rendering). If any answer needs another file, it isn't legible
174
+ yet.
175
+
176
+ **Reading Rango's own source.** Rango is consumed as raw TypeScript — the
177
+ `exports` map resolves `@rangojs/router` and its subpaths to `./src/*.ts` for
178
+ both types and runtime, so a consuming app bundles Rango straight from source.
179
+ Only the `./vite` plugin entry and the CLI `bin` load from `dist/`. To confirm
180
+ any runtime or type detail against an installed copy, read the resolved source
181
+ under `node_modules/@rangojs/router/src/`, not `dist/` — the runtime does not
182
+ resolve `dist/` outside `./vite`, and it may lag `src/`.
183
+
11
184
  ## Skills
12
185
 
13
- | Skill | Description |
14
- | ----------------------- | -------------------------------------------------------------------------- |
15
- | `/router-setup` | Create and configure the RSC router |
16
- | `/route` | Define routes with `urls()` and `path()` |
17
- | `/layout` | Layouts that wrap child routes |
18
- | `/loader` | Data loaders with `createLoader()` |
19
- | `/server-actions` | Mutations with `"use server"`, useActionState, validation, revalidation |
20
- | `/middleware` | Request processing and authentication |
21
- | `/intercept` | Modal/slide-over patterns for soft navigation |
22
- | `/parallel` | Multi-column layouts and sidebars |
23
- | `/caching` | Segment caching with memory or KV stores |
24
- | `/use-cache` | Function-level caching with `"use cache"` directive |
25
- | `/cache-guide` | When to use `cache()` vs `"use cache"` — differences and decision guide |
26
- | `/document-cache` | Edge caching with Cache-Control headers |
27
- | `/theme` | Light/dark mode with FOUC prevention |
28
- | `/links` | URL generation: ctx.reverse, href, useHref, useMount, scopedReverse |
29
- | `/hooks` | Client-side React hooks |
30
- | `/typesafety` | Type-safe routes, params, href, and environment |
31
- | `/host-router` | Multi-app host routing with domain/subdomain patterns |
32
- | `/tailwind` | Set up Tailwind CSS v4 with `?url` imports |
33
- | `/response-routes` | JSON/text/HTML/XML/stream endpoints with `path.json()`, `path.text()` |
34
- | `/mime-routes` | Content negotiation same URL, different response types via Accept header |
35
- | `/fonts` | Load web fonts with preload hints |
36
- | `/migrate-nextjs` | Migrate a Next.js App Router project to Rango |
37
- | `/migrate-react-router` | Migrate a React Router / Remix project to Rango |
186
+ Grouped by concern — read when you need to…
187
+
188
+ **Structure & routing** shape URLs, layouts, navigation, and request processing:
189
+
190
+ | Skill | Description |
191
+ | ------------------------- | -------------------------------------------------------------------------- |
192
+ | `/router-setup` | Create and configure the RSC router |
193
+ | `/route` | Define routes with `urls()`, `path()`, and `include()` |
194
+ | `/layout` | Layouts that wrap child routes |
195
+ | `/parallel` | Multi-column layouts and sidebars |
196
+ | `/intercept` | Modal/slide-over patterns for soft navigation |
197
+ | `/middleware` | Request processing and authentication |
198
+ | `/host-router` | Multi-app host routing with domain/subdomain patterns |
199
+ | `/links` | URL generation: ctx.reverse, href, useHref, useMount, scopedReverse |
200
+ | `/response-routes` | JSON/text/HTML/XML/stream endpoints with `path.json()`, `path.text()` |
201
+ | `/api-client` | Typed client for consuming your own response-route JSON APIs (recipe) |
202
+ | `/mime-routes` | Content negotiation — same URL, different response types via Accept header |
203
+ | `/streams-and-websockets` | SSE via `path.stream` and WebSocket upgrades via `path.any` |
204
+ | `/handler-use` | Attach default loaders/middleware to a handler via `handler.use` |
205
+ | `/composability` | Reusable route-helper factories (structure vs config) |
206
+
207
+ **Data & caching**fetch, mutate, and cache:
208
+
209
+ | Skill | Description |
210
+ | ----------------- | ----------------------------------------------------------------------- |
211
+ | `/loader` | Data loaders with `createLoader()` and `revalidate()` |
212
+ | `/server-actions` | Mutations with `"use server"`, useActionState, validation, revalidation |
213
+ | `/caching` | Segment caching with memory or KV stores |
214
+ | `/use-cache` | Function-level caching with `"use cache"` directive |
215
+ | `/cache-guide` | When to use `cache()` vs `"use cache"` — differences and decision guide |
216
+ | `/document-cache` | Edge caching with Cache-Control headers |
217
+ | `/prerender` | Pre-render route segments at build time (Passthrough live fallback) |
218
+
219
+ **Client & presentation** — build the client-side UX:
220
+
221
+ | Skill | Description |
222
+ | ------------------- | ------------------------------------------------------------------------- |
223
+ | `/hooks` | Client-side React hooks |
224
+ | `/theme` | Light/dark mode with FOUC prevention |
225
+ | `/i18n` | Locale routing with `:locale?`, resolution chains, react-intl integration |
226
+ | `/fonts` | Load web fonts with preload hints |
227
+ | `/css` | Import CSS in the Document `<head>` (`?url` + managed `precedence` links) |
228
+ | `/tailwind` | Set up Tailwind CSS v4 with `?url` imports |
229
+ | `/view-transitions` | React View Transitions on layouts, routes, and parallel slots |
230
+ | `/breadcrumbs` | Built-in Breadcrumbs handle for breadcrumb navigation |
231
+ | `/react-compiler` | Enable React Compiler (opt-in) the vite-rsc way; client-only scope |
232
+
233
+ **Observability & production health**:
234
+
235
+ | Skill | Description |
236
+ | ------------------ | ------------------------------------------------------------------------ |
237
+ | `/observability` | `debugPerformance`, `Server-Timing`, structured telemetry, tracing |
238
+ | `/bundle-analysis` | Audit your app's production bundle for server leaks and oversized chunks |
239
+ | `/debug-manifest` | Inspect route manifest structure |
240
+
241
+ **Testing**:
242
+
243
+ | Skill | Description |
244
+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------- |
245
+ | `/testing` | Unit (loaders/middleware/reverse/components), integration (dispatch/Flight), and e2e (dev+prod parity, progressive enhancement) |
246
+
247
+ **Setup, types & migration**:
248
+
249
+ | Skill | Description |
250
+ | ----------------------- | ----------------------------------------------- |
251
+ | `/typesafety` | Type-safe routes, params, href, and environment |
252
+ | `/migrate-nextjs` | Migrate a Next.js App Router project to Rango |
253
+ | `/migrate-react-router` | Migrate a React Router / Remix project to Rango |
38
254
 
39
255
  ## Quick Start
40
256
 
@@ -90,6 +306,15 @@ Each file is classified by its contents:
90
306
  Directories are scanned recursively for `.ts`/`.tsx` files, skipping `node_modules`,
91
307
  dotfiles, and existing `.gen.` files.
92
308
 
309
+ > The two generated files are **not interchangeable surfaces**.
310
+ > `router.named-routes.gen.ts` augments the global `GeneratedRouteMap` for
311
+ > named-route typing (`Handler<"name">`, `ctx.reverse("name")`, prerender).
312
+ > Per-module `*.gen.ts` exports a local `routes` map for `useReverse(routes)`
313
+ > and explicit local handler typing (`Handler<".name", routes>`). Neither
314
+ > carries response payloads — response/MIME payload inference comes from
315
+ > `typeof router.routeMap` via `RegisteredRoutes`, not `*.named-routes.gen.ts`.
316
+ > See `/typesafety` for the full surface breakdown.
317
+
93
318
  ### Recursive includes
94
319
 
95
320
  The generator follows `include()` calls across files, resolving imports to build
@@ -0,0 +1,168 @@
1
+ ---
2
+ name: react-compiler
3
+ description: Enable the React Compiler in a Rango app the @vitejs/plugin-rsc way — a separate @rolldown/plugin-babel running reactCompilerPreset(), ordered after react() and before the plugin that supplies @vitejs/plugin-rsc. Use when a consumer wants to turn React Compiler on, hits the dead plugin-react v6 `react({ babel })` path, or is unsure why server components aren't being compiled.
4
+ argument-hint:
5
+ ---
6
+
7
+ # React Compiler
8
+
9
+ React Compiler is **opt-in** in Rango. The plugin pipeline is fully compatible —
10
+ you just add one more plugin. The catch on a current Rango stack (Vite 8 +
11
+ `@vitejs/plugin-react` v6) is that **v6 dropped its internal Babel for oxc**, so
12
+ the way the React docs and most blog posts show it — `react({ babel: { plugins:
13
+ [...] } })` — silently does nothing. The compiler has to be its own top-level
14
+ plugin.
15
+
16
+ ## The shape (read first)
17
+
18
+ - The compiler is a **Babel** plugin, run via
19
+ [`@rolldown/plugin-babel`](https://www.npmjs.com/package/@rolldown/plugin-babel)
20
+ with `reactCompilerPreset()` from `@vitejs/plugin-react`.
21
+ - **Ordering is load-bearing:** put `babel(...)` **after `react()`** and
22
+ **before the plugin that supplies `@vitejs/plugin-rsc`**. In a default Rango
23
+ app that plugin is `rango()` itself; in a Cloudflare app it is
24
+ `@cloudflare/vite-plugin`.
25
+ - **It is client-only.** `reactCompilerPreset()` gates itself to the client
26
+ environment. Server/RSC components are not compiled, and that is the upstream
27
+ example's behavior — not a Rango limitation. See
28
+ [What gets compiled](#what-gets-compiled-client-only).
29
+ - **Rango's build-time prerender is unaffected.** You do not need to do anything
30
+ special. See [Prerender](#interaction-with-build-time-prerender).
31
+
32
+ ## Step 1: Install
33
+
34
+ ```bash
35
+ pnpm add -D @rolldown/plugin-babel @babel/core babel-plugin-react-compiler
36
+ # TypeScript users also want the Babel core types:
37
+ pnpm add -D @types/babel__core
38
+ ```
39
+
40
+ React 19 ships `react/compiler-runtime` in-tree, so there is **no** extra runtime
41
+ to install and **no** `target` option to set. Only pass `target: '17' | '18'` to
42
+ `reactCompilerPreset()` if you are on an older React.
43
+
44
+ ## Step 2: Wire it in
45
+
46
+ ### Default (non-Cloudflare) app
47
+
48
+ ```ts
49
+ // vite.config.ts
50
+ import { defineConfig } from "vite";
51
+ import react, { reactCompilerPreset } from "@vitejs/plugin-react";
52
+ import babel from "@rolldown/plugin-babel";
53
+ import { rango } from "@rangojs/router/vite";
54
+
55
+ export default defineConfig({
56
+ plugins: [
57
+ react(),
58
+ babel({ presets: [reactCompilerPreset()] }),
59
+ rango(), // supplies @vitejs/plugin-rsc
60
+ ],
61
+ });
62
+ ```
63
+
64
+ ### Cloudflare app
65
+
66
+ ```ts
67
+ // vite.config.ts
68
+ import { cloudflare } from "@cloudflare/vite-plugin";
69
+ import react, { reactCompilerPreset } from "@vitejs/plugin-react";
70
+ import babel from "@rolldown/plugin-babel";
71
+ import { defineConfig } from "vite";
72
+ import { rango } from "@rangojs/router/vite";
73
+
74
+ export default defineConfig({
75
+ plugins: [
76
+ react(),
77
+ babel({ presets: [reactCompilerPreset()] }),
78
+ rango({ preset: "cloudflare" }),
79
+ cloudflare({
80
+ /* ... */
81
+ }), // supplies @vitejs/plugin-rsc
82
+ ],
83
+ });
84
+ ```
85
+
86
+ ## What gets compiled (client-only)
87
+
88
+ `reactCompilerPreset()` carries
89
+ `rolldown.applyToEnvironmentHook: (env) => env.config.consumer === "client"`, so
90
+ even though the babel plugin is top-level, the transform runs **only in the
91
+ `client` environment**:
92
+
93
+ | Environment | `consumer` | Compiled? |
94
+ | ----------- | ---------- | --------- |
95
+ | client | `client` | Yes |
96
+ | ssr | `server` | No |
97
+ | rsc | `server` | No |
98
+
99
+ This matches the upstream `@vitejs/plugin-rsc` example. If you genuinely need to
100
+ compile **server** components, you would have to invoke
101
+ `babel-plugin-react-compiler` yourself without the preset's
102
+ `applyToEnvironmentHook` — that is outside what the example does and is not
103
+ covered here.
104
+
105
+ ## Options
106
+
107
+ `reactCompilerPreset()` forwards to `babel-plugin-react-compiler`:
108
+
109
+ | Option | Effect |
110
+ | ------------------------------- | -------------------------------------------------------------------------------------- |
111
+ | `compilationMode: 'annotation'` | Compile only components marked with the `"use memo"` directive, not every eligible one |
112
+ | `target: '17' \| '18'` | Emit `react-compiler-runtime` calls for React < 19. Omit on React 19+. |
113
+
114
+ ## Interaction with build-time prerender
115
+
116
+ Nothing to configure. Rango's discovery/prerender step runs a throwaway temp Vite
117
+ server (`createTempRscServer`) that forwards only your **resolution** plugins
118
+ (`resolveId` / `load`). A pure transform plugin like `@rolldown/plugin-babel` is
119
+ intentionally **not** forwarded — and that is correct: the temp runner only
120
+ produces **data** (serialized Flight payloads + the route manifest), not shipped
121
+ code, and React Compiler is a memoization-only transform that does not change
122
+ rendered output. Your shipped client bundle still gets compiled, because the
123
+ babel plugin lives in your app's top-level plugin array alongside `react()`.
124
+
125
+ ## Step 3: Verify the compiler actually ran
126
+
127
+ A compiled module imports the cache allocator from `react/compiler-runtime` and
128
+ calls `_c(n)`. Those two appear in **every** compiled module, so they are the
129
+ reliable per-module signal in dev:
130
+
131
+ ```bash
132
+ pnpm dev
133
+ # fetch any client component module straight from Vite and look for the markers:
134
+ curl -s "http://localhost:5173/src/components/SomeClientComponent.tsx" \
135
+ | grep -E "compiler-runtime|_c\("
136
+ ```
137
+
138
+ For a production build, grep the built client bundle for the compiler's
139
+ input-independent cache check, which has a **zero baseline** without the compiler:
140
+
141
+ ```bash
142
+ pnpm build
143
+ grep -r "Symbol.for(\"react.memo_cache_sentinel\")" dist/client/assets/ | head
144
+ ```
145
+
146
+ Note the **comparison** form `$[i] === Symbol.for("react.memo_cache_sentinel")`
147
+ is only emitted for components with input-independent JSX, so it is reliable over
148
+ the **whole** client bundle, not necessarily in one chosen module. (React core
149
+ also defines that symbol once with a single `=` assignment, so count comparisons,
150
+ not the bare string.) Run the same grep over `dist/rsc` / `dist/ssr` and you
151
+ should find **none** — that is the client-only contract.
152
+
153
+ ## Troubleshooting
154
+
155
+ | Symptom | Cause / fix |
156
+ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
157
+ | Nothing is compiled; no `compiler-runtime` import anywhere | You used `react({ babel: { plugins: [...] } })`. plugin-react v6 has no internal Babel — add `@rolldown/plugin-babel` as its own plugin. |
158
+ | Client compiled, but server/RSC components are not | Expected. `reactCompilerPreset()` is client-only (see the table). Not a bug. |
159
+ | `Cannot find module 'babel-plugin-react-compiler'` (or `@babel/core`) | Install the peer deps from Step 1; they are not bundled by `reactCompilerPreset()`. |
160
+ | Build pulls in `react-compiler-runtime` | You set `target: '17'`/`'18'` on React 19. Drop `target` — React 19 ships `react/compiler-runtime` in-tree. |
161
+ | Output looks compiled but a component misbehaves | The component likely breaks the Rules of React. Fix the component, or scope the compiler with `compilationMode: 'annotation'` while you do. |
162
+
163
+ ## Reference
164
+
165
+ A worked, tested wiring (dev + production e2e markers, incl. the client-only
166
+ contract) lives in the `@rangojs/router` repo: `docs/react-compiler.md` and the
167
+ `react-compiler.test.ts` files under `e2e/e2e-basic`, `tests/cloudflare-basic`,
168
+ and `tests/vite-rsc-demo`.