@rangojs/router 0.0.0-experimental.135c6902 → 0.0.0-experimental.136

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 (404) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +440 -133
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3386 -1111
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +78 -25
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +64 -2
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +247 -23
  13. package/skills/caching/SKILL.md +281 -11
  14. package/skills/composability/SKILL.md +27 -3
  15. package/skills/css/SKILL.md +76 -0
  16. package/skills/debug-manifest/SKILL.md +4 -2
  17. package/skills/document-cache/SKILL.md +78 -55
  18. package/skills/handler-use/SKILL.md +364 -0
  19. package/skills/hooks/SKILL.md +250 -30
  20. package/skills/host-router/SKILL.md +83 -23
  21. package/skills/i18n/SKILL.md +276 -0
  22. package/skills/intercept/SKILL.md +87 -18
  23. package/skills/layout/SKILL.md +35 -9
  24. package/skills/links/SKILL.md +249 -17
  25. package/skills/loader/SKILL.md +289 -53
  26. package/skills/middleware/SKILL.md +52 -13
  27. package/skills/migrate-nextjs/SKILL.md +584 -0
  28. package/skills/migrate-react-router/SKILL.md +914 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +144 -7
  32. package/skills/prerender/SKILL.md +172 -125
  33. package/skills/rango/SKILL.md +251 -22
  34. package/skills/react-compiler/SKILL.md +168 -0
  35. package/skills/response-routes/SKILL.md +123 -48
  36. package/skills/route/SKILL.md +101 -5
  37. package/skills/router-setup/SKILL.md +117 -10
  38. package/skills/scripts/SKILL.md +179 -0
  39. package/skills/server-actions/SKILL.md +775 -0
  40. package/skills/streams-and-websockets/SKILL.md +283 -0
  41. package/skills/tailwind/SKILL.md +27 -3
  42. package/skills/testing/SKILL.md +130 -0
  43. package/skills/testing/bindings.md +103 -0
  44. package/skills/testing/cache-prerender.md +127 -0
  45. package/skills/testing/client-components.md +124 -0
  46. package/skills/testing/e2e-parity.md +125 -0
  47. package/skills/testing/flight.md +91 -0
  48. package/skills/testing/handles.md +129 -0
  49. package/skills/testing/loader.md +128 -0
  50. package/skills/testing/middleware.md +99 -0
  51. package/skills/testing/render-handler.md +122 -0
  52. package/skills/testing/response-routes.md +95 -0
  53. package/skills/testing/reverse-and-types.md +84 -0
  54. package/skills/testing/server-actions.md +107 -0
  55. package/skills/testing/server-tree.md +128 -0
  56. package/skills/testing/setup.md +123 -0
  57. package/skills/typesafety/SKILL.md +332 -29
  58. package/skills/use-cache/SKILL.md +57 -14
  59. package/skills/view-transitions/SKILL.md +337 -0
  60. package/src/__augment-tests__/augment.ts +81 -0
  61. package/src/__augment-tests__/augmented.check.ts +116 -0
  62. package/src/__internal.ts +1 -66
  63. package/src/browser/action-coordinator.ts +53 -36
  64. package/src/browser/action-fence.ts +47 -0
  65. package/src/browser/app-shell.ts +39 -0
  66. package/src/browser/app-version.ts +14 -0
  67. package/src/browser/connection-warmup.ts +134 -0
  68. package/src/browser/cookie-name.ts +140 -0
  69. package/src/browser/event-controller.ts +192 -150
  70. package/src/browser/history-state.ts +21 -0
  71. package/src/browser/index.ts +3 -3
  72. package/src/browser/invalidate-client-cache.ts +52 -0
  73. package/src/browser/navigation-bridge.ts +131 -30
  74. package/src/browser/navigation-client.ts +199 -86
  75. package/src/browser/navigation-store-handle.ts +38 -0
  76. package/src/browser/navigation-store.ts +157 -74
  77. package/src/browser/navigation-transaction.ts +9 -59
  78. package/src/browser/network-error-handler.ts +34 -7
  79. package/src/browser/partial-update.ts +174 -109
  80. package/src/browser/prefetch/cache.ts +222 -69
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +113 -32
  83. package/src/browser/prefetch/resource-ready.ts +77 -0
  84. package/src/browser/rango-state.ts +158 -76
  85. package/src/browser/react/Link.tsx +102 -15
  86. package/src/browser/react/NavigationProvider.tsx +300 -122
  87. package/src/browser/react/ScrollRestoration.tsx +10 -6
  88. package/src/browser/react/context.ts +7 -2
  89. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  90. package/src/browser/react/filter-segment-order.ts +66 -7
  91. package/src/browser/react/index.ts +0 -48
  92. package/src/browser/react/location-state-shared.ts +178 -8
  93. package/src/browser/react/location-state.ts +39 -14
  94. package/src/browser/react/use-action.ts +6 -15
  95. package/src/browser/react/use-handle.ts +23 -69
  96. package/src/browser/react/use-href.tsx +8 -1
  97. package/src/browser/react/use-link-status.ts +33 -8
  98. package/src/browser/react/use-navigation.ts +32 -7
  99. package/src/browser/react/use-params.ts +20 -10
  100. package/src/browser/react/use-reverse.ts +106 -0
  101. package/src/browser/react/use-router.ts +46 -11
  102. package/src/browser/react/use-search-params.ts +0 -5
  103. package/src/browser/react/use-segments.ts +11 -21
  104. package/src/browser/response-adapter.ts +99 -8
  105. package/src/browser/rsc-router.tsx +125 -28
  106. package/src/browser/scroll-restoration.ts +37 -22
  107. package/src/browser/segment-reconciler.ts +36 -14
  108. package/src/browser/segment-structure-assert.ts +2 -2
  109. package/src/browser/server-action-bridge.ts +222 -61
  110. package/src/browser/types.ts +115 -12
  111. package/src/browser/validate-redirect-origin.ts +43 -16
  112. package/src/build/collect-fallback-refs.ts +107 -0
  113. package/src/build/generate-manifest.ts +65 -40
  114. package/src/build/generate-route-types.ts +5 -1
  115. package/src/build/index.ts +8 -2
  116. package/src/build/prefix-tree-utils.ts +123 -0
  117. package/src/build/route-trie.ts +165 -36
  118. package/src/build/route-types/ast-route-extraction.ts +15 -8
  119. package/src/build/route-types/codegen.ts +16 -5
  120. package/src/build/route-types/include-resolution.ts +125 -24
  121. package/src/build/route-types/param-extraction.ts +6 -3
  122. package/src/build/route-types/per-module-writer.ts +22 -6
  123. package/src/build/route-types/router-processing.ts +260 -94
  124. package/src/build/route-types/scan-filter.ts +9 -2
  125. package/src/build/route-types/source-scan.ts +216 -0
  126. package/src/build/runtime-discovery.ts +9 -20
  127. package/src/cache/cache-error.ts +104 -0
  128. package/src/cache/cache-key-utils.ts +29 -13
  129. package/src/cache/cache-policy.ts +108 -34
  130. package/src/cache/cache-runtime.ts +239 -52
  131. package/src/cache/cache-scope.ts +234 -87
  132. package/src/cache/cache-tag.ts +103 -0
  133. package/src/cache/cf/cf-base64.ts +33 -0
  134. package/src/cache/cf/cf-cache-constants.ts +127 -0
  135. package/src/cache/cf/cf-cache-store.ts +1989 -378
  136. package/src/cache/cf/cf-cache-types.ts +349 -0
  137. package/src/cache/cf/cf-kv-utils.ts +46 -0
  138. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  139. package/src/cache/cf/index.ts +6 -16
  140. package/src/cache/document-cache.ts +89 -21
  141. package/src/cache/handle-snapshot.ts +70 -0
  142. package/src/cache/index.ts +10 -20
  143. package/src/cache/memory-segment-store.ts +136 -37
  144. package/src/cache/profile-registry.ts +46 -31
  145. package/src/cache/read-through-swr.ts +56 -12
  146. package/src/cache/segment-codec.ts +9 -17
  147. package/src/cache/tag-invalidation.ts +230 -0
  148. package/src/cache/taint.ts +55 -0
  149. package/src/cache/types.ts +37 -100
  150. package/src/client.rsc.tsx +44 -21
  151. package/src/client.tsx +119 -290
  152. package/src/cloudflare/index.ts +11 -0
  153. package/src/cloudflare/tracing.ts +109 -0
  154. package/src/component-utils.ts +19 -0
  155. package/src/components/DefaultDocument.tsx +8 -2
  156. package/src/context-var.ts +84 -2
  157. package/src/decode-loader-results.ts +52 -0
  158. package/src/defer.ts +196 -0
  159. package/src/deps/ssr.ts +0 -1
  160. package/src/encode-kv.ts +49 -0
  161. package/src/errors.ts +30 -4
  162. package/src/escape-script.ts +52 -0
  163. package/src/handle.ts +70 -22
  164. package/src/handles/MetaTags.tsx +62 -19
  165. package/src/handles/Scripts.tsx +183 -0
  166. package/src/handles/breadcrumbs.ts +37 -8
  167. package/src/handles/is-thenable.ts +19 -0
  168. package/src/handles/meta.ts +51 -40
  169. package/src/handles/script.ts +244 -0
  170. package/src/host/cookie-handler.ts +9 -60
  171. package/src/host/errors.ts +0 -24
  172. package/src/host/index.ts +8 -2
  173. package/src/host/pattern-matcher.ts +23 -52
  174. package/src/host/router.ts +107 -99
  175. package/src/host/testing.ts +40 -27
  176. package/src/host/types.ts +37 -4
  177. package/src/host/utils.ts +1 -1
  178. package/src/href-client.ts +137 -22
  179. package/src/index.rsc.ts +99 -13
  180. package/src/index.ts +139 -19
  181. package/src/internal-debug.ts +11 -10
  182. package/src/loader-store.ts +500 -0
  183. package/src/loader.rsc.ts +20 -13
  184. package/src/loader.ts +12 -11
  185. package/src/missing-id-error.ts +68 -0
  186. package/src/outlet-context.ts +1 -1
  187. package/src/outlet-provider.tsx +1 -5
  188. package/src/prerender/param-hash.ts +16 -16
  189. package/src/prerender/store.ts +37 -41
  190. package/src/prerender.ts +198 -82
  191. package/src/redirect-origin.ts +100 -0
  192. package/src/regex-escape.ts +8 -0
  193. package/src/render-error-thrower.tsx +20 -0
  194. package/src/response-utils.ts +62 -0
  195. package/src/reverse.ts +65 -15
  196. package/src/root-error-boundary.tsx +1 -19
  197. package/src/route-content-wrapper.tsx +19 -77
  198. package/src/route-definition/dsl-helpers.ts +461 -304
  199. package/src/route-definition/helper-factories.ts +28 -140
  200. package/src/route-definition/helpers-types.ts +149 -74
  201. package/src/route-definition/index.ts +4 -2
  202. package/src/route-definition/redirect.ts +51 -10
  203. package/src/route-definition/resolve-handler-use.ts +160 -0
  204. package/src/route-definition/use-item-types.ts +29 -0
  205. package/src/route-map-builder.ts +0 -16
  206. package/src/route-types.ts +37 -46
  207. package/src/router/basename.ts +14 -0
  208. package/src/router/content-negotiation.ts +164 -17
  209. package/src/router/error-handling.ts +45 -18
  210. package/src/router/find-match.ts +44 -23
  211. package/src/router/handler-context.ts +83 -39
  212. package/src/router/instrument.ts +350 -0
  213. package/src/router/intercept-resolution.ts +48 -24
  214. package/src/router/lazy-includes.ts +15 -52
  215. package/src/router/loader-resolution.ts +274 -56
  216. package/src/router/logging.ts +0 -6
  217. package/src/router/manifest.ts +40 -42
  218. package/src/router/match-api.ts +124 -204
  219. package/src/router/match-context.ts +0 -22
  220. package/src/router/match-handlers.ts +58 -58
  221. package/src/router/match-middleware/background-revalidation.ts +54 -25
  222. package/src/router/match-middleware/cache-lookup.ts +205 -271
  223. package/src/router/match-middleware/cache-store.ts +81 -50
  224. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  225. package/src/router/match-middleware/segment-resolution.ts +45 -14
  226. package/src/router/match-pipelines.ts +1 -42
  227. package/src/router/match-result.ts +93 -39
  228. package/src/router/metrics.ts +5 -34
  229. package/src/router/middleware-types.ts +13 -142
  230. package/src/router/middleware.ts +268 -171
  231. package/src/router/navigation-snapshot.ts +131 -0
  232. package/src/router/params-util.ts +23 -0
  233. package/src/router/pattern-matching.ts +132 -90
  234. package/src/router/prefetch-cache-ttl.ts +51 -0
  235. package/src/router/prefetch-limits.ts +37 -0
  236. package/src/router/prerender-match.ts +195 -56
  237. package/src/router/preview-match.ts +32 -102
  238. package/src/router/request-classification.ts +276 -0
  239. package/src/router/revalidation.ts +123 -73
  240. package/src/router/route-snapshot.ts +244 -0
  241. package/src/router/router-context.ts +3 -27
  242. package/src/router/router-interfaces.ts +129 -35
  243. package/src/router/router-options.ts +202 -15
  244. package/src/router/router-registry.ts +2 -5
  245. package/src/router/segment-resolution/fresh.ts +197 -92
  246. package/src/router/segment-resolution/helpers.ts +115 -30
  247. package/src/router/segment-resolution/loader-cache.ts +76 -39
  248. package/src/router/segment-resolution/revalidation.ts +392 -338
  249. package/src/router/segment-resolution/static-store.ts +19 -5
  250. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  251. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  252. package/src/router/segment-resolution.ts +5 -1
  253. package/src/router/segment-wrappers.ts +6 -5
  254. package/src/router/state-cookie-name.ts +33 -0
  255. package/src/router/substitute-pattern-params.ts +56 -0
  256. package/src/router/telemetry-otel.ts +161 -199
  257. package/src/router/telemetry.ts +96 -19
  258. package/src/router/timeout.ts +0 -20
  259. package/src/router/tracing.ts +206 -0
  260. package/src/router/trie-matching.ts +163 -59
  261. package/src/router/types.ts +10 -63
  262. package/src/router/url-params.ts +44 -0
  263. package/src/router.ts +174 -54
  264. package/src/rsc/handler-context.ts +3 -2
  265. package/src/rsc/handler.ts +660 -518
  266. package/src/rsc/helpers.ts +168 -46
  267. package/src/rsc/index.ts +2 -5
  268. package/src/rsc/json-route-result.ts +38 -0
  269. package/src/rsc/loader-fetch.ts +127 -31
  270. package/src/rsc/manifest-init.ts +33 -42
  271. package/src/rsc/origin-guard.ts +39 -25
  272. package/src/rsc/progressive-enhancement.ts +133 -13
  273. package/src/rsc/redirect-guard.ts +99 -0
  274. package/src/rsc/response-cache-serve.ts +238 -0
  275. package/src/rsc/response-error.ts +79 -12
  276. package/src/rsc/response-route-handler.ts +99 -189
  277. package/src/rsc/rsc-rendering.ts +115 -73
  278. package/src/rsc/runtime-warnings.ts +23 -10
  279. package/src/rsc/server-action.ts +287 -113
  280. package/src/rsc/ssr-setup.ts +18 -2
  281. package/src/rsc/transition-gate.ts +89 -0
  282. package/src/rsc/types.ts +36 -6
  283. package/src/runtime-env.ts +18 -0
  284. package/src/search-params.ts +35 -30
  285. package/src/segment-content-promise.ts +67 -0
  286. package/src/segment-loader-promise.ts +149 -0
  287. package/src/segment-system.tsx +269 -202
  288. package/src/serialize.ts +243 -0
  289. package/src/server/context.ts +235 -51
  290. package/src/server/cookie-parse.ts +32 -0
  291. package/src/server/cookie-store.ts +80 -5
  292. package/src/server/handle-store.ts +40 -38
  293. package/src/server/loader-registry.ts +38 -46
  294. package/src/server/request-context.ts +442 -173
  295. package/src/ssr/index.tsx +24 -16
  296. package/src/static-handler.ts +27 -18
  297. package/src/testing/cache-status.ts +162 -0
  298. package/src/testing/collect-handle.ts +40 -0
  299. package/src/testing/dispatch.ts +701 -0
  300. package/src/testing/dom.entry.ts +22 -0
  301. package/src/testing/e2e/fixture.ts +188 -0
  302. package/src/testing/e2e/index.ts +128 -0
  303. package/src/testing/e2e/matchers.ts +35 -0
  304. package/src/testing/e2e/page-helpers.ts +272 -0
  305. package/src/testing/e2e/parity.ts +387 -0
  306. package/src/testing/e2e/server.ts +195 -0
  307. package/src/testing/flight-matchers.ts +97 -0
  308. package/src/testing/flight-normalize.ts +11 -0
  309. package/src/testing/flight-runtime.d.ts +57 -0
  310. package/src/testing/flight-tree.ts +682 -0
  311. package/src/testing/flight.entry.ts +52 -0
  312. package/src/testing/flight.ts +257 -0
  313. package/src/testing/generated-routes.ts +183 -0
  314. package/src/testing/index.ts +105 -0
  315. package/src/testing/internal/context.ts +371 -0
  316. package/src/testing/internal/flight-client-globals.ts +30 -0
  317. package/src/testing/internal/seed-vars.ts +54 -0
  318. package/src/testing/render-handler.ts +357 -0
  319. package/src/testing/render-route.tsx +581 -0
  320. package/src/testing/run-loader.ts +385 -0
  321. package/src/testing/run-middleware.ts +205 -0
  322. package/src/testing/run-transition-when.ts +164 -0
  323. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  324. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  325. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  326. package/src/testing/vitest-stubs/version.ts +5 -0
  327. package/src/testing/vitest.ts +305 -0
  328. package/src/theme/ThemeProvider.tsx +20 -58
  329. package/src/theme/ThemeScript.tsx +7 -9
  330. package/src/theme/constants.ts +52 -13
  331. package/src/theme/index.ts +0 -7
  332. package/src/theme/theme-context.ts +1 -5
  333. package/src/theme/theme-script.ts +22 -21
  334. package/src/theme/use-theme.ts +0 -3
  335. package/src/types/boundaries.ts +0 -35
  336. package/src/types/cache-types.ts +17 -8
  337. package/src/types/error-types.ts +30 -90
  338. package/src/types/global-namespace.ts +54 -41
  339. package/src/types/handler-context.ts +234 -82
  340. package/src/types/index.ts +3 -10
  341. package/src/types/loader-types.ts +44 -15
  342. package/src/types/request-scope.ts +112 -0
  343. package/src/types/route-config.ts +6 -50
  344. package/src/types/route-entry.ts +12 -7
  345. package/src/types/segments.ts +136 -15
  346. package/src/urls/include-helper.ts +33 -70
  347. package/src/urls/index.ts +1 -11
  348. package/src/urls/path-helper-types.ts +68 -18
  349. package/src/urls/path-helper.ts +57 -111
  350. package/src/urls/pattern-types.ts +48 -19
  351. package/src/urls/response-types.ts +25 -22
  352. package/src/urls/type-extraction.ts +58 -139
  353. package/src/urls/urls-function.ts +1 -19
  354. package/src/use-loader.tsx +346 -89
  355. package/src/vite/debug.ts +185 -0
  356. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  357. package/src/vite/discovery/discover-routers.ts +130 -85
  358. package/src/vite/discovery/discovery-errors.ts +194 -0
  359. package/src/vite/discovery/gate-state.ts +171 -0
  360. package/src/vite/discovery/prerender-collection.ts +214 -132
  361. package/src/vite/discovery/route-types-writer.ts +40 -84
  362. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  363. package/src/vite/discovery/state.ts +57 -4
  364. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  365. package/src/vite/index.ts +6 -0
  366. package/src/vite/inject-client-debug.ts +36 -0
  367. package/src/vite/plugin-types.ts +178 -5
  368. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  369. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  370. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  371. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  372. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  373. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  374. package/src/vite/plugins/expose-action-id.ts +48 -95
  375. package/src/vite/plugins/expose-id-utils.ts +96 -51
  376. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  377. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  378. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  379. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  380. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  381. package/src/vite/plugins/performance-tracks.ts +89 -0
  382. package/src/vite/plugins/refresh-cmd.ts +89 -27
  383. package/src/vite/plugins/use-cache-transform.ts +73 -83
  384. package/src/vite/plugins/version-injector.ts +40 -29
  385. package/src/vite/plugins/version-plugin.ts +37 -40
  386. package/src/vite/plugins/virtual-entries.ts +39 -25
  387. package/src/vite/rango.ts +119 -111
  388. package/src/vite/router-discovery.ts +941 -142
  389. package/src/vite/utils/ast-handler-extract.ts +26 -35
  390. package/src/vite/utils/banner.ts +1 -1
  391. package/src/vite/utils/bundle-analysis.ts +10 -15
  392. package/src/vite/utils/client-chunks.ts +184 -0
  393. package/src/vite/utils/directive-prologue.ts +40 -0
  394. package/src/vite/utils/forward-user-plugins.ts +171 -0
  395. package/src/vite/utils/manifest-utils.ts +4 -59
  396. package/src/vite/utils/package-resolution.ts +20 -52
  397. package/src/vite/utils/prerender-utils.ts +81 -34
  398. package/src/vite/utils/shared-utils.ts +92 -42
  399. package/src/browser/action-response-classifier.ts +0 -99
  400. package/src/browser/react/use-client-cache.ts +0 -58
  401. package/src/browser/shallow.ts +0 -40
  402. package/src/handles/index.ts +0 -7
  403. package/src/network-error-thrower.tsx +0 -23
  404. package/src/router/middleware-cookies.ts +0 -55
