@rangojs/router 0.0.0-experimental.d7eeaa75 → 0.0.0-experimental.dc2bd2b4

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 (253) hide show
  1. package/README.md +120 -25
  2. package/dist/bin/rango.js +147 -57
  3. package/dist/testing/vitest.js +48 -0
  4. package/dist/vite/index.js +2151 -846
  5. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  6. package/package.json +57 -11
  7. package/skills/breadcrumbs/SKILL.md +3 -1
  8. package/skills/bundle-analysis/SKILL.md +159 -0
  9. package/skills/cache-guide/SKILL.md +220 -30
  10. package/skills/caching/SKILL.md +116 -8
  11. package/skills/composability/SKILL.md +27 -2
  12. package/skills/document-cache/SKILL.md +78 -55
  13. package/skills/handler-use/SKILL.md +364 -0
  14. package/skills/hooks/SKILL.md +229 -20
  15. package/skills/host-router/SKILL.md +45 -20
  16. package/skills/i18n/SKILL.md +276 -0
  17. package/skills/intercept/SKILL.md +46 -4
  18. package/skills/layout/SKILL.md +28 -7
  19. package/skills/links/SKILL.md +247 -17
  20. package/skills/loader/SKILL.md +219 -9
  21. package/skills/middleware/SKILL.md +47 -12
  22. package/skills/migrate-nextjs/SKILL.md +562 -0
  23. package/skills/migrate-react-router/SKILL.md +769 -0
  24. package/skills/mime-routes/SKILL.md +27 -0
  25. package/skills/observability/SKILL.md +137 -0
  26. package/skills/parallel/SKILL.md +71 -6
  27. package/skills/prerender/SKILL.md +14 -33
  28. package/skills/rango/SKILL.md +242 -22
  29. package/skills/react-compiler/SKILL.md +168 -0
  30. package/skills/response-routes/SKILL.md +66 -9
  31. package/skills/route/SKILL.md +57 -4
  32. package/skills/router-setup/SKILL.md +3 -3
  33. package/skills/server-actions/SKILL.md +751 -0
  34. package/skills/streams-and-websockets/SKILL.md +283 -0
  35. package/skills/testing/SKILL.md +647 -0
  36. package/skills/typesafety/SKILL.md +319 -27
  37. package/skills/use-cache/SKILL.md +34 -5
  38. package/skills/view-transitions/SKILL.md +294 -0
  39. package/src/__augment-tests__/augment.ts +81 -0
  40. package/src/__augment-tests__/augmented.check.ts +117 -0
  41. package/src/browser/action-coordinator.ts +53 -36
  42. package/src/browser/app-shell.ts +52 -0
  43. package/src/browser/event-controller.ts +86 -70
  44. package/src/browser/history-state.ts +21 -0
  45. package/src/browser/index.ts +3 -3
  46. package/src/browser/navigation-bridge.ts +84 -11
  47. package/src/browser/navigation-client.ts +76 -28
  48. package/src/browser/navigation-store.ts +32 -9
  49. package/src/browser/navigation-transaction.ts +10 -28
  50. package/src/browser/partial-update.ts +64 -26
  51. package/src/browser/prefetch/cache.ts +129 -21
  52. package/src/browser/prefetch/fetch.ts +148 -16
  53. package/src/browser/prefetch/queue.ts +36 -5
  54. package/src/browser/rango-state.ts +53 -13
  55. package/src/browser/react/Link.tsx +30 -2
  56. package/src/browser/react/NavigationProvider.tsx +72 -31
  57. package/src/browser/react/filter-segment-order.ts +51 -7
  58. package/src/browser/react/index.ts +3 -0
  59. package/src/browser/react/location-state-shared.ts +175 -4
  60. package/src/browser/react/location-state.ts +39 -13
  61. package/src/browser/react/use-handle.ts +17 -9
  62. package/src/browser/react/use-navigation.ts +22 -2
  63. package/src/browser/react/use-params.ts +20 -8
  64. package/src/browser/react/use-reverse.ts +106 -0
  65. package/src/browser/react/use-router.ts +22 -2
  66. package/src/browser/react/use-segments.ts +11 -8
  67. package/src/browser/response-adapter.ts +25 -0
  68. package/src/browser/rsc-router.tsx +64 -22
  69. package/src/browser/scroll-restoration.ts +22 -14
  70. package/src/browser/segment-reconciler.ts +36 -14
  71. package/src/browser/segment-structure-assert.ts +2 -2
  72. package/src/browser/server-action-bridge.ts +23 -30
  73. package/src/browser/types.ts +21 -0
  74. package/src/build/collect-fallback-refs.ts +107 -0
  75. package/src/build/generate-manifest.ts +60 -35
  76. package/src/build/generate-route-types.ts +2 -0
  77. package/src/build/index.ts +2 -0
  78. package/src/build/route-trie.ts +52 -25
  79. package/src/build/route-types/codegen.ts +4 -4
  80. package/src/build/route-types/include-resolution.ts +1 -1
  81. package/src/build/route-types/per-module-writer.ts +7 -4
  82. package/src/build/route-types/router-processing.ts +55 -14
  83. package/src/build/route-types/scan-filter.ts +1 -1
  84. package/src/build/route-types/source-scan.ts +118 -0
  85. package/src/build/runtime-discovery.ts +9 -20
  86. package/src/cache/cache-scope.ts +28 -42
  87. package/src/cache/cf/cf-cache-store.ts +54 -13
  88. package/src/client.rsc.tsx +3 -0
  89. package/src/client.tsx +92 -182
  90. package/src/context-var.ts +5 -5
  91. package/src/decode-loader-results.ts +36 -0
  92. package/src/errors.ts +30 -1
  93. package/src/handle.ts +26 -13
  94. package/src/host/index.ts +2 -2
  95. package/src/host/router.ts +129 -57
  96. package/src/host/types.ts +31 -2
  97. package/src/host/utils.ts +1 -1
  98. package/src/href-client.ts +140 -20
  99. package/src/index.rsc.ts +9 -4
  100. package/src/index.ts +53 -15
  101. package/src/loader-store.ts +500 -0
  102. package/src/loader.rsc.ts +2 -5
  103. package/src/loader.ts +3 -10
  104. package/src/missing-id-error.ts +68 -0
  105. package/src/outlet-context.ts +1 -1
  106. package/src/prerender.ts +4 -4
  107. package/src/response-utils.ts +37 -0
  108. package/src/reverse.ts +65 -36
  109. package/src/route-content-wrapper.tsx +6 -28
  110. package/src/route-definition/dsl-helpers.ts +384 -257
  111. package/src/route-definition/helper-factories.ts +29 -139
  112. package/src/route-definition/helpers-types.ts +100 -28
  113. package/src/route-definition/resolve-handler-use.ts +6 -0
  114. package/src/route-definition/use-item-types.ts +32 -0
  115. package/src/route-types.ts +26 -41
  116. package/src/router/basename.ts +14 -0
  117. package/src/router/content-negotiation.ts +15 -2
  118. package/src/router/error-handling.ts +1 -1
  119. package/src/router/handler-context.ts +21 -38
  120. package/src/router/intercept-resolution.ts +4 -18
  121. package/src/router/lazy-includes.ts +8 -8
  122. package/src/router/loader-resolution.ts +19 -2
  123. package/src/router/manifest.ts +22 -13
  124. package/src/router/match-api.ts +4 -3
  125. package/src/router/match-handlers.ts +63 -20
  126. package/src/router/match-middleware/cache-lookup.ts +44 -91
  127. package/src/router/match-middleware/cache-store.ts +3 -2
  128. package/src/router/match-result.ts +53 -32
  129. package/src/router/metrics.ts +1 -1
  130. package/src/router/middleware-types.ts +15 -26
  131. package/src/router/middleware.ts +99 -84
  132. package/src/router/pattern-matching.ts +101 -17
  133. package/src/router/prerender-match.ts +1 -1
  134. package/src/router/preview-match.ts +3 -1
  135. package/src/router/request-classification.ts +4 -28
  136. package/src/router/revalidation.ts +58 -2
  137. package/src/router/router-interfaces.ts +45 -28
  138. package/src/router/router-options.ts +40 -1
  139. package/src/router/router-registry.ts +2 -5
  140. package/src/router/segment-resolution/fresh.ts +27 -6
  141. package/src/router/segment-resolution/revalidation.ts +147 -106
  142. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  143. package/src/router/substitute-pattern-params.ts +56 -0
  144. package/src/router/telemetry.ts +99 -0
  145. package/src/router/trie-matching.ts +18 -13
  146. package/src/router/types.ts +8 -0
  147. package/src/router/url-params.ts +49 -0
  148. package/src/router.ts +38 -23
  149. package/src/rsc/handler-context.ts +2 -2
  150. package/src/rsc/handler.ts +28 -69
  151. package/src/rsc/helpers.ts +91 -43
  152. package/src/rsc/index.ts +1 -1
  153. package/src/rsc/origin-guard.ts +28 -10
  154. package/src/rsc/progressive-enhancement.ts +4 -0
  155. package/src/rsc/response-route-handler.ts +46 -53
  156. package/src/rsc/rsc-rendering.ts +35 -51
  157. package/src/rsc/runtime-warnings.ts +9 -10
  158. package/src/rsc/server-action.ts +17 -37
  159. package/src/rsc/ssr-setup.ts +16 -0
  160. package/src/rsc/types.ts +8 -2
  161. package/src/search-params.ts +4 -4
  162. package/src/segment-content-promise.ts +67 -0
  163. package/src/segment-loader-promise.ts +122 -0
  164. package/src/segment-system.tsx +132 -116
  165. package/src/serialize.ts +243 -0
  166. package/src/server/context.ts +143 -53
  167. package/src/server/cookie-store.ts +28 -4
  168. package/src/server/request-context.ts +20 -42
  169. package/src/ssr/index.tsx +5 -1
  170. package/src/static-handler.ts +1 -1
  171. package/src/testing/cache-status.ts +166 -0
  172. package/src/testing/collect-handle.ts +63 -0
  173. package/src/testing/dispatch.ts +440 -0
  174. package/src/testing/dom.entry.ts +22 -0
  175. package/src/testing/e2e/fixture.ts +154 -0
  176. package/src/testing/e2e/index.ts +149 -0
  177. package/src/testing/e2e/matchers.ts +51 -0
  178. package/src/testing/e2e/page-helpers.ts +272 -0
  179. package/src/testing/e2e/parity.ts +306 -0
  180. package/src/testing/e2e/server.ts +183 -0
  181. package/src/testing/flight-matchers.ts +104 -0
  182. package/src/testing/flight-runtime.d.ts +21 -0
  183. package/src/testing/flight.entry.ts +22 -0
  184. package/src/testing/flight.ts +182 -0
  185. package/src/testing/generated-routes.ts +223 -0
  186. package/src/testing/index.ts +105 -0
  187. package/src/testing/internal/context.ts +193 -0
  188. package/src/testing/render-route.tsx +536 -0
  189. package/src/testing/run-loader.ts +296 -0
  190. package/src/testing/run-middleware.ts +170 -0
  191. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  192. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  193. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  194. package/src/testing/vitest-stubs/version.ts +5 -0
  195. package/src/testing/vitest.ts +183 -0
  196. package/src/types/global-namespace.ts +39 -26
  197. package/src/types/handler-context.ts +68 -50
  198. package/src/types/index.ts +1 -0
  199. package/src/types/loader-types.ts +5 -6
  200. package/src/types/request-scope.ts +126 -0
  201. package/src/types/route-entry.ts +11 -0
  202. package/src/types/segments.ts +35 -2
  203. package/src/urls/include-helper.ts +34 -67
  204. package/src/urls/index.ts +0 -3
  205. package/src/urls/path-helper-types.ts +41 -7
  206. package/src/urls/path-helper.ts +17 -52
  207. package/src/urls/pattern-types.ts +36 -19
  208. package/src/urls/response-types.ts +22 -29
  209. package/src/urls/type-extraction.ts +26 -116
  210. package/src/urls/urls-function.ts +1 -5
  211. package/src/use-loader.tsx +413 -42
  212. package/src/vite/debug.ts +185 -0
  213. package/src/vite/discovery/bundle-postprocess.ts +6 -6
  214. package/src/vite/discovery/discover-routers.ts +101 -51
  215. package/src/vite/discovery/discovery-errors.ts +194 -0
  216. package/src/vite/discovery/gate-state.ts +171 -0
  217. package/src/vite/discovery/prerender-collection.ts +67 -26
  218. package/src/vite/discovery/route-types-writer.ts +40 -84
  219. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  220. package/src/vite/discovery/state.ts +33 -0
  221. package/src/vite/discovery/virtual-module-codegen.ts +13 -23
  222. package/src/vite/index.ts +2 -0
  223. package/src/vite/plugin-types.ts +67 -0
  224. package/src/vite/plugins/cjs-to-esm.ts +8 -7
  225. package/src/vite/plugins/client-ref-dedup.ts +16 -0
  226. package/src/vite/plugins/client-ref-hashing.ts +28 -5
  227. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  228. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  229. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  230. package/src/vite/plugins/expose-action-id.ts +54 -30
  231. package/src/vite/plugins/expose-id-utils.ts +12 -8
  232. package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
  233. package/src/vite/plugins/expose-ids/handler-transform.ts +8 -61
  234. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  235. package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
  236. package/src/vite/plugins/expose-internal-ids.ts +496 -486
  237. package/src/vite/plugins/performance-tracks.ts +29 -25
  238. package/src/vite/plugins/use-cache-transform.ts +65 -50
  239. package/src/vite/plugins/version-injector.ts +39 -23
  240. package/src/vite/plugins/version-plugin.ts +59 -2
  241. package/src/vite/plugins/virtual-entries.ts +2 -2
  242. package/src/vite/rango.ts +116 -29
  243. package/src/vite/router-discovery.ts +750 -100
  244. package/src/vite/utils/ast-handler-extract.ts +15 -15
  245. package/src/vite/utils/banner.ts +1 -1
  246. package/src/vite/utils/bundle-analysis.ts +4 -2
  247. package/src/vite/utils/client-chunks.ts +190 -0
  248. package/src/vite/utils/forward-user-plugins.ts +193 -0
  249. package/src/vite/utils/manifest-utils.ts +21 -5
  250. package/src/vite/utils/package-resolution.ts +41 -1
  251. package/src/vite/utils/prerender-utils.ts +21 -6
  252. package/src/vite/utils/shared-utils.ts +107 -26
  253. package/src/browser/action-response-classifier.ts +0 -99
