@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
@@ -14,6 +14,9 @@
14
14
 
15
15
  import type { Plugin } from "vite";
16
16
  import { readFile } from "node:fs/promises";
17
+ import { createRangoDebugger, createCounter, NS } from "../debug.js";
18
+
19
+ const debug = createRangoDebugger(NS.transform);
17
20
 
18
21
  const RSDW_PATCH_RE =
19
22
  /((?:var|let|const)\s+\w+\s*=\s*root\._children\s*,\s*(\w+)\s*=\s*root\._debugInfo\s*[;,])/;
@@ -45,44 +48,42 @@ export function patchRsdwClientDebugInfoRecovery(code: string): {
45
48
 
46
49
  export function performanceTracksOptimizeDepsPlugin(): {
47
50
  name: string;
48
- setup(build: any): void;
51
+ load(id: string): Promise<{ code: string } | null>;
49
52
  } {
53
+ const RSDW_CLIENT_RE =
54
+ /react-server-dom-webpack-client\.browser\.(development|production)\.js$/;
50
55
  return {
51
56
  name: "@rangojs/router:performance-tracks-optimize-deps",
52
- setup(build: any): void {
53
- build.onLoad(
54
- {
55
- filter:
56
- /react-server-dom-webpack-client\.browser\.(development|production)\.js$/,
57
- },
58
- async (args: { path: string }) => {
59
- const code = await readFile(args.path, "utf8");
60
- const patched = patchRsdwClientDebugInfoRecovery(code);
61
- return {
62
- contents: patched.code,
63
- loader: "js",
64
- };
65
- },
66
- );
57
+ async load(id: string): Promise<{ code: string } | null> {
58
+ const cleanId = id.split("?")[0] ?? id;
59
+ if (!RSDW_CLIENT_RE.test(cleanId)) return null;
60
+ const code = await readFile(cleanId, "utf8");
61
+ const patched = patchRsdwClientDebugInfoRecovery(code);
62
+ return { code: patched.code };
67
63
  },
68
64
  };
69
65
  }
70
66
 
71
67
  export function performanceTracksPlugin(): Plugin {
68
+ const counter = createCounter(debug, "performance-tracks");
72
69
  return {
73
70
  name: "@rangojs/router:performance-tracks",
74
71
 
72
+ buildEnd() {
73
+ counter?.flush();
74
+ },
75
+
75
76
  transform(code, id) {
76
77
  if (!id.includes("react-server-dom") || !id.includes("client")) return;
77
- const patched = patchRsdwClientDebugInfoRecovery(code);
78
- if (!patched.debugInfoVar) return;
79
- if (process.env.INTERNAL_RANGO_DEBUG)
80
- console.log(
81
- "[perf-tracks] patched RSDW client (var:",
82
- patched.debugInfoVar,
83
- ")",
84
- );
85
- return patched.code;
78
+ const start = counter ? performance.now() : 0;
79
+ try {
80
+ const patched = patchRsdwClientDebugInfoRecovery(code);
81
+ if (!patched.debugInfoVar) return;
82
+ debug?.("patched RSDW client (var: %s)", patched.debugInfoVar);
83
+ return patched.code;
84
+ } finally {
85
+ counter?.record(id, performance.now() - start);
86
+ }
86
87
  },
87
88
  };
88
89
  }
@@ -20,7 +20,7 @@ import type { Plugin } from "vite";
20
20
  */
21
21
  export function poke(): Plugin {
22
22
  return {
23
- name: "vite-plugin-poke",
23
+ name: "@rangojs/router:poke",
24
24
  apply: "serve",
25
25
 
26
26
  configureServer(server) {
@@ -20,6 +20,9 @@ import type { Plugin } from "vite";
20
20
  import path from "node:path";
21
21
  import MagicString from "magic-string";
22
22
  import { normalizePath, hashId } from "./expose-id-utils.js";
23
+ import { createRangoDebugger, createCounter, NS } from "../debug.js";
24
+
25
+ const debug = createRangoDebugger(NS.transform);
23
26
 
24
27
  const CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
25
28
 
@@ -27,11 +30,14 @@ const CACHE_RUNTIME_IMPORT = "@rangojs/router/cache-runtime";
27
30
  // and should not be wrapped (children can't be cache-keyed).
28
31
  const LAYOUT_TEMPLATE_PATTERN = /\/(layout|template)\.(tsx?|jsx?)$/;
29
32
 
33
+ export const USE_CACHE_DIRECTIVE_RE: RegExp = /^use cache(:\s*[\w-]+)?$/;
34
+
30
35
  export function useCacheTransform(): Plugin {
31
36
  let projectRoot = "";
32
37
  let isBuild = false;
33
38
  let rscTransforms: typeof import("@vitejs/plugin-rsc/transforms") | null =
34
39
  null;
40
+ const counter = createCounter(debug, "use-cache");
35
41
 
36
42
  return {
37
43
  name: "@rangojs/router:use-cache",
@@ -42,6 +48,10 @@ export function useCacheTransform(): Plugin {
42
48
  isBuild = config.command === "build";
43
49
  },
44
50
 
51
+ buildEnd() {
52
+ counter?.flush();
53
+ },
54
+
45
55
  async transform(code, id) {
46
56
  // Only process in RSC environment
47
57
  if (this.environment?.name !== "rsc") return;
@@ -55,63 +65,60 @@ export function useCacheTransform(): Plugin {
55
65
  // Only JS/TS files
56
66
  if (!/\.(tsx?|jsx?|mjs)$/.test(id)) return;
57
67
 
58
- // Lazy-load transform helpers
59
- if (!rscTransforms) {
68
+ const start = counter ? performance.now() : 0;
69
+ try {
70
+ if (!rscTransforms) {
71
+ try {
72
+ rscTransforms = await import("@vitejs/plugin-rsc/transforms");
73
+ } catch {
74
+ return;
75
+ }
76
+ }
77
+
78
+ const {
79
+ hasDirective,
80
+ transformWrapExport,
81
+ transformHoistInlineDirective,
82
+ } = rscTransforms;
83
+
84
+ let ast: any;
60
85
  try {
61
- rscTransforms = await import("@vitejs/plugin-rsc/transforms");
86
+ const { parseAst } = await import("vite");
87
+ ast = parseAst(code, { lang: "tsx" });
62
88
  } catch {
63
89
  return;
64
90
  }
65
- }
66
91
 
67
- const {
68
- hasDirective,
69
- transformWrapExport,
70
- transformHoistInlineDirective,
71
- } = rscTransforms;
72
-
73
- // Parse AST
74
- let ast: any;
75
- try {
76
- const { parseAst } = await import("vite");
77
- ast = parseAst(code);
78
- } catch {
79
- return;
80
- }
81
-
82
- const filePath = normalizePath(path.relative(projectRoot, id));
83
- const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
92
+ const filePath = normalizePath(path.relative(projectRoot, id));
93
+ const isLayoutOrTemplate = LAYOUT_TEMPLATE_PATTERN.test(id);
94
+
95
+ if (hasDirective(ast.body, "use cache")) {
96
+ return transformFileLevelUseCache(
97
+ code,
98
+ ast,
99
+ filePath,
100
+ id,
101
+ isBuild,
102
+ isLayoutOrTemplate,
103
+ transformWrapExport,
104
+ );
105
+ }
84
106
 
85
- // Check for file-level "use cache"
86
- if (hasDirective(ast.body, "use cache")) {
87
- return transformFileLevelUseCache(
107
+ const functionResult = transformFunctionLevelUseCache(
88
108
  code,
89
109
  ast,
90
110
  filePath,
91
111
  id,
92
112
  isBuild,
93
- isLayoutOrTemplate,
94
- transformWrapExport,
113
+ transformHoistInlineDirective,
95
114
  );
96
- }
97
-
98
- // Check for function-level "use cache" / "use cache: profileName"
99
- // (only if there's no file-level directive but code still contains the string)
100
- const functionResult = transformFunctionLevelUseCache(
101
- code,
102
- ast,
103
- filePath,
104
- id,
105
- isBuild,
106
- transformHoistInlineDirective,
107
- );
108
115
 
109
- // Always check for near-miss directives, even when valid directives
110
- // exist. A file may contain both valid and invalid "use cache" directives
111
- // in different functions — the invalid ones should still warn.
112
- warnOnNearMissDirectives(ast, id, this.warn.bind(this));
116
+ warnOnNearMissDirectives(ast, id, this.warn.bind(this));
113
117
 
114
- if (functionResult) return functionResult;
118
+ if (functionResult) return functionResult;
119
+ } finally {
120
+ counter?.record(id, performance.now() - start);
121
+ }
115
122
  },
116
123
  };
117
124
  }
@@ -125,8 +132,7 @@ function transformFileLevelUseCache(
125
132
  isLayoutOrTemplate: boolean,
126
133
  transformWrapExport: (typeof import("@vitejs/plugin-rsc/transforms"))["transformWrapExport"],
127
134
  ) {
128
- // Collect non-function exports to report after wrapping
129
- const nonFunctionExports: string[] = [];
135
+ const unconfirmedExports: string[] = [];
130
136
 
131
137
  const { exportNames, output } = transformWrapExport(code, ast, {
132
138
  runtime: (value: string, name: string) => {
@@ -135,30 +141,38 @@ function transformFileLevelUseCache(
135
141
  },
136
142
  rejectNonAsyncFunction: false,
137
143
  filter: (name: string, meta: { isFunction?: boolean }) => {
138
- // Skip default export of layout/template files (they receive children)
139
144
  if (name === "default" && isLayoutOrTemplate) return false;
140
- // Non-function exports cannot be wrapped with registerCachedFunction
141
- if (meta.isFunction === false) {
142
- nonFunctionExports.push(name);
145
+ // isFunction is boolean | undefined: true = confirmed function, false =
146
+ // confirmed non-function, undefined = cannot tell statically (e.g. a
147
+ // factory/HOF initializer `const x = makeCached(fn)`). Deliberate policy:
148
+ // require a confirmed function and reject everything else, including
149
+ // indeterminate initializers that may be functions at runtime -- rewrite
150
+ // those as direct async functions. (Pre-#1246 plugin-rsc reported false,
151
+ // not undefined, here, so === false would wrongly wrap them post-bump.)
152
+ if (meta.isFunction !== true) {
153
+ unconfirmedExports.push(name);
143
154
  return false;
144
155
  }
145
156
  return true;
146
157
  },
147
158
  });
148
159
 
149
- if (nonFunctionExports.length > 0) {
160
+ if (unconfirmedExports.length > 0) {
161
+ const plural = unconfirmedExports.length > 1;
150
162
  throw new Error(
151
- `[rango:use-cache] File-level "use cache" in ${sourceId} cannot wrap ` +
152
- `non-function export${nonFunctionExports.length > 1 ? "s" : ""}: ` +
153
- `${nonFunctionExports.map((n) => `"${n}"`).join(", ")}. ` +
154
- `Only function exports can be cached. Either remove "use cache" from ` +
155
- `the file level and add it inside individual functions, or move the ` +
156
- `non-function exports to a separate module.`,
163
+ `[rango:use-cache] File-level "use cache" in ${sourceId} only wraps ` +
164
+ `exports that are statically-confirmed functions. ` +
165
+ `${plural ? "These exports are" : "This export is"} not: ` +
166
+ `${unconfirmedExports.map((n) => `"${n}"`).join(", ")}. ` +
167
+ `Declare them directly (export async function foo() {} or ` +
168
+ `export const foo = async () => {}). A factory or otherwise ` +
169
+ `statically-indeterminate initializer (export const foo = makeCached(fn)) ` +
170
+ `is rejected even if it returns a function at runtime -- rewrite it as a ` +
171
+ `direct async function, or move non-function exports to a separate module.`,
157
172
  );
158
173
  }
159
174
 
160
175
  if (exportNames.length === 0) {
161
- // Even if no exports were wrapped, strip the directive
162
176
  const s = new MagicString(code);
163
177
  const directive = findFileLevelDirective(ast);
164
178
  if (directive) {
@@ -175,12 +189,10 @@ function transformFileLevelUseCache(
175
189
  return;
176
190
  }
177
191
 
178
- // Prepend the import
179
192
  output.prepend(
180
193
  `import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};\n`,
181
194
  );
182
195
 
183
- // Replace the directive with a comment
184
196
  const directive = findFileLevelDirective(ast);
185
197
  if (directive) {
186
198
  output.overwrite(
@@ -206,7 +218,7 @@ function transformFunctionLevelUseCache(
206
218
  ) {
207
219
  try {
208
220
  const { output, names } = transformHoistInlineDirective(code, ast, {
209
- directive: /^use cache(:\s*[\w-]+)?$/,
221
+ directive: USE_CACHE_DIRECTIVE_RE,
210
222
  runtime: (
211
223
  value: string,
212
224
  name: string,
@@ -224,9 +236,6 @@ function transformFunctionLevelUseCache(
224
236
 
225
237
  if (names.length === 0) return;
226
238
 
227
- // Use a top-level import instead of await import() — the hoisted wrapper
228
- // may be placed in a non-async context (e.g., inside a synchronous
229
- // urls() callback) where await is not allowed.
230
239
  output.prepend(
231
240
  `import { registerCachedFunction as __rango_registerCachedFunction } from ${JSON.stringify(CACHE_RUNTIME_IMPORT)};\n`,
232
241
  );
@@ -241,9 +250,6 @@ function transformFunctionLevelUseCache(
241
250
  }
242
251
  }
243
252
 
244
- /**
245
- * Find the file-level "use cache" directive AST node for removal.
246
- */
247
253
  function findFileLevelDirective(
248
254
  ast: any,
249
255
  ): { start: number; end: number } | null {
@@ -260,23 +266,8 @@ function findFileLevelDirective(
260
266
  return null;
261
267
  }
262
268
 
263
- /**
264
- * The valid directive regex (must stay in sync with transformFunctionLevelUseCache).
265
- */
266
- const VALID_DIRECTIVE_RE = /^use cache(:\s*[\w-]+)?$/;
267
-
268
- /**
269
- * Regex for near-miss: starts with "use cache:" but has invalid tokens.
270
- */
271
269
  const NEAR_MISS_RE = /^use cache:\s*.+$/;
272
270
 
273
- /**
274
- * Walk the AST looking for string literals that look like malformed
275
- * "use cache" directives and emit a Vite warning for each.
276
- *
277
- * This catches cases like `"use cache: bad.name"` or `"use cache: "`
278
- * that the transform regex silently ignores.
279
- */
280
271
  function warnOnNearMissDirectives(
281
272
  ast: any,
282
273
  fileId: string,
@@ -294,7 +285,7 @@ function warnOnNearMissDirectives(
294
285
  if (
295
286
  value.startsWith("use cache") &&
296
287
  NEAR_MISS_RE.test(value) &&
297
- !VALID_DIRECTIVE_RE.test(value)
288
+ !USE_CACHE_DIRECTIVE_RE.test(value)
298
289
  ) {
299
290
  const profilePart = value.slice("use cache:".length).trim();
300
291
  warn(
@@ -304,7 +295,6 @@ function warnOnNearMissDirectives(
304
295
  }
305
296
  }
306
297
 
307
- // Walk into function bodies where directives appear
308
298
  for (const key of Object.keys(node)) {
309
299
  const child = node[key];
310
300
  if (Array.isArray(child)) {
@@ -1,12 +1,26 @@
1
1
  import type { Plugin } from "vite";
2
2
  import { resolve } from "node:path";
3
3
  import * as Vite from "vite";
4
+ import { resolveRscEntryFromConfig } from "../utils/shared-utils.js";
5
+ import { RSC_ENTRY_BOOTSTRAP_IMPORTS } from "./virtual-entries.js";
4
6
 
5
7
  /**
6
- * Plugin that auto-injects VERSION and routes-manifest into custom entry.rsc files.
7
- * If a custom entry.rsc file uses createRSCHandler but doesn't pass version,
8
- * this transform adds the import and property automatically.
9
- * Also ensures the routes-manifest virtual module is always imported.
8
+ * Plugin that auto-injects VERSION, routes-manifest, and loader-manifest into
9
+ * custom entry.rsc files. If a custom entry.rsc file uses createRSCHandler but
10
+ * doesn't pass version, this transform adds the import and property
11
+ * automatically. It also ensures the routes-manifest and loader-manifest
12
+ * virtual modules are always imported.
13
+ *
14
+ * The loader-manifest import is what makes fetchable loaders resolvable on a
15
+ * custom worker entry. The virtual RSC entry (getVirtualEntryRSC) imports the
16
+ * loader manifest itself, but a hand-written entry (e.g. a Cloudflare
17
+ * worker.rsc.tsx) does not — so without this injection, setLoaderImports() is
18
+ * never bundled, lazyLoaderImports stays null at runtime, and a fetchable
19
+ * loader that is never imported by the server graph (not registered via
20
+ * loader(), reachable only through a client component) cannot be found by the
21
+ * _rsc_loader endpoint in production. Dev still works because it resolves
22
+ * loaders by parsing their id into a file path; only production relied on the
23
+ * manifest, hence the production-only failure this fixes.
10
24
  * @internal
11
25
  */
12
26
  export function createVersionInjectorPlugin(
@@ -20,18 +34,7 @@ export function createVersionInjectorPlugin(
20
34
 
21
35
  configResolved(config) {
22
36
  let entryPath = rscEntryPath;
23
- // Cloudflare preset: read entry from resolved environment config.
24
- // The @cloudflare/vite-plugin reads wrangler config (toml/json/jsonc)
25
- // and sets optimizeDeps.entries on the RSC environment.
26
- if (!entryPath) {
27
- const rscEnvConfig = (config.environments as any)?.["rsc"];
28
- const entries = rscEnvConfig?.optimizeDeps?.entries;
29
- if (typeof entries === "string") {
30
- entryPath = entries;
31
- } else if (Array.isArray(entries) && entries.length > 0) {
32
- entryPath = entries[0];
33
- }
34
- }
37
+ if (!entryPath) entryPath = resolveRscEntryFromConfig(config);
35
38
  if (entryPath) {
36
39
  resolvedEntryPath = resolve(config.root, entryPath);
37
40
  }
@@ -39,7 +42,6 @@ export function createVersionInjectorPlugin(
39
42
 
40
43
  transform(code, id) {
41
44
  if (!resolvedEntryPath) return null;
42
- // Only transform the RSC entry file
43
45
  const normalizedId = Vite.normalizePath(id);
44
46
  const normalizedEntry = Vite.normalizePath(resolvedEntryPath);
45
47
 
@@ -47,16 +49,13 @@ export function createVersionInjectorPlugin(
47
49
  return null;
48
50
  }
49
51
 
50
- // Prepend imports at the top of the file. ES imports are hoisted
51
- // by the module system, so source position is irrelevant.
52
- const prepend: string[] = [];
53
- let newCode = code;
54
-
55
- if (!code.includes("virtual:rsc-router/routes-manifest")) {
56
- prepend.push(`import "virtual:rsc-router/routes-manifest";`);
57
- }
52
+ // Same startup bootstrap imports the generated virtual RSC entry uses,
53
+ // from the single shared list so the two paths cannot drift.
54
+ const prepend: string[] = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
55
+ (id) => `import "${id}";`,
56
+ );
58
57
 
59
- // Auto-inject VERSION if file uses createRSCHandler without version
58
+ let newCode = code;
60
59
  const needsVersion =
61
60
  code.includes("createRSCHandler") &&
62
61
  !code.includes("@rangojs/router:version") &&
@@ -70,9 +69,21 @@ export function createVersionInjectorPlugin(
70
69
  );
71
70
  }
72
71
 
73
- if (prepend.length === 0 && newCode === code) return null;
74
-
75
- newCode = prepend.join("\n") + (prepend.length > 0 ? "\n" : "") + newCode;
72
+ const lines = newCode.split("\n");
73
+ let insertAt = 0;
74
+ while (insertAt < lines.length) {
75
+ const trimmed = lines[insertAt]!.trim();
76
+ if (trimmed === "" || /^\/\/\/\s*<reference\b/.test(trimmed)) {
77
+ insertAt++;
78
+ } else {
79
+ break;
80
+ }
81
+ }
82
+ newCode = [
83
+ ...lines.slice(0, insertAt),
84
+ ...prepend,
85
+ ...lines.slice(insertAt),
86
+ ].join("\n");
76
87
 
77
88
  return {
78
89
  code: newCode,
@@ -1,5 +1,6 @@
1
1
  import { parseAst, type Plugin } from "vite";
2
2
  import { VIRTUAL_IDS, getVirtualVersionContent } from "./virtual-entries.js";
3
+ import { hasUseClientDirective } from "../utils/directive-prologue.js";
3
4
 
4
5
  interface ClientModuleSignature {
5
6
  key: string;
@@ -16,30 +17,17 @@ function normalizeModuleId(id: string): string {
16
17
  function getClientModuleSignature(
17
18
  source: string,
18
19
  ): ClientModuleSignature | undefined {
20
+ // Same leading-directive sniff the rango HMR plugin uses (shared helper, so the
21
+ // two agree on what counts as a client module). A parse failure yields false.
22
+ if (!hasUseClientDirective(source)) return undefined;
23
+
19
24
  let program: any;
20
25
  try {
21
- program = parseAst(source, { jsx: true });
26
+ program = parseAst(source, { lang: "tsx" });
22
27
  } catch {
23
28
  return undefined;
24
29
  }
25
30
 
26
- let isUseClient = false;
27
- for (const node of program.body ?? []) {
28
- if (
29
- node?.type === "ExpressionStatement" &&
30
- node.expression?.type === "Literal" &&
31
- typeof node.expression.value === "string"
32
- ) {
33
- if (node.expression.value === "use client") {
34
- isUseClient = true;
35
- }
36
- continue;
37
- }
38
- break;
39
- }
40
-
41
- if (!isUseClient) return undefined;
42
-
43
31
  const exports = new Set<string>();
44
32
  let hasDefault = false;
45
33
  let hasExportAll = false;
@@ -133,14 +121,13 @@ export function createVersionPlugin(): Plugin {
133
121
  let currentVersion = buildVersion;
134
122
  let isDev = false;
135
123
  let server: any = null;
124
+ let resolvedCacheDir: string | undefined;
136
125
  const clientModuleSignatures = new Map<string, ClientModuleSignature>();
137
126
 
138
127
  let versionCounter = 0;
139
128
  const bumpVersion = (reason: string) => {
140
- // Use timestamp + counter to guarantee uniqueness even when multiple
141
- // bumps happen within the same millisecond (e.g. cascading HMR events).
142
129
  currentVersion = Date.now().toString(16) + String(++versionCounter);
143
- console.log(`[rsc-router] ${reason}, version updated: ${currentVersion}`);
130
+ console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
144
131
 
145
132
  const rscEnv = server?.environments?.rsc;
146
133
  const versionMod = rscEnv?.moduleGraph?.getModuleById(
@@ -157,6 +144,9 @@ export function createVersionPlugin(): Plugin {
157
144
 
158
145
  configResolved(config) {
159
146
  isDev = config.command === "serve";
147
+ resolvedCacheDir = config.cacheDir
148
+ ? String(config.cacheDir).replace(/\\/g, "/")
149
+ : undefined;
160
150
  },
161
151
 
162
152
  configureServer(devServer) {
@@ -203,19 +193,15 @@ export function createVersionPlugin(): Plugin {
203
193
  return null;
204
194
  },
205
195
 
206
- // Track RSC module changes and update version
207
196
  async hotUpdate(ctx) {
208
197
  if (!isDev) return;
209
198
 
210
- // Check if this is an RSC environment update (not client/ssr)
211
- // RSC modules affect server-rendered content and cached payloads
212
- // In Vite 6, environment is accessed via `this.environment`
213
199
  const isRscModule = this.environment?.name === "rsc";
214
200
 
215
201
  if (!isRscModule) return;
216
202
 
217
- // Skip re-bumping when the version virtual module itself is invalidated
218
- // (our own bumpVersion() invalidates it, which re-triggers hotUpdate).
203
+ if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
204
+
219
205
  if (
220
206
  ctx.modules.length === 1 &&
221
207
  ctx.modules[0].id === "\0" + VIRTUAL_IDS.version
@@ -230,9 +216,6 @@ export function createVersionPlugin(): Plugin {
230
216
  const source = await ctx.read();
231
217
  const nextSignature = getClientModuleSignature(source);
232
218
  if (nextSignature) {
233
- // "use client" file — compare export signatures.
234
- // client-component-hmr may have cleared ctx.modules, so we
235
- // cannot rely on ctx.modules.length for these files.
236
219
  clientModuleSignatures.set(filePath, nextSignature);
237
220
  if (
238
221
  previousSignature &&
@@ -243,20 +226,11 @@ export function createVersionPlugin(): Plugin {
243
226
  } else {
244
227
  clientModuleSignatures.delete(filePath);
245
228
  if (!previousSignature) {
246
- // Not and never was "use client" — use module graph check.
247
- // ctx.modules is reliable for pure server files (only
248
- // client-component-hmr clears it for "use client" modules).
249
229
  if (ctx.modules.length === 0) return;
250
230
  }
251
- // Was "use client" but directive removed — boundary changed,
252
- // bump below.
253
231
  }
254
- } catch {
255
- // Fail open: if we can't read or parse the update, invalidate.
256
- }
232
+ } catch {}
257
233
  } else {
258
- // Non-code file (json, css, etc.) — only bump if it's actually
259
- // referenced by the RSC module graph.
260
234
  if (ctx.modules.length === 0) return;
261
235
  }
262
236
 
@@ -264,3 +238,26 @@ export function createVersionPlugin(): Plugin {
264
238
  },
265
239
  };
266
240
  }
241
+
242
+ export function isViteDepCachePath(
243
+ filePath: string | undefined,
244
+ cacheDir?: string,
245
+ ): boolean {
246
+ if (!filePath) return false;
247
+ const normalized = filePath.replace(/\\/g, "/");
248
+
249
+ if (cacheDir) {
250
+ const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
251
+ if (
252
+ normalized === normalizedCacheDir ||
253
+ normalized.startsWith(normalizedCacheDir + "/")
254
+ ) {
255
+ return true;
256
+ }
257
+ }
258
+
259
+ return (
260
+ /\/node_modules\/\.vite[^/]*\//.test(normalized) ||
261
+ normalized.includes("/.vite-isolated/")
262
+ );
263
+ }