package/src/vite/rango.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PluginOption } from "vite";
1
+ import { type PluginOption } from "vite";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { exposeActionId } from "./plugins/expose-action-id.js";
@@ -12,20 +12,37 @@ import { VIRTUAL_IDS } from "./plugins/virtual-entries.js";
12
12
  import {
13
13
  getExcludeDeps,
14
14
  getPackageAliases,
15
+ getPublishedPackageName,
16
+ getVendorAliases,
15
17
  } from "./utils/package-resolution.js";
16
18
  import { findRouterFiles } from "../build/generate-route-types.js";
17
19
  import { createVersionPlugin } from "./plugins/version-plugin.js";
18
20
  import {
19
- sharedEsbuildOptions,
21
+ sharedRolldownOptions,
20
22
  createVirtualEntriesPlugin,
21
23
  onwarn,
22
24
  getManualChunks,
23
25
  } from "./utils/shared-utils.js";
26
+ import {
27
+ resolveClientChunks,
28
+ type ClientChunkContext,
29
+ } from "./utils/client-chunks.js";
24
30
  import type { RangoOptions } from "./plugin-types.js";
25
31
  import { printBanner, rangoVersion } from "./utils/banner.js";
26
32
  import { createVersionInjectorPlugin } from "./plugins/version-injector.js";
