@rangojs/router 0.0.0-experimental.eb0645d3 → 0.0.0-experimental.f1468e3c

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