package/src/vite/rango.ts CHANGED
@@ -12,21 +12,30 @@ 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);
30
39
 
31
40
  /**
32
41
  * Vite plugin for @rangojs/router.
@@ -53,25 +62,58 @@ import { performanceTracksPlugin } from "./plugins/performance-tracks.js";
53
62
  * ```
54
63
  */
55
64
  export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
65
+ const rangoStart = performance.now();
56
66
  const resolvedOptions: RangoOptions = options ?? { preset: "node" };
57
67
  const preset = resolvedOptions.preset ?? "node";
58
68
  const showBanner = resolvedOptions.banner ?? true;
69
+ // Client-chunking strategy (per-route/per-feature splitting of the browser
70
+ // bundle). Defaults to the built-in directory strategy (`true`) pre-1.0; pass
71
+ // `clientChunks: false` to opt out. Resolved once and forwarded to
72
+ // @vitejs/plugin-rsc in both presets. The built-in strategy only splits where it
73
+ // recognizes a route structure, so this default is a no-op for flat / host-split
74
+ // apps and never duplicates the shared runtime.
75
+ const clientChunksOption = resolvedOptions.clientChunks ?? true;
76
+ // Shared context the built-in strategy reads at build time: the production
77
+ // hashes of registered error/notFound fallback modules (-> app-fallback).
78
+ // Populated by the discovery plugin in buildStart, before the client build
79
+ // invokes the strategy. Only wired when the built-in strategy is active; a
80
+ // custom function owns its own grouping.
81
+ const useBuiltInClientChunks = clientChunksOption === true;
82
+ const clientChunkCtx: ClientChunkContext | undefined = useBuiltInClientChunks
83
+ ? { fallbackRefs: new Set<string>() }
84
+ : undefined;
85
+ const clientChunks = resolveClientChunks(clientChunksOption, clientChunkCtx);
86
+ debugConfig?.("rango(%s) setup start", preset);
59
87
 