27
33
  import { createCjsToEsmPlugin } from "./plugins/cjs-to-esm.js";
28
34
  import { createRouterDiscoveryPlugin } from "./router-discovery.js";
35
+ import { performanceTracksPlugin } from "./plugins/performance-tracks.js";
36
+ import { createRangoDebugger, NS } from "./debug.js";
37
+
38
+ const debugConfig = createRangoDebugger(NS.config);
39
+
40
+ // The leading-directive 'use client' sniff is shared with version-plugin's
41
+ // getClientModuleSignature so the two cannot drift. Imported for local use by the
42
+ // HMR transform below and re-exported because the E8 sniff test imports it from
43
+ // this module.
44
+ import { hasUseClientDirective } from "./utils/directive-prologue.js";
45
+ export { hasUseClientDirective };
29
46
 
30
47
  /**
31
48
  * Vite plugin for @rangojs/router.
@@ -52,15 +69,46 @@ import { createRouterDiscoveryPlugin } from "./router-discovery.js";
52
69
  * ```
53
70
  */
54
71
  export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
72
+ const rangoStart = performance.now();
55
73
  const resolvedOptions: RangoOptions = options ?? { preset: "node" };
56
74
  const preset = resolvedOptions.preset ?? "node";
57
75
  const showBanner = resolvedOptions.banner ?? true;
