@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa

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 (411) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +296 -887
  3. package/dist/bin/rango.js +459 -91
  4. package/dist/testing/vitest.js +36 -2
  5. package/dist/vite/index.js +1708 -414
  6. package/package.json +35 -10
  7. package/skills/api-client/SKILL.md +211 -0
  8. package/skills/breadcrumbs/SKILL.md +82 -5
  9. package/skills/bundle-analysis/SKILL.md +2 -2
  10. package/skills/cache-guide/SKILL.md +14 -9
  11. package/skills/caching/SKILL.md +221 -12
  12. package/skills/catalog.json +271 -0
  13. package/skills/comparison/SKILL.md +50 -0
  14. package/skills/comparison/agents/openai.yaml +4 -0
  15. package/skills/comparison/references/framework-comparison.md +837 -0
  16. package/skills/composability/SKILL.md +83 -2
  17. package/skills/css/SKILL.md +76 -0
  18. package/skills/debug-manifest/SKILL.md +5 -3
  19. package/skills/defer-hydration/SKILL.md +235 -0
  20. package/skills/document-cache/SKILL.md +11 -3
  21. package/skills/fonts/SKILL.md +1 -1
  22. package/skills/handler-use/SKILL.md +9 -9
  23. package/skills/hooks/SKILL.md +73 -900
  24. package/skills/hooks/data.md +273 -0
  25. package/skills/hooks/handle-and-actions.md +103 -0
  26. package/skills/hooks/navigation.md +110 -0
  27. package/skills/hooks/outlets.md +41 -0
  28. package/skills/hooks/state.md +228 -0
  29. package/skills/hooks/urls.md +135 -0
  30. package/skills/host-router/SKILL.md +84 -7
  31. package/skills/i18n/SKILL.md +1 -1
  32. package/skills/intercept/SKILL.md +51 -17
  33. package/skills/layout/SKILL.md +38 -16
  34. package/skills/links/SKILL.md +1 -1
  35. package/skills/loader/SKILL.md +48 -20
  36. package/skills/middleware/SKILL.md +11 -5
  37. package/skills/migrate-nextjs/SKILL.md +203 -20
  38. package/skills/migrate-react-router/SKILL.md +59 -675
  39. package/skills/migrate-react-router/cloudflare-workers.md +129 -0
  40. package/skills/migrate-react-router/component-migration.md +196 -0
  41. package/skills/migrate-react-router/data-and-actions.md +225 -0
  42. package/skills/migrate-react-router/route-mapping.md +271 -0
  43. package/skills/mime-routes/SKILL.md +3 -3
  44. package/skills/observability/SKILL.md +70 -5
  45. package/skills/parallel/SKILL.md +32 -8
  46. package/skills/ppr/SKILL.md +622 -0
  47. package/skills/prerender/SKILL.md +59 -28
  48. package/skills/rango/SKILL.md +124 -50
  49. package/skills/response-routes/SKILL.md +78 -46
  50. package/skills/route/SKILL.md +85 -6
  51. package/skills/router-setup/SKILL.md +41 -6
  52. package/skills/scripts/SKILL.md +179 -0
  53. package/skills/server-actions/SKILL.md +28 -3
  54. package/skills/shell-manifest/SKILL.md +185 -0
  55. package/skills/streams-and-websockets/SKILL.md +1 -1
  56. package/skills/tailwind/SKILL.md +28 -4
  57. package/skills/testing/SKILL.md +68 -654
  58. package/skills/testing/bindings.md +103 -0
  59. package/skills/testing/cache-prerender.md +127 -0
  60. package/skills/testing/client-components.md +124 -0
  61. package/skills/testing/e2e-parity.md +125 -0
  62. package/skills/testing/flight.md +91 -0
  63. package/skills/testing/handles.md +131 -0
  64. package/skills/testing/loader.md +128 -0
  65. package/skills/testing/middleware.md +99 -0
  66. package/skills/testing/render-handler.md +122 -0
  67. package/skills/testing/response-routes.md +95 -0
  68. package/skills/testing/reverse-and-types.md +85 -0
  69. package/skills/testing/server-actions.md +107 -0
  70. package/skills/testing/server-tree.md +128 -0
  71. package/skills/testing/setup.md +123 -0
  72. package/skills/theme/SKILL.md +1 -1
  73. package/skills/typesafety/SKILL.md +45 -918
  74. package/skills/typesafety/env-and-bindings.md +254 -0
  75. package/skills/typesafety/generated-files-and-cli.md +335 -0
  76. package/skills/typesafety/params-and-search.md +153 -0
  77. package/skills/typesafety/route-types.md +209 -0
  78. package/skills/use-cache/SKILL.md +47 -17
  79. package/skills/vercel/SKILL.md +128 -0
  80. package/skills/view-transitions/SKILL.md +44 -1
  81. package/src/__augment-tests__/augmented.check.ts +2 -3
  82. package/src/__internal.ts +0 -65
  83. package/src/browser/action-coordinator.ts +1 -1
  84. package/src/browser/action-fence.ts +47 -0
  85. package/src/browser/app-shell.ts +14 -27
  86. package/src/browser/connection-warmup.ts +134 -0
  87. package/src/browser/cookie-name.ts +140 -0
  88. package/src/browser/event-controller.ts +178 -100
  89. package/src/browser/invalidate-client-cache.ts +52 -0
  90. package/src/browser/logging.ts +28 -0
  91. package/src/browser/merge-segment-loaders.ts +6 -4
  92. package/src/browser/navigation-bridge.ts +81 -68
  93. package/src/browser/navigation-client.ts +115 -70
  94. package/src/browser/navigation-store-handle.ts +38 -0
  95. package/src/browser/navigation-store.ts +153 -88
  96. package/src/browser/navigation-transaction.ts +0 -32
  97. package/src/browser/network-error-handler.ts +34 -7
  98. package/src/browser/partial-update.ts +157 -144
  99. package/src/browser/prefetch/cache.ts +148 -81
  100. package/src/browser/prefetch/fetch.ts +231 -51
  101. package/src/browser/prefetch/queue.ts +25 -7
  102. package/src/browser/rango-state.ts +157 -115
  103. package/src/browser/react/Link.tsx +40 -7
  104. package/src/browser/react/NavigationProvider.tsx +140 -99
  105. package/src/browser/react/ScrollRestoration.tsx +10 -6
  106. package/src/browser/react/filter-segment-order.ts +17 -2
  107. package/src/browser/react/index.ts +0 -51
  108. package/src/browser/react/location-state-shared.ts +14 -15
  109. package/src/browser/react/location-state.ts +0 -1
  110. package/src/browser/react/use-action.ts +6 -15
  111. package/src/browser/react/use-handle.ts +0 -5
  112. package/src/browser/react/use-href.tsx +8 -1
  113. package/src/browser/react/use-link-status.ts +33 -8
  114. package/src/browser/react/use-navigation.ts +10 -5
  115. package/src/browser/react/use-params.ts +0 -2
  116. package/src/browser/react/use-router.ts +6 -4
  117. package/src/browser/react/use-search-params.ts +0 -5
  118. package/src/browser/react/use-segments.ts +0 -13
  119. package/src/browser/response-adapter.ts +74 -8
  120. package/src/browser/rsc-router.tsx +97 -22
  121. package/src/browser/scroll-restoration.ts +15 -8
  122. package/src/browser/segment-reconciler.ts +31 -21
  123. package/src/browser/server-action-bridge.ts +216 -38
  124. package/src/browser/types.ts +94 -22
  125. package/src/browser/validate-redirect-origin.ts +43 -16
  126. package/src/build/generate-manifest.ts +155 -131
  127. package/src/build/generate-route-types.ts +1 -1
  128. package/src/build/index.ts +11 -5
  129. package/src/build/prefix-tree-utils.ts +123 -0
  130. package/src/build/route-trie.ts +152 -22
  131. package/src/build/route-types/ast-route-extraction.ts +15 -8
  132. package/src/build/route-types/codegen.ts +12 -1
  133. package/src/build/route-types/include-resolution.ts +455 -61
  134. package/src/build/route-types/param-extraction.ts +6 -3
  135. package/src/build/route-types/per-module-writer.ts +15 -2
  136. package/src/build/route-types/router-processing.ts +77 -41
  137. package/src/build/route-types/source-scan.ts +105 -7
  138. package/src/build/runtime-discovery.ts +4 -1
  139. package/src/cache/cache-error.ts +104 -0
  140. package/src/cache/cache-key-utils.ts +58 -13
  141. package/src/cache/cache-policy.ts +108 -34
  142. package/src/cache/cache-runtime.ts +454 -101
  143. package/src/cache/cache-scope.ts +159 -54
  144. package/src/cache/cache-tag.ts +149 -0
  145. package/src/cache/cf/cf-base64.ts +33 -0
  146. package/src/cache/cf/cf-cache-constants.ts +127 -0
  147. package/src/cache/cf/cf-cache-store.ts +2170 -377
  148. package/src/cache/cf/cf-cache-types.ts +349 -0
  149. package/src/cache/cf/cf-kv-utils.ts +46 -0
  150. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  151. package/src/cache/cf/index.ts +6 -16
  152. package/src/cache/document-cache.ts +126 -41
  153. package/src/cache/handle-snapshot.ts +70 -0
  154. package/src/cache/index.ts +23 -20
  155. package/src/cache/memory-segment-store.ts +243 -37
  156. package/src/cache/profile-registry.ts +46 -31
  157. package/src/cache/read-through-swr.ts +56 -12
  158. package/src/cache/segment-codec.ts +13 -21
  159. package/src/cache/shell-snapshot.ts +417 -0
  160. package/src/cache/tag-invalidation.ts +230 -0
  161. package/src/cache/types.ts +194 -99
  162. package/src/cache/vercel/index.ts +11 -0
  163. package/src/cache/vercel/vercel-cache-store.ts +1132 -0
  164. package/src/client.rsc.tsx +39 -22
  165. package/src/client.tsx +28 -58
  166. package/src/cloudflare/index.ts +11 -0
  167. package/src/cloudflare/tracing.ts +108 -0
  168. package/src/component-utils.ts +19 -0
  169. package/src/components/DefaultDocument.tsx +8 -2
  170. package/src/context-var.ts +13 -1
  171. package/src/decode-loader-results.ts +18 -2
  172. package/src/defer.ts +185 -0
  173. package/src/deps/ssr.ts +0 -1
  174. package/src/encode-kv.ts +49 -0
  175. package/src/errors.ts +0 -3
  176. package/src/escape-script.ts +52 -0
  177. package/src/handle.ts +57 -40
  178. package/src/handles/MetaTags.tsx +24 -53
  179. package/src/handles/Scripts.tsx +183 -0
  180. package/src/handles/breadcrumbs.ts +35 -8
  181. package/src/handles/deferred-resolution.ts +127 -0
  182. package/src/handles/is-thenable.ts +18 -0
  183. package/src/handles/meta.ts +14 -40
  184. package/src/handles/script.ts +244 -0
  185. package/src/host/cookie-handler.ts +9 -60
  186. package/src/host/errors.ts +13 -22
  187. package/src/host/index.ts +7 -0
  188. package/src/host/pattern-matcher.ts +23 -52
  189. package/src/host/router.ts +1 -65
  190. package/src/host/testing.ts +40 -27
  191. package/src/host/types.ts +6 -2
  192. package/src/href-client.ts +7 -12
  193. package/src/index.rsc.ts +88 -8
  194. package/src/index.ts +90 -16
  195. package/src/internal-debug.ts +11 -10
  196. package/src/loader.rsc.ts +19 -9
  197. package/src/loader.ts +12 -4
  198. package/src/outlet-provider.tsx +1 -5
  199. package/src/prerender/param-hash.ts +16 -16
  200. package/src/prerender/store.ts +32 -37
  201. package/src/prerender.ts +75 -7
  202. package/src/redirect-origin.ts +114 -0
  203. package/src/regex-escape.ts +8 -0
  204. package/src/render-error-thrower.tsx +20 -0
  205. package/src/response-utils.ts +25 -0
  206. package/src/root-error-boundary.tsx +1 -19
  207. package/src/route-content-wrapper.tsx +13 -49
  208. package/src/route-definition/dsl-helpers.ts +60 -53
  209. package/src/route-definition/helper-factories.ts +0 -2
  210. package/src/route-definition/helpers-types.ts +46 -46
  211. package/src/route-definition/index.ts +1 -2
  212. package/src/route-definition/redirect.ts +44 -11
  213. package/src/route-definition/resolve-handler-use.ts +6 -1
  214. package/src/route-definition/use-item-types.ts +3 -6
  215. package/src/route-map-builder.ts +41 -20
  216. package/src/route-types.ts +0 -5
  217. package/src/router/content-negotiation.ts +58 -23
  218. package/src/router/error-handling.ts +44 -17
  219. package/src/router/find-match.ts +129 -30
  220. package/src/router/handler-context.ts +6 -1
  221. package/src/router/instrument.ts +355 -0
  222. package/src/router/intercept-resolution.ts +35 -2
  223. package/src/router/lazy-includes.ts +79 -56
  224. package/src/router/loader-resolution.ts +151 -73
  225. package/src/router/logging.ts +0 -6
  226. package/src/router/manifest.ts +74 -40
  227. package/src/router/match-api.ts +76 -52
  228. package/src/router/match-context.ts +0 -22
  229. package/src/router/match-handlers.ts +181 -178
  230. package/src/router/match-middleware/background-revalidation.ts +40 -24
  231. package/src/router/match-middleware/cache-lookup.ts +115 -194
  232. package/src/router/match-middleware/cache-store.ts +61 -50
  233. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  234. package/src/router/match-middleware/segment-resolution.ts +0 -22
  235. package/src/router/match-pipelines.ts +1 -42
  236. package/src/router/match-result.ts +36 -67
  237. package/src/router/metrics.ts +0 -34
  238. package/src/router/middleware-types.ts +0 -116
  239. package/src/router/middleware.ts +231 -120
  240. package/src/router/navigation-snapshot.ts +7 -56
  241. package/src/router/params-util.ts +23 -0
  242. package/src/router/parse-pattern.ts +115 -0
  243. package/src/router/pattern-matching.ts +99 -152
  244. package/src/router/prefetch-cache-ttl.ts +51 -0
  245. package/src/router/prefetch-limits.ts +37 -0
  246. package/src/router/prerender-match.ts +111 -66
  247. package/src/router/preview-match.ts +3 -1
  248. package/src/router/request-classification.ts +47 -42
  249. package/src/router/revalidation.ts +75 -81
  250. package/src/router/route-snapshot.ts +14 -3
  251. package/src/router/router-context.ts +6 -29
  252. package/src/router/router-interfaces.ts +70 -8
  253. package/src/router/router-options.ts +126 -4
  254. package/src/router/segment-resolution/fresh.ts +104 -80
  255. package/src/router/segment-resolution/helpers.ts +86 -6
  256. package/src/router/segment-resolution/loader-cache.ts +155 -39
  257. package/src/router/segment-resolution/loader-mask.ts +60 -0
  258. package/src/router/segment-resolution/loader-snapshot.ts +259 -0
  259. package/src/router/segment-resolution/mask-nested.ts +83 -0
  260. package/src/router/segment-resolution/revalidation.ts +215 -304
  261. package/src/router/segment-resolution/static-store.ts +19 -5
  262. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  263. package/src/router/segment-resolution/view-transition-default.ts +35 -15
  264. package/src/router/segment-resolution.ts +5 -1
  265. package/src/router/segment-wrappers.ts +6 -5
  266. package/src/router/state-cookie-name.ts +33 -0
  267. package/src/router/substitute-pattern-params.ts +54 -35
  268. package/src/router/telemetry-otel.ts +160 -200
  269. package/src/router/telemetry.ts +9 -23
  270. package/src/router/timeout.ts +0 -20
  271. package/src/router/tracing.ts +215 -0
  272. package/src/router/trie-matching.ts +171 -64
  273. package/src/router/types.ts +1 -63
  274. package/src/router/url-params.ts +13 -5
  275. package/src/router.ts +119 -48
  276. package/src/rsc/full-payload.ts +70 -0
  277. package/src/rsc/handler-context.ts +1 -0
  278. package/src/rsc/handler.ts +267 -152
  279. package/src/rsc/helpers.ts +78 -4
  280. package/src/rsc/index.ts +1 -4
  281. package/src/rsc/json-route-result.ts +38 -0
  282. package/src/rsc/loader-fetch.ts +114 -38
  283. package/src/rsc/manifest-init.ts +29 -42
  284. package/src/rsc/nonce.ts +10 -1
  285. package/src/rsc/origin-guard.ts +11 -15
  286. package/src/rsc/progressive-enhancement.ts +120 -13
  287. package/src/rsc/redirect-guard.ts +100 -0
  288. package/src/rsc/response-cache-serve.ts +238 -0
  289. package/src/rsc/response-error.ts +79 -12
  290. package/src/rsc/response-route-handler.ts +58 -141
  291. package/src/rsc/rsc-rendering.ts +492 -49
  292. package/src/rsc/runtime-warnings.ts +14 -0
  293. package/src/rsc/server-action.ts +268 -82
  294. package/src/rsc/shell-capture.ts +1190 -0
  295. package/src/rsc/shell-serve.ts +181 -0
  296. package/src/rsc/transition-gate.ts +89 -0
  297. package/src/rsc/types.ts +45 -3
  298. package/src/runtime-env.ts +18 -0
  299. package/src/search-params.ts +31 -26
  300. package/src/segment-loader-promise.ts +49 -4
  301. package/src/segment-system.tsx +260 -95
  302. package/src/server/context.ts +99 -9
  303. package/src/server/cookie-parse.ts +32 -0
  304. package/src/server/cookie-store.ts +125 -2
  305. package/src/server/handle-store.ts +21 -38
  306. package/src/server/loader-registry.ts +33 -42
  307. package/src/server/request-context.ts +379 -138
  308. package/src/ssr/index.tsx +491 -182
  309. package/src/ssr/inject-rsc-eager.ts +167 -0
  310. package/src/ssr/ssr-root.tsx +228 -0
  311. package/src/static-handler.ts +10 -13
  312. package/src/testing/cache-status.ts +44 -48
  313. package/src/testing/collect-handle.ts +14 -31
  314. package/src/testing/dispatch.ts +533 -160
  315. package/src/testing/e2e/fixture.ts +45 -11
  316. package/src/testing/e2e/index.ts +1 -22
  317. package/src/testing/e2e/matchers.ts +0 -16
  318. package/src/testing/e2e/parity.ts +85 -4
  319. package/src/testing/e2e/server.ts +12 -0
  320. package/src/testing/flight-matchers.ts +7 -14
  321. package/src/testing/flight-normalize.ts +11 -0
  322. package/src/testing/flight-runtime.d.ts +36 -0
  323. package/src/testing/flight-tree.ts +682 -0
  324. package/src/testing/flight.entry.ts +30 -0
  325. package/src/testing/flight.ts +145 -70
  326. package/src/testing/generated-routes.ts +26 -50
  327. package/src/testing/index.ts +18 -19
  328. package/src/testing/internal/context.ts +184 -68
  329. package/src/testing/internal/flight-client-globals.ts +30 -0
  330. package/src/testing/internal/seed-vars.ts +54 -0
  331. package/src/testing/render-handler.ts +357 -0
  332. package/src/testing/render-route.tsx +134 -115
  333. package/src/testing/run-loader.ts +140 -51
  334. package/src/testing/run-middleware.ts +59 -33
  335. package/src/testing/run-transition-when.ts +164 -0
  336. package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
  337. package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
  338. package/src/testing/vitest.ts +138 -16
  339. package/src/theme/ThemeProvider.tsx +56 -84
  340. package/src/theme/ThemeScript.tsx +7 -9
  341. package/src/theme/constants.ts +52 -13
  342. package/src/theme/index.ts +0 -7
  343. package/src/theme/theme-context.ts +1 -5
  344. package/src/theme/theme-script.ts +22 -21
  345. package/src/theme/use-theme.ts +0 -3
  346. package/src/types/boundaries.ts +0 -35
  347. package/src/types/cache-types.ts +13 -4
  348. package/src/types/error-types.ts +30 -90
  349. package/src/types/global-namespace.ts +15 -15
  350. package/src/types/handler-context.ts +45 -15
  351. package/src/types/index.ts +2 -10
  352. package/src/types/loader-types.ts +6 -3
  353. package/src/types/request-scope.ts +8 -22
  354. package/src/types/route-config.ts +20 -52
  355. package/src/types/route-entry.ts +0 -6
  356. package/src/types/segments.ts +100 -13
  357. package/src/urls/include-helper.ts +10 -12
  358. package/src/urls/include-provider.ts +71 -0
  359. package/src/urls/index.ts +2 -8
  360. package/src/urls/path-helper-types.ts +52 -14
  361. package/src/urls/path-helper.ts +5 -54
  362. package/src/urls/pattern-types.ts +36 -0
  363. package/src/urls/type-extraction.ts +76 -42
  364. package/src/urls/urls-function.ts +0 -14
  365. package/src/use-loader.tsx +0 -186
  366. package/src/vercel/index.ts +11 -0
  367. package/src/vercel/tracing.ts +88 -0
  368. package/src/vite/discovery/bundle-postprocess.ts +2 -1
  369. package/src/vite/discovery/dev-prerender-cache.ts +117 -0
  370. package/src/vite/discovery/discover-routers.ts +34 -43
  371. package/src/vite/discovery/discovery-errors.ts +61 -0
  372. package/src/vite/discovery/prerender-collection.ts +33 -46
  373. package/src/vite/discovery/state.ts +12 -1
  374. package/src/vite/discovery/virtual-module-codegen.ts +1 -11
  375. package/src/vite/index.ts +9 -0
  376. package/src/vite/inject-client-debug.ts +88 -0
  377. package/src/vite/plugin-types.ts +143 -10
  378. package/src/vite/plugins/cjs-to-esm.ts +8 -12
  379. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  380. package/src/vite/plugins/client-ref-hashing.ts +0 -10
  381. package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
  382. package/src/vite/plugins/expose-action-id.ts +2 -73
  383. package/src/vite/plugins/expose-id-utils.ts +85 -56
  384. package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
  385. package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
  386. package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
  387. package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
  388. package/src/vite/plugins/expose-internal-ids.ts +10 -1
  389. package/src/vite/plugins/performance-tracks.ts +0 -3
  390. package/src/vite/plugins/refresh-cmd.ts +1 -1
  391. package/src/vite/plugins/use-cache-transform.ts +21 -46
  392. package/src/vite/plugins/vercel-output.ts +384 -0
  393. package/src/vite/plugins/version-injector.ts +22 -27
  394. package/src/vite/plugins/version-plugin.ts +6 -66
  395. package/src/vite/plugins/virtual-entries.ts +137 -26
  396. package/src/vite/rango.ts +146 -135
  397. package/src/vite/router-discovery.ts +189 -48
  398. package/src/vite/utils/ast-handler-extract.ts +11 -20
  399. package/src/vite/utils/bundle-analysis.ts +6 -13
  400. package/src/vite/utils/client-chunks.ts +0 -6
  401. package/src/vite/utils/directive-prologue.ts +40 -0
  402. package/src/vite/utils/forward-user-plugins.ts +0 -22
  403. package/src/vite/utils/manifest-utils.ts +4 -75
  404. package/src/vite/utils/package-resolution.ts +1 -73
  405. package/src/vite/utils/prerender-utils.ts +71 -44
  406. package/src/vite/utils/shared-utils.ts +55 -37
  407. package/src/browser/react/use-client-cache.ts +0 -58
  408. package/src/browser/shallow.ts +0 -40
  409. package/src/handles/index.ts +0 -7
  410. package/src/network-error-thrower.tsx +0 -23
  411. package/src/router/middleware-cookies.ts +0 -55
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: prerender
3
- description: Pre-render route segments at build time with Prerender and Passthrough live fallback
3
+ description: Pre-render route segments at build time with Prerender and Passthrough live fallback. Use when a page's content is mostly static and shouldn't render on every request, speeding up cold responses, or deciding which routes to prerender vs render live.
4
4
  argument-hint: [passthrough]