60
88
  const plugins: PluginOption[] = [];
61
89
 
62
- // Get package resolution info (workspace vs npm install)
63
- const rangoAliases = getPackageAliases();
90
+ // Get package resolution info (workspace vs npm install).
91
+ // Vendor aliases redirect the bare plugin-rsc vendor specs (which plugin-rsc
92
+ // itself injects into optimizeDeps.include) to absolute paths resolved from
93
+ // this package — so strict-pnpm consumers don't hit "Failed to resolve
94
+ // dependency" warnings when those deps aren't hoisted to their app root.
95
+ const rangoAliases = { ...getPackageAliases(), ...getVendorAliases() };
64
96
  const excludeDeps = [
65
97
  ...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.
98
+ // plugin-rsc itself injects these into the client env's
99
+ // optimizeDeps.include, which overrides exclude for the dep's own
100
+ // pre-bundle entry. What exclude still controls is how *other*
101
+ // pre-bundled deps treat imports of these specs (external vs inlined)
102
+ // via esbuildCjsExternalPlugin. The cjs-to-esm transform in
103
+ // plugins/cjs-to-esm.ts is the fallback for strict-pnpm consumers,
104
+ // where client.browser's bare include fails to resolve and Vite ends up
105
+ // serving the raw CJS file at dev-serve time.
69
106
  "@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
107
  "@vitejs/plugin-rsc/vendor/react-server-dom/client.browser",
73
108
  ];