76
+ const clientChunksOption = resolvedOptions.clientChunks ?? true;
77
+ const useBuiltInClientChunks = clientChunksOption === true;
78
+ const clientChunkCtx: ClientChunkContext | undefined = useBuiltInClientChunks
79
+ ? { fallbackRefs: new Set<string>() }
80
+ : undefined;
81
+ const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
82
+ debugConfig?.("rango(%s) setup start", preset);
58
83
 
59
84
  const plugins: PluginOption[] = [];
60
85
 
61
- // Get package resolution info (workspace vs npm install)
62
- const rangoAliases = getPackageAliases();
63
- const excludeDeps = getExcludeDeps();
86
+ // Get package resolution info (workspace vs npm install).
87
+ // Vendor aliases redirect the bare plugin-rsc vendor specs (which plugin-rsc
88
+ // itself injects into optimizeDeps.include) to absolute paths resolved from
89
+ // this package — so strict-pnpm consumers don't hit "Failed to resolve
90
+ // dependency" warnings when those deps aren't hoisted to their app root.
91
+ const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
92
+ const excludeDeps = [
93
+ ...getExcludeDeps(),
94
+ // plugin-rsc itself injects these into the client env's
95
+ // optimizeDeps.include, which overrides exclude for the dep's own
96
+ // pre-bundle entry. What exclude still controls is how *other*
97
+ // pre-bundled deps treat imports of these specs (external vs inlined)
98
+ // via esbuildCjsExternalPlugin. The cjs-to-esm transform in
99
+ // plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
100
+ // where client.browser's bare include fails to resolve and Vite ends up
101
+ // serving the raw CJS file at dev-serve time.
102
+ "@vitejs/plugin-rsc/browser",
103
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.browser",
104
+ ];
105
+
106
+ // Vite supports a nested `A > B` syntax in optimizeDeps.include that resolves
107
+ // B from A's location. We anchor transitive deps (rsc-html-stream,
108
+ // @vitejs/plugin-rsc/vendor/*) to @rangojs/router so pnpm consumers — where
109
+ // these aren't visible at the app root — can still pre-bundle them.
110
+ const pkg = getPublishedPackageName();
111
+ const nested = (spec: string) => `${pkg} > ${spec}`;
64
112
 