5
5
  ---
6
6
 
@@ -11,6 +11,13 @@ deserialization path, same segment system. The worker handles every request --
11
11
  there are NO static .html or .rsc files served from assets. The worker reads
12
12
  pre-computed Flight payloads instead of executing handler code.
13
13
 
14
+ ## Not this skill if…
15
+
16
+ - You want a cached HTML shell captured at runtime, with holes and loaders
17
+ staying live per request — see `/ppr`.
18
+ - You want runtime segment caching with TTL/SWR — that is the `cache()` DSL:
19
+ see `/caching`. Prerender is the same cache filled at build time.
20
+
14
21
  ## API: Prerender
15
22
 
16
23
  ### Static Route (no params)
@@ -119,6 +126,8 @@ interface BuildContext<TParams> {
119
126
  use: <T>(handle: Handle<T>) => (data: T) => void; // Push handle data
120
127
  url: URL; // Synthetic URL from pattern + params
121
128
  pathname: string; // Pathname from synthetic URL
129
+ searchParams: URLSearchParams; // URLSearchParams from the synthetic URL (always empty for prerender)
130
+ search: {}; // Typed search params -- always {} for prerender (no real query string)
122
131
  set(key: string, value: any): void; // Set context variable (string key)
123
132
  set<T>(contextVar: ContextVar<T>, value: T): void; // Set typed context variable
124
133
  get(key: string): any; // Read context variable (string key)
@@ -241,16 +250,16 @@ path("/blog/:slug", BlogPost, { name: "blog.post" }, () => [
241
250
 
242
251
  ## Interaction with DSL Items
243
252
 
244
- | DSL item | Behavior with Prerender |
245
- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
246
- | `loader()` | Live at runtime, bundled normally. Use `cache()` for caching. |
247
- | `revalidate()` | Not allowed without Passthrough. Allowed with Passthrough. |
248
- | `cache()` | Orthogonal -- use on parent layouts and loaders. |
249
- | `layout()` | Child layouts inside path are pre-rendered. Parent layouts are live. |
250
- | `parallel()` | Parallel slots inside path are pre-rendered. |
251
- | `middleware()` | Skipped during pre-render (no request). Runs at request time for loaders. |
252
- | `loading()` | Ignored without Passthrough. Works for live fallback with Passthrough. |
253
- | `intercept()` | Pre-rendered at build time. Intercept variant stored under `/i` key alongside main segments. At runtime, the correct variant is served based on `ctx.isIntercept`. `when()` conditions are skipped at build time (all intercepts are pre-rendered unconditionally). |
253
+ | DSL item | Behavior with Prerender |
254
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
255
+ | `loader()` | Live at runtime, bundled normally. Use `cache()` for caching. |
256
+ | `revalidate()` | Not allowed without Passthrough. Allowed with Passthrough. |
257
+ | `cache()` | Orthogonal -- use on parent layouts and loaders. |
258
+ | `layout()` | Child layouts inside path are pre-rendered. Parent layouts are live. |
259
+ | `parallel()` | Parallel slots inside path are pre-rendered. |
260
+ | `middleware()` | Skipped during pre-render (no request). Runs at request time for loaders. |
261
+ | `loading()` | Ignored without Passthrough. Works for live fallback with Passthrough. |
262
+ | `intercept()` | Pre-rendered at build time. Intercept variant stored under `/i` key alongside main segments. At runtime, the correct variant is served based on `ctx.isIntercept`. `when` config conditions are skipped at build time (all intercepts are pre-rendered unconditionally). |
254
263
 
255
264
  When Passthrough revalidation is enabled, remember that revalidation is
256
265
  still partial: opting a child segment into revalidation does not
@@ -343,14 +352,31 @@ export const TocSidebar = Static(() => {
343
352
 
344
353
  ### Error behavior at build time
345
354
 
346
- | Handler outcome | Effect |
347
- | --------------------------- | ----------------------------------------------------- |
348
- | JSX / `null` | Normal prerender entry, log OK |
349
- | `return ctx.passthrough()` | Skip entry, log PASS, continue (Passthrough routes) |
350
- | `throw new Skip("reason")` | Skip entry, log SKIP, continue with remaining entries |
351
- | `throw new Error("reason")` | Log FAIL, stop ALL pre-rendering, fail the build |
355
+ When a render throws a non-`Skip` error, it is **surfaced to the build** — never
356
+ baked into a frozen error page served as a 200 (issue #587). What happens next is
357
+ controlled by `prerender.onError` in your `rango()` options:
358
+
359
+ ```ts
360
+ rango({ prerender: { onError: "warn" } }); // default is "fail"
361
+ ```
352
362
 
353
- Both error types propagate to the router's `onError` callback with phase
363
+ | Handler outcome | `onError: "fail"` (default) | `onError: "warn"` |
364
+ | --------------------------- | -------------------------------------------- | -------------------------------- |
365
+ | JSX / `null` | Normal prerender entry, log OK | Normal prerender entry, log OK |
366
+ | `return ctx.passthrough()` | Skip entry, log PASS (Passthrough routes) | Skip entry, log PASS |
367
+ | `throw new Skip("reason")` | Skip entry, log SKIP, continue | Skip entry, log SKIP, continue |
368
+ | `throw new Error("reason")` | Log FAIL, stop ALL pre-rendering, fail build | Log WARN, skip the URL, continue |
369
+
370
+ With `"warn"` the errored entry is logged and left un-baked (never served as a baked
371
+ 200 error page). `"warn"` is a build-unblock, not a runtime contract: the route falls
372
+ through to normal resolution — it may render live (its handler is still bundled) or
373
+ 404 (once other baked entries trigger prerender handler eviction), so the outcome
374
+ depends on the rest of the build, and a skipped `Static()` handler's evicted code can
375
+ surface as an error. For DEFINED runtime behavior reach for `Passthrough()` (a live
376
+ fallback) or `throw new Skip()` (an intentional skip — works in the render fn, not
377
+ only `getParams()`); otherwise prefer the default `"fail"`.
378
+
379
+ Both `Skip` and hard errors propagate to the router's `onError` callback with phase
354
380
  `"prerender"` or `"static"`.
355
381
 
356
382
  ### Build logs
@@ -370,9 +396,11 @@ The build produces per-URL timing logs:
370
396
  [rango] Static render complete: 2 done, 1 skipped (120ms total)
371
397
  ```
372
398
 
373
- A `FAIL` line is logged per-URL when a handler throws a non-Skip error. The
374
- error is re-thrown immediately, so no summary line is printed — the build
375
- stops at the first failure.
399
+ A `FAIL` line is logged per-URL when a handler throws a non-Skip error (with the
400
+ default `prerender.onError: "fail"`). The error is re-thrown immediately, so no
401
+ summary line is printed — the build stops at the first failure. Under
402
+ `prerender.onError: "warn"` the same case logs a `WARN` line, skips that URL, and
403
+ the build continues.
376
404
 
377
405
  ### Dev mode behavior
378
406
 
@@ -588,12 +616,12 @@ At runtime, the cache-lookup middleware checks `ctx.isIntercept`:
588
616
  (filtered by `namespace?.startsWith("intercept:")`) and sets up slots.
589
617
  - **Direct navigation**: looks up `paramHash` (no suffix). Standard prerender path.
590
618
  - **Intercept miss (no `/i` entry)**: falls through to the normal pipeline so
591
- intercept-resolution middleware runs live. This handles `when()` conditions
619
+ intercept-resolution middleware runs live. This handles `when` config conditions
592
620
  that prevented pre-rendering.
593
621
 
594
- The `when()` callback receives an `InterceptSelectorContext` with `from.pathname`
622
+ The `when` config selector receives an `InterceptSelectorContext` with `from.pathname`
595
623
  which is unknown at build time. All intercepts are pre-rendered unconditionally;
596
- `when()` is evaluated at runtime by the intercept-resolution middleware.
624
+ `when` is evaluated at runtime by the intercept-resolution middleware.
597
625
 
598
626
  ### Example: Pre-rendered route with intercept
599
627
 
@@ -612,10 +640,13 @@ layout(ShopLayout, () => [
612
640
 
613
641
  // Intercept detail from shop index into a modal.
614
642
  // At build time, this is resolved and stored under the /i key.
615
- intercept("@modal", ".detail", <ProductModal />, () => [
616
- when(({ from }) => from.pathname === "/shop"),
617
- loader(ProductLoader),
618
- ]),
643
+ intercept(
644
+ "@modal",
645
+ ".detail",
646
+ <ProductModal />,
647
+ { when: ({ from }) => from.pathname === "/shop" },
648
+ () => [loader(ProductLoader)],
649
+ ),
619
650
  ])
620
651
  ```
621
652
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rango
3
- description: Overview of @rangojs/router and available skills
3
+ description: Overview of @rangojs/router and available skills. Use when unsure which skill to reach for, starting a new task in a Rango app, or asking "what can this router do".
4
4
  argument-hint:
5
5
  ---
6
6
 
@@ -28,10 +28,10 @@ with the shape, then pick a primitive.
28
28
  cache hit streams UI instantly while loaders resolve fresh alongside). Opt into
29
29
  caching explicitly. See `/loader` → "Parallel and streaming".
30
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; cache
32
- entries accept an optional `tags` field, but built-in stores do not yet index
33
- or invalidate by tag, so tag-based invalidation (`revalidateTag`) is a
34
- forward-looking API requiring a custom store.
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
35
  - **Type-safe end to end** — route names, params, search schemas, loader return
36
36
  types, context vars, and `href` / `reverse` are checked at compile time
37
37
  (`/typesafety`).
@@ -59,36 +59,81 @@ appears, not up front.
59
59
  To decide where something can live: **does it define a URL? structure, stays in
60
60
  `urls()`. Does it modify a node? config, compose freely.**
61
61
 
62
+ ## Passing data down the tree
63
+
64
+ Four ways to get per-request data to a segment below you, ordered safest-first.
65
+ Reach for the next rung only when the one above doesn't fit — the higher rungs
66
+ are immune to partial-revalidation staleness by construction.
67
+
68
+ 1. **A loader** (`loader()` + `useLoader()`). Loaders resolve fresh on every
69
+ pass — full renders, action revalidations, cache hits. Nothing to keep in
70
+ sync. If the data can be a loader, make it a loader.
71
+ 2. **Middleware `ctx.set()`**. Route middleware wraps every render pass,
72
+ including post-action revalidation and PE re-renders, so its variables are
73
+ never stale. Right for request-shaped context: auth, session, locale.
74
+ 3. **Handler `ctx.set()` to its own children** —
75
+ `path(handler, ..., () => [layout(...)])`. Orphan layouts and their
76
+ parallels belong to the route entry: on an action the whole entry re-runs
77
+ together by default (handler-first preserved), so the data stays consistent
78
+ with zero configuration. Right for data the page must compute anyway —
79
+ e.g. pagination, where the handler's search decides how many pages the
80
+ layout chrome renders. One rule: if you narrow the entry's revalidation
81
+ with a predicate that can return a hard `false`, put the same contract on
82
+ the entry's children too — a hard `false` on one side of a
83
+ producer/consumer pair desyncs it.
84
+ 4. **Cross-entry sharing** — an outer `layout()` entry feeding descendants.
85
+ Outer entries do NOT revalidate on actions by default (the revalidation
86
+ trace calls this `action:parent-chain-skip`), so this rung always requires
87
+ a shared revalidation contract: the same named `revalidate()` function on
88
+ the producer and every consumer. See `/layout` → "Revalidation Contracts".
89
+ Before writing one, check whether the producer can move down a rung.
90
+
91
+ The failure mode this ladder prevents: a consumer re-runs, its producer
92
+ doesn't, `ctx.get()` reads `undefined`, and fallback UI silently replaces good
93
+ UI after an action. Rungs 1–3 make that unrepresentable; rung 4 makes it a
94
+ stated, greppable contract.
95
+
62
96
  ## Pick a primitive
63
97
 
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 |
98
+ | I need to… | Use | Skill |
99
+ | --------------------------------------- | ---------------------------------- | ----------------------- |
100
+ | render data fresh every request | `loader()` + `useLoader()` | /loader |
101
+ | cache a rendered subtree | `cache()` on a segment | /caching |
102
+ | cache one function/component's result | `"use cache"` | /use-cache |
103
+ | cache a loader's data | `loader(L, () => [cache()])` | /loader, /caching |
104
+ | re-render a segment after an action | `revalidate()` | /loader |
105
+ | mutate | `"use server"` action | /server-actions |
106
+ | debug a slow request | `debugPerformance` / telemetry | /observability |
107
+ | share config across routes | factory returning a helper array | /composability |
108
+ | compose a sub-app / module | `include()` | /route |
109
+ | modal / soft navigation | `intercept()` | /intercept |
110
+ | pre-render a route at build time | `Prerender(...)` wrapper | /prerender |
111
+ | feed live loaders from a cached shell | replayed handle + `ctx.rendered()` | /shell-manifest |
112
+ | cache the HTML shell, keep loaders live | `ppr` path option | /ppr |
113
+ | stream SSE / upgrade a WebSocket | `path.stream()` / `path.any()` | /streams-and-websockets |
78
114
 
79
115
  ## Invariants
80
116
 
81
117
  - `path()`/`include()` are always visible in `urls()`; config helpers are extractable.
82
118
  - **Cache decides freshness; `revalidate()` decides client-update.** Orthogonal; compose.
83
119
  - Loaders resolve fresh every request (even inside `cache()`) and never run twice/request.
120
+ - **The consumption-lane rule.** For every shared artifact (`cache()`,
121
+ `"use cache"`, the PPR shell): server-side handler consumption
122
+ (`await ctx.use(loader)`) yields a BAKED copy — identity reads
123
+ (`cookies()`/`headers()`) are permitted there and the capture-time value
124
+ freezes into the shared artifact (a documented footgun; see `/caching` →
125
+ "Cache purity & tainted objects"). Client-side consumption (`useLoader` in
126
+ a `"use client"` component) is the LIVE lane. DSL `loader()` segments
127
+ follow their lane machinery (live under renderable `loading()`, bake
128
+ otherwise). Pinned by semantic-matrix row PPR3.
84
129
  - Inside `"use cache"`: `cookies()`/`headers()` and `ctx` side-effects
85
130
  (`set`/`header`/`setTheme`/`onResponse`/`setLocationState`) throw; `ctx.use(Handle)`
86
131
  is captured on miss and replayed on hit. (The non-cacheable read guard is a
87
132
  separate `cache()`-boundary check — see the correctness bullet below.)
88
- - One identity `path#export` (`functionId`/`$$id`/`actionId`); one store. The
89
- cross-cutting freshness mechanism today is TTL/SWR expiry; cache entries accept
90
- an optional `tags` field, but built-in stores do not yet index or invalidate by
91
- tag, so `revalidateTag` is forward-looking (requires a custom store).
133
+ - One identity `path#export` (`functionId`/`$$id`/`actionId`); one store. Freshness
134
+ is TTL/SWR expiry plus tag-based invalidation: tag via `cache({ tags })` /
135
+ `cacheTag(...tags)`, then `updateTag(...tags)` (awaitable) or `revalidateTag(...tags)`
136
+ (background). Built-in stores index by tag.
92
137
  - `useLoader` / `useHandle` / `useFetchLoader` are client-only.
93
138
  - Caches are correctness-first: persistent store keys are version-segmented (no
94
139
  cross-deploy drift), the forward/back cache is mutation-aware, and
@@ -111,13 +156,14 @@ To decide where something can live: **does it define a URL? structure, stays in
111
156
  Same words, different jobs — this is the most common source of the
112
157
  `revalidate()`-is-caching misread.
113
158
 
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 `revalidatePath` / `revalidateTag` | **Axis 1** (cache) | Cache busting. No shipped equivalent: entries accept `tags`, but built-in stores don't yet index/invalidate by tag, so `revalidateTag` is forward-looking (custom store); today entries expire by TTL/SWR. No `revalidatePath`. |
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. |
159
+ | You may know | Maps to Rango axis | Watch out |
160
+ | --------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
161
+ | 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. |
162
+ | 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. |
163
+ | React Router / Remix `shouldRevalidate` | **Axis 2** | This is the correct mental model for Rango's `revalidate()`. |
164
+ | HTTP `Cache-Control` / ISR | **Axis 1** | Edge/document layer — see `/document-cache`. Separate from both `cache()` and `revalidate()`. |
165
+ | Next.js PPR (partial prerendering) | HTML shell layer | Same idea, different wiring: the opt-in `ppr` path option captures at runtime (no build-time default); holes are render-defined — `loading()` subtrees plus pending promises under a consumer's own `<Suspense>`. See `/ppr`. |
166
+ | 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
167
 
122
168
  See `/cache-guide` for the axis-1 decision guide, `/loader` and `/route` for
123
169
  `revalidate()` (axis 2), and `/document-cache` for the edge layer.
@@ -154,6 +200,12 @@ returned, for outcome-conditional revalidation. The arg also exposes `actionId`
154
200
  (raw `path#export`), `actionUrl`, `formData`, `method`, and `stale` (cross-tab
155
201
  `_rsc_stale` signal). All are `undefined` on plain navigation (no action).
156
202
 
203
+ Two idioms, picked by what an _unrelated_ action should do. `ctx.isAction()`
204
+ returns a raw boolean, so combine it with `|| undefined` to **defer** ("mine,
205
+ else let the default decide": `ctx.isAction(CartActions) || undefined`) or leave
206
+ it bare to **suppress** ("mine only": `ctx.isAction(CartActions)`). Prefer the
207
+ defer form unless a sibling segment must own the unrelated-action decision.
208
+
157
209
  ```ts
158
210
  // re-render only when checkout actually succeeded; defer otherwise
159
211
  revalidate((ctx) => (ctx.isAction(checkout) && ctx.actionResult?.ok) || undefined),
@@ -179,6 +231,12 @@ resolve `dist/` outside `./vite`, and it may lag `src/`.
179
231
 
180
232
  Grouped by concern — read when you need to…
181
233
 
234
+ **Positioning & evaluation**:
235
+
236
+ | Skill | Description |
237
+ | ------------- | ------------------------------------------------------------ |
238
+ | `/comparison` | Compare Rango with Next.js, TanStack Start, and Waku fairly. |
239
+
182
240
  **Structure & routing** — shape URLs, layouts, navigation, and request processing:
183
241
 
184
242
  | Skill | Description |
@@ -192,6 +250,7 @@ Grouped by concern — read when you need to…
192
250
  | `/host-router` | Multi-app host routing with domain/subdomain patterns |
193
251
  | `/links` | URL generation: ctx.reverse, href, useHref, useMount, scopedReverse |
194
252
  | `/response-routes` | JSON/text/HTML/XML/stream endpoints with `path.json()`, `path.text()` |
253
+ | `/api-client` | Typed client for consuming your own response-route JSON APIs (recipe) |
195
254
  | `/mime-routes` | Content negotiation — same URL, different response types via Accept header |
196
255
  | `/streams-and-websockets` | SSE via `path.stream` and WebSocket upgrades via `path.any` |
197
256
  | `/handler-use` | Attach default loaders/middleware to a handler via `handler.use` |
@@ -199,28 +258,33 @@ Grouped by concern — read when you need to…
199
258
 
200
259
  **Data & caching** — fetch, mutate, and cache:
201
260
 
202
- | Skill | Description |
203
- | ----------------- | ----------------------------------------------------------------------- |
204
- | `/loader` | Data loaders with `createLoader()` and `revalidate()` |
205
- | `/server-actions` | Mutations with `"use server"`, useActionState, validation, revalidation |
206
- | `/caching` | Segment caching with memory or KV stores |
207
- | `/use-cache` | Function-level caching with `"use cache"` directive |
208
- | `/cache-guide` | When to use `cache()` vs `"use cache"` — differences and decision guide |
209
- | `/document-cache` | Edge caching with Cache-Control headers |
210
- | `/prerender` | Pre-render route segments at build time (Passthrough live fallback) |
261
+ | Skill | Description |
262
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
263
+ | `/loader` | Data loaders with `createLoader()` and `revalidate()` |
264
+ | `/server-actions` | Mutations with `"use server"`, useActionState, validation, revalidation |
265
+ | `/caching` | Segment caching with memory or KV stores |
266
+ | `/use-cache` | Function-level caching with `"use cache"` directive |
267
+ | `/cache-guide` | When to use `cache()` vs `"use cache"` — differences and decision guide |
268
+ | `/document-cache` | Edge caching with Cache-Control headers |
269
+ | `/ppr` | PPR shell caching: cached shell served instantly, live holes resumed — a hole is a `loading()` subtree OR a pending promise under `<Suspense>` (no loader needed) |
270
+ | `/prerender` | Pre-render route segments at build time (Passthrough live fallback) |
271
+ | `/shell-manifest` | Replayed handles as cache metadata read by live loaders (frozen shell, batched live holes) |
211
272
 
212
273
  **Client & presentation** — build the client-side UX:
213
274
 
214
- | Skill | Description |
215
- | ------------------- | ------------------------------------------------------------------------- |
216
- | `/hooks` | Client-side React hooks |
217
- | `/theme` | Light/dark mode with FOUC prevention |
218
- | `/i18n` | Locale routing with `:locale?`, resolution chains, react-intl integration |
219
- | `/fonts` | Load web fonts with preload hints |
220
- | `/tailwind` | Set up Tailwind CSS v4 with `?url` imports |
221
- | `/view-transitions` | React View Transitions on layouts, routes, and parallel slots |
222
- | `/breadcrumbs` | Built-in Breadcrumbs handle for breadcrumb navigation |
223
- | `/react-compiler` | Enable React Compiler (opt-in) the vite-rsc way; client-only scope |
275
+ | Skill | Description |
276
+ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
277
+ | `/hooks` | Client-side React hooks |
278
+ | `/theme` | Light/dark mode with FOUC prevention |
279
+ | `/i18n` | Locale routing with `:locale?`, resolution chains, react-intl integration |
280
+ | `/fonts` | Load web fonts with preload hints |
281
+ | `/css` | Import CSS in the Document `<head>` (`?url` + managed `precedence` links) |
282
+ | `/scripts` | Inject third-party scripts (GTM/analytics) into head/body via the `Script` handle; nonce auto-applied to document-rendered scripts |
283
+ | `/tailwind` | Set up Tailwind CSS v4 with `?url` imports |
284
+ | `/view-transitions` | React View Transitions on layouts, routes, and parallel slots |
285
+ | `/defer-hydration` | Full body HTML in the PPR shell + hydration off the critical path (gated Suspense boundary, content-as-fallback) |
286
+ | `/breadcrumbs` | Built-in Breadcrumbs handle for breadcrumb navigation |
287
+ | `/react-compiler` | Enable React Compiler (opt-in) the vite-rsc way; client-only scope |
224
288
 
225
289
  **Observability & production health**:
226
290
 
@@ -230,6 +294,12 @@ Grouped by concern — read when you need to…
230
294
  | `/bundle-analysis` | Audit your app's production bundle for server leaks and oversized chunks |
231
295
  | `/debug-manifest` | Inspect route manifest structure |
232
296
 
297
+ **Deployment**:
298
+
299
+ | Skill | Description |
300
+ | --------- | ----------------------------------------------------------------------------------------- |
301
+ | `/vercel` | Deploy to Vercel Functions (`preset: "vercel"`), Runtime Cache, and `createVercelTracing` |
302
+
233
303
  **Testing**:
234
304
 
235
305
  | Skill | Description |
@@ -310,7 +380,11 @@ dotfiles, and existing `.gen.` files.
310
380
  ### Recursive includes
311
381
 
312
382
  The generator follows `include()` calls across files, resolving imports to build
313
- the full route tree. Circular includes are detected and warned about.
383
+ the full route tree. It resolves both the eager form `include("/x", patterns)`
384
+ and the code-split async form `include("/x", () => import("./x"))` — for the
385
+ latter it walks the imported module's `export default urls(...)`, including any
386
+ nested `include()`s inside it — so a code-split route group is still fully typed
387
+ (see `/composability`). Circular includes are detected and warned about.
314
388
 
315
389
  ### First-wins deduplication
316
390