74
109
 
110
+ // Vite supports a nested `A > B` syntax in optimizeDeps.include that resolves
111
+ // B from A's location. We anchor transitive deps (rsc-html-stream,
112
+ // @vitejs/plugin-rsc/vendor/*) to @rangojs/router so pnpm consumers — where
113
+ // these aren't visible at the app root — can still pre-bundle them.
114
+ const pkg = getPublishedPackageName();
115
+ const nested = (spec: string) => `${pkg} > ${spec}`;
116
+
75
117
  // Mutable ref for router path (node preset only).
76
118
  // Set immediately when user-specified, or populated by the auto-discover
77
119
  // config() hook using Vite's resolved root.
@@ -106,10 +148,18 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
106
148
  // This ensures the same Context instance is used by both browser entry and RSC proxy modules
107
149
  optimizeDeps: {
108
150
  exclude: excludeDeps,
109
- esbuildOptions: sharedEsbuildOptions,
151
+ rolldownOptions: sharedRolldownOptions,
110
152
  },
111
153
  resolve: {
112
154
  alias: rangoAliases,
155
+ // Force a single React/React-DOM copy across all three RSC
156
+ // environments. RSC requires exactly one react/react-dom instance
157
+ // per environment runtime; consumer install topologies (pnpm
158
+ // strict layout, experimental React pins, third-party "use client"
159
+ // packages) can otherwise resolve duplicate copies, causing
160
+ // "Invalid hook call" / lost context. Child environments inherit
161
+ // this root dedupe, and Vite merges it with any consumer dedupe.
162
+ dedupe: ["react", "react-dom"],
113
163
  },