65
113
  // Mutable ref for router path (node preset only).
66
114
  // Set immediately when user-specified, or populated by the auto-discover
@@ -72,14 +120,8 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
72
120
  const prerenderEnabled = true;
73
121
 
74
122
  if (preset === "cloudflare") {
75
- // Cloudflare preset: configure entries for cloudflare worker setup
76
- // Router is not needed here - worker.rsc.tsx imports it directly
77
-
78
- // Dynamically import @vitejs/plugin-rsc
79
123
  const { default: rsc } = await import("@vitejs/plugin-rsc");
80
124
 
81
- // Only client and ssr entries - rsc entry is handled by cloudflare plugin
82
- // Always use virtual modules for cloudflare preset
83
125
  const finalEntries: { client: string; ssr: string } = {
84
126
  client: VIRTUAL_IDS.browser,
85
127
  ssr: VIRTUAL_IDS.ssr,
@@ -90,16 +132,21 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
90
132
  enforce: "pre",
91
133
 
92
134
  config() {
93
- // Configure environments for cloudflare deployment
94
135
  return {
95
- // Exclude rsc-router modules from optimization to prevent module duplication
96
- // This ensures the same Context instance is used by both browser entry and RSC proxy modules
97
136
  optimizeDeps: {
98
137
  exclude: excludeDeps,
99
- esbuildOptions: sharedEsbuildOptions,
138
+ rolldownOptions: sharedRolldownOptions,
100
139
  },
101
140
  resolve: {
102
141
  alias: rangoAliases,
142
+ // Force a single React/React-DOM copy across all three RSC
143
+ // environments. RSC requires exactly one react/react-dom instance
144
+ // per environment runtime; consumer install topologies (pnpm
145
+ // strict layout, experimental React pins, third-party "use client"
146
+ // packages) can otherwise resolve duplicate copies, causing
147
+ // "Invalid hook call" / lost context. Child environments inherit
148
+ // this root dedupe, and Vite merges it with any consumer dedupe.
149
+ dedupe: ["react", "react-dom"],
103
150
  },
104
151
  build: {
105
152
  rollupOptions: { onwarn },
@@ -108,30 +155,22 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
108
155
  client: {
109
156
  build: {
110
157
  rollupOptions: {
158
+ onwarn,
111
159
  output: {
112
160
  manualChunks: getManualChunks,
113
161
  },
114
162
  },
115
163
  },
116
- // Pre-bundle rsc-html-stream to prevent discovery during first request
117
- // Exclude rsc-router modules to ensure same Context instance
118
164
  optimizeDeps: {
119
- include: ["rsc-html-stream/client"],
165
+ include: [nested("rsc-html-stream/client")],
120
166
  exclude: excludeDeps,
121
- esbuildOptions: sharedEsbuildOptions,
167
+ rolldownOptions: sharedRolldownOptions,
122
168
  },
123
169
  },
124
170
  ssr: {
125
- // Build SSR inside RSC directory so wrangler can deploy self-contained dist/rsc
126
171
  build: {
127
172
  outDir: "./dist/rsc/ssr",
128
173
  },
129
- resolve: {
130
- // Ensure single React instance in SSR child environment
131
- dedupe: ["react", "react-dom"],
132
- },
133
- // Pre-bundle SSR entry and React for proper module linking with childEnvironments
134
- // All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
135
174
  optimizeDeps: {
136
175
  entries: [finalEntries.ssr],
137
176
  include: [
@@ -141,26 +180,27 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
141
180
  "react-dom/static.edge",
142
181
  "react/jsx-runtime",
143
182
  "react/jsx-dev-runtime",
144
- "rsc-html-stream/server",
145
- "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
183
+ nested("rsc-html-stream/server"),
184
+ nested(
185
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
186
+ ),
146
187
  ],
147
188
  exclude: excludeDeps,
148
- esbuildOptions: sharedEsbuildOptions,
189
+ rolldownOptions: sharedRolldownOptions,
149
190
  },
150
191
  },
151
192
  rsc: {
152
- // RSC environment needs exclude list and esbuild options
153
- // Exclude rsc-router modules to prevent createContext in RSC environment
154
193
  optimizeDeps: {
155
- // Pre-bundle all RSC deps to prevent late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
156
194
  include: [
157
195
  "react",
158
196
  "react/jsx-runtime",
159
197
  "react/jsx-dev-runtime",
160
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
198
+ nested(
199
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
200
+ ),
161
201
  ],
162
202
  exclude: excludeDeps,
163
- esbuildOptions: sharedEsbuildOptions,
203
+ rolldownOptions: sharedRolldownOptions,
164
204
  },
165
205
  },
166
206
  },
@@ -181,23 +221,16 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
181
221
  });
182
222
 
183
223
  plugins.push(createVirtualEntriesPlugin(finalEntries));
184
-
185
- // Add RSC plugin with cloudflare-specific options
186
- // Note: loadModuleDevProxy should NOT be used with childEnvironments
187
- // since SSR runs in workerd alongside RSC
224
+ plugins.push(performanceTracksPlugin());
188
225
  plugins.push(
189
226
  rsc({
190
227
  entries: finalEntries,
191
228
  serverHandler: false,
229
+ clientChunks,
192
230
  }) as PluginOption,
193
231
  );
194
-
195
- // Deduplicate client references from third-party packages in dev mode.
196
- // Prevents module duplication when server components import "use client"
197
- // packages that are also imported directly by client components.
198
232
  plugins.push(clientRefDedup());
199
233
  } else {
200
- // Auto-discover router using Vite's resolved root (not process.cwd())
201
234
  plugins.push({
202
235
  name: "@rangojs/router:auto-discover",
203
236
  config(userConfig) {
@@ -218,20 +251,17 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
218
251
  " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f),
219
252
  )
220
253
  .join("\n");
221
- throw new Error(`[rsc-router] Multiple routers found:\n${list}`);
254
+ throw new Error(`[rango] Multiple routers found:\n${list}`);
222
255
  }
223
- // 0 found: routerRef.path stays undefined, warn at startup via discovery plugin
224
256
  },
225
257
  });
