@rangojs/router 0.0.0-experimental.9c9afef3 → 0.0.0-experimental.a014d2b7

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