114
164
  build: {
115
165
  rollupOptions: { onwarn },
@@ -118,6 +168,14 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
118
168
  client: {
119
169
  build: {
120
170
  rollupOptions: {
171
+ // FILE_NAME_CONFLICT (and any other client-build warning) is
172
+ // emitted by the CLIENT environment build, which consults THIS
173
+ // env's onwarn -- Vite 8's environment builds do NOT propagate
174
+ // the top-level build.rollupOptions.onwarn into the client env.
175
+ // Wire it here so the suppression runs where the conflicts
176
+ // originate (the top-level handler is invoked 0x for these; the
177
+ // client-env handler is invoked for all of them).
178
+ onwarn,
121
179
  output: {
122
180
  manualChunks: getManualChunks,
123
181
  },
@@ -126,9 +184,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
126
184
  // Pre-bundle rsc-html-stream to prevent discovery during first request
127
185
  // Exclude rsc-router modules to ensure same Context instance
128
186
  optimizeDeps: {
129
- include: ["rsc-html-stream/client"],
187
+ include: [nested("rsc-html-stream/client")],
130
188
  exclude: excludeDeps,
131
- esbuildOptions: sharedEsbuildOptions,
189
+ rolldownOptions: sharedRolldownOptions,
132
190
  },
133
191
  },
134
192
  ssr: {
@@ -136,10 +194,6 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
136
194
  build: {
137
195
  outDir: "./dist/rsc/ssr",
138
196
  },
139
- resolve: {
140
- // Ensure single React instance in SSR child environment
141
- dedupe: ["react", "react-dom"],
142
- },
143
197
  // Pre-bundle SSR entry and React for proper module linking with childEnvironments
144
198
  // All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
145
199
  optimizeDeps: {
@@ -151,11 +205,13 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
151
205
  "react-dom/static.edge",
152
206
  "react/jsx-runtime",
153
207
  "react/jsx-dev-runtime",
154
- "rsc-html-stream/server",
155
- "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
208
+ nested("rsc-html-stream/server"),
209
+ nested(
210
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
211
+ ),
156
212
  ],
157
213
  exclude: excludeDeps,
158
- esbuildOptions: sharedEsbuildOptions,
214
+ rolldownOptions: sharedRolldownOptions,
159
215
  },
160
216
  },
161
217
  rsc: {
@@ -167,10 +223,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
167
223
  "react",
168
224
  "react/jsx-runtime",
169
225
  "react/jsx-dev-runtime",
170
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
226
+ nested(
227
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
228
+ ),
171
229
  ],
172
230
  exclude: excludeDeps,
173
- esbuildOptions: sharedEsbuildOptions,
231
+ rolldownOptions: sharedRolldownOptions,
174
232
  },
175
233
  },