226
258
 
227
- // Always use virtual entries for client, ssr, and rsc
228
259
  const finalEntries = {
229
260
  client: VIRTUAL_IDS.browser,
230
261
  ssr: VIRTUAL_IDS.ssr,
231
262
  rsc: VIRTUAL_IDS.rsc,
232
263
  };
233
264
 
234
- // Dynamically import @vitejs/plugin-rsc
235
265
  const { default: rsc } = await import("@vitejs/plugin-rsc");
236
266
 
237
267
  let hasWarnedDuplicate = false;
@@ -244,18 +274,27 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
244
274
  return {
245
275
  optimizeDeps: {
246
276
  exclude: excludeDeps,
247
- esbuildOptions: sharedEsbuildOptions,
277
+ rolldownOptions: sharedRolldownOptions,
248
278
  },
249
279
  build: {
250
280
  rollupOptions: { onwarn },
251
281
  },
252
282
  resolve: {
253
283
  alias: rangoAliases,
284
+ // Force a single React/React-DOM copy across all three RSC
285
+ // environments. RSC requires exactly one react/react-dom instance
286
+ // per environment runtime; consumer install topologies (pnpm
287
+ // strict layout, experimental React pins, third-party "use client"
288
+ // packages) can otherwise resolve duplicate copies, causing
289
+ // "Invalid hook call" / lost context. Child environments inherit
290
+ // this root dedupe, and Vite merges it with any consumer dedupe.
291
+ dedupe: ["react", "react-dom"],
254
292
  },
255
293
  environments: {
256
294
  client: {
257
295
  build: {
258
296
  rollupOptions: {
297
+ onwarn,
259
298
  output: {
260
299
  manualChunks: getManualChunks,
261
300
  },
@@ -267,10 +306,10 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
267
306
  "react-dom",
268
307
  "react/jsx-runtime",
269
308
  "react/jsx-dev-runtime",
270
- "rsc-html-stream/client",
309
+ nested("rsc-html-stream/client"),
271
310
  ],
272
311
  exclude: excludeDeps,
273
- esbuildOptions: sharedEsbuildOptions,
312
+ rolldownOptions: sharedRolldownOptions,
274
313
  entries: [VIRTUAL_IDS.browser],
275
314
  },
276
315
  },
@@ -284,10 +323,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
284
323
  "react-dom/static.edge",
285
324
  "react/jsx-runtime",
286
325
  "react/jsx-dev-runtime",
287
- "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
326
+ nested(
327
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
328
+ ),
288
329
  ],
289
330
  exclude: excludeDeps,
290
- esbuildOptions: sharedEsbuildOptions,
331
+ rolldownOptions: sharedRolldownOptions,
291
332
  },
