@rangojs/router 0.0.0-experimental.19 → 0.0.0-experimental.1c0bdfad

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