176
234
  },
@@ -202,6 +260,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
202
260
  rsc({
203
261
  entries: finalEntries,
204
262
  serverHandler: false,
263
+ clientChunks,
205
264
  }) as PluginOption,
206
265
  );
207
266
 
@@ -231,7 +290,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
231
290
  " - " + (f.startsWith(root) ? f.slice(root.length + 1) : f),
232
291
  )
233
292
  .join("\n");
234
- throw new Error(`[rsc-router] Multiple routers found:\n${list}`);
293
+ throw new Error(`[rango] Multiple routers found:\n${list}`);
235
294
  }
236
295
  // 0 found: routerRef.path stays undefined, warn at startup via discovery plugin
237
296
  },
@@ -257,18 +316,34 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
257
316
  return {
258
317
  optimizeDeps: {
259
318
  exclude: excludeDeps,
260
- esbuildOptions: sharedEsbuildOptions,
319
+ rolldownOptions: sharedRolldownOptions,
261
320
  },
262
321
  build: {
263
322
  rollupOptions: { onwarn },
264
323
  },
265
324
  resolve: {
266
325
  alias: rangoAliases,
326
+ // Force a single React/React-DOM copy across all three RSC
327
+ // environments. RSC requires exactly one react/react-dom instance
328
+ // per environment runtime; consumer install topologies (pnpm
329
+ // strict layout, experimental React pins, third-party "use client"
330
+ // packages) can otherwise resolve duplicate copies, causing
331
+ // "Invalid hook call" / lost context. Child environments inherit
332
+ // this root dedupe, and Vite merges it with any consumer dedupe.
333
+ dedupe: ["react", "react-dom"],
267
334
  },
268
335
  environments: {
269
336
  client: {
270
337
  build: {
271
338
  rollupOptions: {
339
+ // FILE_NAME_CONFLICT (and any other client-build warning) is
340
+ // emitted by the CLIENT environment build, which consults THIS
341
+ // env's onwarn -- Vite 8's environment builds do NOT propagate
342
+ // the top-level build.rollupOptions.onwarn into the client env.
343
+ // Wire it here so the suppression runs where the conflicts
344
+ // originate (the top-level handler is invoked 0x for these; the
345
+ // client-env handler is invoked for all of them).
346
+ onwarn,
272
347
  output: {
273
348
  manualChunks: getManualChunks,
274
349
  },
@@ -280,10 +355,10 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
280
355
  "react-dom",
281
356
  "react/jsx-runtime",
282
357
  "react/jsx-dev-runtime",
283
- "rsc-html-stream/client",
358
+ nested("rsc-html-stream/client"),
284
359
  ],
285
360
  exclude: excludeDeps,
286
- esbuildOptions: sharedEsbuildOptions,
361
+ rolldownOptions: sharedRolldownOptions,
287
362
  entries: [VIRTUAL_IDS.browser],
288
363
  },
289
364
  },
@@ -297,10 +372,12 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
297
372
  "react-dom/static.edge",
298
373
  "react/jsx-runtime",
299
374
  "react/jsx-dev-runtime",
300
- "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
375
+ nested(
376
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
377
+ ),
301
378
  ],
302
379
  exclude: excludeDeps,
303
- esbuildOptions: sharedEsbuildOptions,
380
+ rolldownOptions: sharedRolldownOptions,
304
381
  },