292
333
  },
293
334
  rsc: {
@@ -297,9 +338,17 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
297
338
  "react",
298
339
  "react/jsx-runtime",
299
340
  "react/jsx-dev-runtime",
300
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
341
+ nested(
342
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
343
+ ),
301
344
  ],
302
- esbuildOptions: sharedEsbuildOptions,
345
+ // Vite 8 does not propagate the top-level optimizeDeps.exclude
346
+ // (set in config()) to non-client envs, so the rsc env must set
347
+ // it explicitly — mirroring the node ssr env and the cloudflare
348
+ // rsc env. Without it a strict-pnpm npm-installed app can try to
349
+ // pre-bundle the router's own subpath entries and fail.
350
+ exclude: excludeDeps,
351
+ rolldownOptions: sharedRolldownOptions,
303
352
  },
304
353
  },
305
354
  },
@@ -324,39 +373,24 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
324
373
  if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
325
374
  hasWarnedDuplicate = true;
326
375
  console.warn(
327
- "[rsc-router] Duplicate @vitejs/plugin-rsc detected. " +
376
+ "[rango] Duplicate @vitejs/plugin-rsc detected. " +
328
377
  "Remove rsc() from your vite config — rango() includes it automatically.",
329
378
  );
330
379
  }
331
380
  },
332
381
  });
333
382
 
334
- // Add virtual entries plugin (RSC entry generated lazily from routerRef)
335
383
  plugins.push(createVirtualEntriesPlugin(finalEntries, routerRef));
336
-
384
+ plugins.push(performanceTracksPlugin());
337
385
  plugins.push(
338
386
  rsc({
339
387
  entries: finalEntries,
388
+ clientChunks,
340
389
  }) as PluginOption,
341
390
  );
342
-
343
- // Deduplicate client references from third-party packages in dev mode.
344
- // Prevents module duplication when server components import "use client"
345
- // packages that are also imported directly by client components.
346
391
  plugins.push(clientRefDedup());
347
392
  }
348
393
 
349
- // Fix HMR for "use client" components.
350
- //
351
- // @vitejs/plugin-rsc's hotUpdate returns undefined for "use client" files
352
- // in the RSC environment. Vite then tries to propagate through the RSC
353
- // module graph, but the proxy module has no import.meta.hot.accept()
354
- // boundary, causing a full page reload. The client env would handle it
355
- // fine via React Refresh, but the RSC env's full-reload arrives first.
356
- //
357
- // Fix: in the RSC env, return [] for "use client" files to signal
358
- // "handled, nothing to propagate". The client env is left alone so
359
- // React Refresh processes the update normally.
360
394
  plugins.push({
361
395
  name: "@rangojs/router:client-component-hmr",
362
396
  hotUpdate(ctx) {
@@ -375,71 +409,45 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
375
409
 
376
410
  try {
377
411
  const source = readFileSync(file, "utf-8");
378
- const trimmed = source.trimStart();
379
- if (
380
- trimmed.startsWith('"use client"') ||
381
- trimmed.startsWith("'use client'")
382
- ) {
383
- // Consume the update in RSC/SSR envs. The proxy module was already
384
- // re-transformed by the RSC plugin's hotUpdate. Without this, Vite
385
- // tries to propagate through the RSC/SSR module graph where the proxy
386
- // has no import.meta.hot.accept() boundary, triggering a full reload.
387
- // The actual component update is handled by React Refresh in the
388
- // client environment.
412
+ if (hasUseClientDirective(source)) {
389
413
  return [];
390
414
  }
391
- } catch {
392
- // File deleted/moved during HMR, let default handling proceed
393
- }
415
+ } catch {}
394
416
  },
395
417
  });
396
418
 
397
419
  plugins.push(exposeActionId());
398
-
399
- // "use cache" directive transform (enforce: "post"):
400
- // Wraps exports with registerCachedFunction() for function-level caching.
401
420
  plugins.push(useCacheTransform());
402
-
403
- // Consolidated plugin for create* ID injection (enforce: "post"):
404
- // loaders, handles, location state, and prerender handlers.
405
421
  plugins.push(exposeInternalIds());
406
-
407
- // Router ID injection runs at normal priority (no enforce) to avoid
408
- // changing Vite's dep optimization timing.
409
422
  plugins.push(exposeRouterId());
410
-
411
- // Add version virtual module plugin for cache invalidation
412
423
  plugins.push(createVersionPlugin());
413
424
 
414
- // Entry path for discovery: user-specified value (if any) or undefined.
415
- // Auto-discovered path is passed separately via routerRef.
416
- // Cloudflare preset: deferred to configResolved (read from resolved Vite env config).
417
425
  const discoveryEntryPath =
418
426
  preset !== "cloudflare" ? routerRef.path : undefined;
419
- // Ref for deferred auto-discovery (node preset only, undefined for cloudflare)
420
427
  const discoveryRouterRef = preset !== "cloudflare" ? routerRef : undefined;
421
428
 
422
- // Version injector: auto-injects VERSION and routes-manifest into the RSC entry.
423
- // For cloudflare preset, the entry is resolved lazily in configResolved.
424
- // For node preset, the virtual entry already includes these imports.
425
429
  if (preset === "cloudflare") {
426
430
  plugins.push(createVersionInjectorPlugin(undefined));
427
431
  }
428
432
 
429
- // Transform CJS vendor files to ESM for browser compatibility
430
- // optimizeDeps.include doesn't work because the file is loaded after initial optimization
431
433
  plugins.push(createCjsToEsmPlugin());
432
-
433
- // Router discovery plugin for build-time manifest generation.
434
- // For cloudflare, the entry is resolved lazily in configResolved from the RSC environment.
435
- // For node, discoveryRouterRef provides the auto-discovered path when not user-specified.
436
434
  plugins.push(
437
435
  createRouterDiscoveryPlugin(discoveryEntryPath, {
438
436
  routerPathRef: discoveryRouterRef,
439
437
  enableBuildPrerender: prerenderEnabled,
440
- staticRouteTypesGeneration: resolvedOptions.staticRouteTypesGeneration,
438
+ buildEnv: options?.buildEnv,
439
+ preset,
440
+ prerenderOnError: options?.prerender?.onError,
441
+ discovery: options?.discovery,
442
+ clientChunkCtx,
441
443
  }),
442
444
  );
443
445
 
446
+ debugConfig?.(
447
+ "rango(%s) setup done: %d plugin(s) (%sms)",
448
+ preset,
449
+ plugins.length,
450
+ (performance.now() - rangoStart).toFixed(1),
451
+ );
444
452
  return plugins;
445
453
  }