305
382
  },
306
383
  rsc: {
@@ -310,9 +387,11 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
310
387
  "react",
311
388
  "react/jsx-runtime",
312
389
  "react/jsx-dev-runtime",
313
- "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
390
+ nested(
391
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
392
+ ),
314
393
  ],
315
- esbuildOptions: sharedEsbuildOptions,
394
+ rolldownOptions: sharedRolldownOptions,
316
395
  },
317
396
  },
318
397
  },
@@ -337,7 +416,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
337
416
  if (rscMinimalCount > 1 && !hasWarnedDuplicate) {
338
417
  hasWarnedDuplicate = true;
339
418
  console.warn(
340
- "[rsc-router] Duplicate @vitejs/plugin-rsc detected. " +
419
+ "[rango] Duplicate @vitejs/plugin-rsc detected. " +
341
420
  "Remove rsc() from your vite config — rango() includes it automatically.",
342
421
  );
343
422
  }
@@ -353,6 +432,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
353
432
  plugins.push(
354
433
  rsc({
355
434
  entries: finalEntries,
435
+ clientChunks,
356
436
  }) as PluginOption,
357
437
  );
358
438
 
@@ -455,8 +535,15 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
455
535
  enableBuildPrerender: prerenderEnabled,
456
536
  buildEnv: options?.buildEnv,
457
537
  preset,
538
+ clientChunkCtx,
458
539
  }),
459
540
  );
460
541
 
542
+ debugConfig?.(
543
+ "rango(%s) setup done: %d plugin(s) (%sms)",
544
+ preset,
545
+ plugins.length,
546
+ (performance.now() - rangoStart).toFixed(1),
547
+ );
461
548
  return plugins;
462
549
  }