vinext 1.0.1 → 1.2.0

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 (334) hide show
  1. package/README.md +93 -10
  2. package/dist/build/app-page-static-eligibility.d.ts +15 -0
  3. package/dist/build/app-page-static-eligibility.js +82 -0
  4. package/dist/build/client-build-config.d.ts +10 -0
  5. package/dist/build/client-build-config.js +18 -2
  6. package/dist/build/pages-client-assets-module.d.ts +8 -0
  7. package/dist/build/pages-client-assets-module.js +21 -1
  8. package/dist/build/prerender-paths.js +8 -81
  9. package/dist/build/prerender.js +33 -8
  10. package/dist/build/run-prerender.js +1 -1
  11. package/dist/build/server-manifest.d.ts +7 -0
  12. package/dist/build/server-manifest.js +11 -1
  13. package/dist/build/ssr-manifest.d.ts +2 -0
  14. package/dist/build/ssr-manifest.js +6 -2
  15. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  16. package/dist/cache/cache-adapters-virtual.js +3 -3
  17. package/dist/check.js +7 -6
  18. package/dist/cli.js +2 -1
  19. package/dist/client/client-redirect-matcher.d.ts +14 -0
  20. package/dist/client/client-redirect-matcher.js +37 -0
  21. package/dist/client/client-redirects.d.ts +27 -0
  22. package/dist/client/client-redirects.js +28 -0
  23. package/dist/client/client-rewrites.d.ts +2 -1
  24. package/dist/client/client-rewrites.js +1 -1
  25. package/dist/client/navigation-runtime.d.ts +11 -0
  26. package/dist/client/navigation-runtime.js +1 -1
  27. package/dist/config/config-matchers.d.ts +26 -11
  28. package/dist/config/config-matchers.js +81 -82
  29. package/dist/config/destination-params.d.ts +47 -0
  30. package/dist/config/destination-params.js +116 -0
  31. package/dist/config/next-config.d.ts +14 -0
  32. package/dist/config/next-config.js +21 -3
  33. package/dist/entries/app-rsc-entry.d.ts +6 -0
  34. package/dist/entries/app-rsc-entry.js +84 -49
  35. package/dist/entries/pages-client-entry.js +3 -1
  36. package/dist/entries/pages-server-entry.js +13 -37
  37. package/dist/index.d.ts +7 -2
  38. package/dist/index.js +193 -73
  39. package/dist/init-cloudflare.d.ts +9 -0
  40. package/dist/init-cloudflare.js +107 -31
  41. package/dist/init-platform.d.ts +4 -0
  42. package/dist/init-platform.js +27 -2
  43. package/dist/init.d.ts +1 -0
  44. package/dist/init.js +67 -3
  45. package/dist/plugins/ast-scope.d.ts +7 -0
  46. package/dist/plugins/ast-scope.js +59 -3
  47. package/dist/plugins/cache-flight-codec.d.ts +19 -0
  48. package/dist/plugins/cache-flight-codec.js +68 -0
  49. package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
  50. package/dist/plugins/commonjs-esm-facade.js +80 -0
  51. package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
  52. package/dist/plugins/dynamic-preload-metadata.js +9 -8
  53. package/dist/plugins/fonts.d.ts +8 -11
  54. package/dist/plugins/fonts.js +71 -34
  55. package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
  56. package/dist/plugins/ignore-dynamic-requests.js +3 -4
  57. package/dist/plugins/middleware-server-only.d.ts +5 -4
  58. package/dist/plugins/middleware-server-only.js +8 -5
  59. package/dist/plugins/pages-node-externals.js +1 -1
  60. package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
  61. package/dist/plugins/rsc-scan-glob-imports.js +50 -0
  62. package/dist/plugins/strip-server-exports.js +262 -98
  63. package/dist/plugins/transform-result.d.ts +9 -5
  64. package/dist/plugins/transitive-externals.js +1 -1
  65. package/dist/plugins/typeof-window.d.ts +2 -2
  66. package/dist/plugins/use-cache-callable.js +8 -2
  67. package/dist/plugins/worker-server-only-imports.d.ts +20 -0
  68. package/dist/plugins/worker-server-only-imports.js +31 -0
  69. package/dist/plugins/worker-use-server.d.ts +25 -0
  70. package/dist/plugins/worker-use-server.js +129 -0
  71. package/dist/routing/file-matcher.d.ts +1 -0
  72. package/dist/routing/file-matcher.js +1 -1
  73. package/dist/server/api-handler.d.ts +1 -0
  74. package/dist/server/api-handler.js +19 -8
  75. package/dist/server/app-browser-action-result.d.ts +1 -1
  76. package/dist/server/app-browser-action-result.js +9 -2
  77. package/dist/server/app-browser-entry.js +11 -7
  78. package/dist/server/app-browser-history-controller.d.ts +2 -0
  79. package/dist/server/app-browser-history-controller.js +8 -0
  80. package/dist/server/app-browser-interception-context.js +26 -2
  81. package/dist/server/app-browser-navigation-controller.d.ts +7 -1
  82. package/dist/server/app-browser-navigation-controller.js +94 -11
  83. package/dist/server/app-browser-server-action-client.js +1 -1
  84. package/dist/server/app-fallback-renderer.d.ts +2 -0
  85. package/dist/server/app-fallback-renderer.js +1 -0
  86. package/dist/server/app-history-state.d.ts +3 -0
  87. package/dist/server/app-history-state.js +7 -0
  88. package/dist/server/app-middleware.d.ts +11 -0
  89. package/dist/server/app-middleware.js +19 -3
  90. package/dist/server/app-optimistic-routing.js +1 -1
  91. package/dist/server/app-page-boundary-render.d.ts +5 -0
  92. package/dist/server/app-page-boundary-render.js +6 -4
  93. package/dist/server/app-page-cache-finalizer.d.ts +11 -0
  94. package/dist/server/app-page-cache-finalizer.js +41 -7
  95. package/dist/server/app-page-cache-render.d.ts +18 -0
  96. package/dist/server/app-page-cache-render.js +63 -43
  97. package/dist/server/app-page-cache.d.ts +6 -1
  98. package/dist/server/app-page-cache.js +28 -8
  99. package/dist/server/app-page-dispatch.d.ts +12 -2
  100. package/dist/server/app-page-dispatch.js +51 -33
  101. package/dist/server/app-page-element-builder.d.ts +7 -0
  102. package/dist/server/app-page-element-builder.js +27 -42
  103. package/dist/server/app-page-execution.d.ts +15 -12
  104. package/dist/server/app-page-execution.js +30 -40
  105. package/dist/server/app-page-head.d.ts +5 -0
  106. package/dist/server/app-page-head.js +9 -3
  107. package/dist/server/app-page-ppr-runtime.js +1 -1
  108. package/dist/server/app-page-probe.d.ts +0 -109
  109. package/dist/server/app-page-probe.js +3 -136
  110. package/dist/server/app-page-render-identity.d.ts +0 -1
  111. package/dist/server/app-page-render-identity.js +1 -1
  112. package/dist/server/app-page-render-observation.js +3 -3
  113. package/dist/server/app-page-render.d.ts +13 -5
  114. package/dist/server/app-page-render.js +219 -119
  115. package/dist/server/app-page-request.d.ts +0 -1
  116. package/dist/server/app-page-request.js +54 -17
  117. package/dist/server/app-page-response.d.ts +4 -3
  118. package/dist/server/app-page-response.js +4 -3
  119. package/dist/server/app-page-route-wiring.d.ts +17 -5
  120. package/dist/server/app-page-route-wiring.js +57 -35
  121. package/dist/server/app-page-rsc-render-status.d.ts +48 -0
  122. package/dist/server/app-page-rsc-render-status.js +54 -0
  123. package/dist/server/app-page-stream.d.ts +15 -8
  124. package/dist/server/app-page-stream.js +6 -0
  125. package/dist/server/app-pages-bridge.d.ts +1 -1
  126. package/dist/server/app-pages-bridge.js +2 -3
  127. package/dist/server/app-prerender-endpoints.js +9 -6
  128. package/dist/server/app-request-stage-dispatch.js +7 -3
  129. package/dist/server/app-request-stage-independent-entry.js +29 -9
  130. package/dist/server/app-response-header-provenance.d.ts +2 -0
  131. package/dist/server/app-response-header-provenance.js +10 -4
  132. package/dist/server/app-response-stage-entry.js +10 -2
  133. package/dist/server/app-route-handler-cache.d.ts +1 -0
  134. package/dist/server/app-route-handler-cache.js +1 -0
  135. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  136. package/dist/server/app-route-handler-dispatch.js +6 -3
  137. package/dist/server/app-route-handler-execution.d.ts +1 -0
  138. package/dist/server/app-route-handler-execution.js +1 -0
  139. package/dist/server/app-route-handler-runtime.d.ts +4 -1
  140. package/dist/server/app-route-handler-runtime.js +45 -24
  141. package/dist/server/app-router-entry.js +27 -8
  142. package/dist/server/app-rsc-cache-busting.js +1 -1
  143. package/dist/server/app-rsc-errors.js +20 -16
  144. package/dist/server/app-rsc-handler.d.ts +11 -0
  145. package/dist/server/app-rsc-handler.js +291 -125
  146. package/dist/server/app-rsc-request-normalization.d.ts +3 -1
  147. package/dist/server/app-rsc-request-normalization.js +4 -2
  148. package/dist/server/app-rsc-response-stage.d.ts +1 -1
  149. package/dist/server/app-rsc-response-stage.js +10 -6
  150. package/dist/server/app-rsc-route-matching.d.ts +9 -1
  151. package/dist/server/app-rsc-route-matching.js +36 -19
  152. package/dist/server/app-segment-config.d.ts +2 -1
  153. package/dist/server/app-server-action-execution.d.ts +2 -1
  154. package/dist/server/app-server-action-execution.js +62 -23
  155. package/dist/server/app-ssr-entry.d.ts +3 -2
  156. package/dist/server/app-ssr-entry.js +8 -5
  157. package/dist/server/app-ssr-stream.d.ts +6 -1
  158. package/dist/server/app-ssr-stream.js +34 -15
  159. package/dist/server/app-worker-stages.d.ts +7 -2
  160. package/dist/server/app-worker-stages.js +4 -4
  161. package/dist/server/cacheability-request.js +11 -7
  162. package/dist/server/client-build-files.d.ts +16 -0
  163. package/dist/server/client-build-files.js +36 -0
  164. package/dist/server/client-reuse-manifest.js +1 -1
  165. package/dist/server/config-headers.js +2 -0
  166. package/dist/server/dev-server.js +50 -29
  167. package/dist/server/dev-stack-sourcemap.js +18 -23
  168. package/dist/server/document-initial-head.d.ts +0 -11
  169. package/dist/server/document-initial-head.js +1 -1
  170. package/dist/server/forwarded-middleware-context.d.ts +5 -0
  171. package/dist/server/forwarded-middleware-context.js +22 -0
  172. package/dist/server/headers.d.ts +18 -1
  173. package/dist/server/headers.js +19 -2
  174. package/dist/server/http-conditional.d.ts +11 -0
  175. package/dist/server/http-conditional.js +10 -1
  176. package/dist/server/http-error-responses.d.ts +1 -1
  177. package/dist/server/image-optimization.d.ts +54 -0
  178. package/dist/server/image-optimization.js +118 -9
  179. package/dist/server/isr-cache.d.ts +10 -0
  180. package/dist/server/isr-cache.js +43 -8
  181. package/dist/server/metadata-route-response.js +9 -8
  182. package/dist/server/middleware-matcher-pattern.js +8 -4
  183. package/dist/server/middleware-matcher.d.ts +2 -0
  184. package/dist/server/middleware-matcher.js +23 -2
  185. package/dist/server/middleware-response-headers.js +2 -0
  186. package/dist/server/middleware-runtime.d.ts +13 -0
  187. package/dist/server/middleware-runtime.js +33 -20
  188. package/dist/server/middleware.d.ts +1 -1
  189. package/dist/server/middleware.js +3 -1
  190. package/dist/server/multi-stage.d.ts +19 -0
  191. package/dist/server/navigation-planner.js +1 -1
  192. package/dist/server/node-response-signal.d.ts +16 -0
  193. package/dist/server/node-response-signal.js +26 -0
  194. package/dist/server/normalize-path.d.ts +0 -13
  195. package/dist/server/normalize-path.js +1 -34
  196. package/dist/server/open-redirect.d.ts +47 -0
  197. package/dist/server/open-redirect.js +74 -1
  198. package/dist/server/pages-api-route.d.ts +3 -2
  199. package/dist/server/pages-api-route.js +4 -3
  200. package/dist/server/pages-cache-tag.d.ts +12 -0
  201. package/dist/server/pages-cache-tag.js +19 -0
  202. package/dist/server/pages-client-assets.d.ts +2 -0
  203. package/dist/server/pages-data-route.d.ts +10 -0
  204. package/dist/server/pages-data-route.js +19 -2
  205. package/dist/server/pages-document-asset-props.d.ts +5 -1
  206. package/dist/server/pages-document-asset-props.js +13 -5
  207. package/dist/server/pages-document-splice.d.ts +19 -0
  208. package/dist/server/pages-document-splice.js +55 -0
  209. package/dist/server/pages-i18n.d.ts +12 -1
  210. package/dist/server/pages-i18n.js +18 -4
  211. package/dist/server/pages-node-compat.d.ts +16 -5
  212. package/dist/server/pages-node-compat.js +20 -12
  213. package/dist/server/pages-page-data.d.ts +32 -24
  214. package/dist/server/pages-page-data.js +50 -120
  215. package/dist/server/pages-page-handler.d.ts +0 -6
  216. package/dist/server/pages-page-handler.js +209 -130
  217. package/dist/server/pages-page-response.d.ts +12 -6
  218. package/dist/server/pages-page-response.js +41 -34
  219. package/dist/server/pages-request-pipeline.d.ts +10 -2
  220. package/dist/server/pages-request-pipeline.js +37 -18
  221. package/dist/server/pages-request-stage-entry.d.ts +6 -0
  222. package/dist/server/pages-request-stage-entry.js +79 -16
  223. package/dist/server/pages-response-stage-entry.js +4 -0
  224. package/dist/server/pages-revalidate.js +1 -1
  225. package/dist/server/pages-router-entry.js +4 -3
  226. package/dist/server/prerender-manifest.d.ts +3 -3
  227. package/dist/server/prerender-manifest.js +4 -3
  228. package/dist/server/prerender-work-unit-setup.js +4 -0
  229. package/dist/server/prod-server.d.ts +20 -7
  230. package/dist/server/prod-server.js +343 -129
  231. package/dist/server/proper-error.d.ts +4 -0
  232. package/dist/server/proper-error.js +31 -0
  233. package/dist/server/request-pipeline.d.ts +24 -9
  234. package/dist/server/request-pipeline.js +24 -9
  235. package/dist/server/response-compression.d.ts +43 -0
  236. package/dist/server/response-compression.js +111 -0
  237. package/dist/server/revalidation-request.d.ts +1 -0
  238. package/dist/server/revalidation-request.js +1 -1
  239. package/dist/server/rsc-stream-hints.js +31 -2
  240. package/dist/server/seed-cache.d.ts +1 -0
  241. package/dist/server/seed-cache.js +15 -11
  242. package/dist/server/server-reference-loader.d.ts +4 -0
  243. package/dist/server/server-reference-loader.js +29 -0
  244. package/dist/server/socket-error-backstop.d.ts +23 -1
  245. package/dist/server/socket-error-backstop.js +69 -17
  246. package/dist/server/static-file-signal.d.ts +15 -4
  247. package/dist/server/static-file-signal.js +46 -12
  248. package/dist/server/worker-image-optimization.d.ts +34 -0
  249. package/dist/server/worker-image-optimization.js +86 -0
  250. package/dist/server/worker-stages.d.ts +1 -1
  251. package/dist/server/worker-stages.js +2 -2
  252. package/dist/server/worker-utils.d.ts +8 -3
  253. package/dist/server/worker-utils.js +12 -7
  254. package/dist/shims/app-router-scroll.js +4 -1
  255. package/dist/shims/app-router-tree-context.d.ts +5 -0
  256. package/dist/shims/app-router-tree-context.js +27 -0
  257. package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
  258. package/dist/shims/cache-adapter-instantiate.js +118 -0
  259. package/dist/shims/cache-callable-runtime.d.ts +6 -42
  260. package/dist/shims/cache-callable-runtime.js +65 -174
  261. package/dist/shims/cache-flight-arguments.d.ts +22 -0
  262. package/dist/shims/cache-flight-arguments.js +56 -0
  263. package/dist/shims/cache-handler.js +1 -9
  264. package/dist/shims/cache-request-state.d.ts +15 -0
  265. package/dist/shims/cache-request-state.js +31 -8
  266. package/dist/shims/cache-runtime.d.ts +12 -20
  267. package/dist/shims/cache-runtime.js +166 -225
  268. package/dist/shims/cache.d.ts +4 -4
  269. package/dist/shims/cache.js +44 -16
  270. package/dist/shims/cacheability-classification.d.ts +7 -0
  271. package/dist/shims/cdn-cache.d.ts +8 -0
  272. package/dist/shims/cdn-cache.js +17 -1
  273. package/dist/shims/disable-smooth-scroll.d.ts +3 -0
  274. package/dist/shims/disable-smooth-scroll.js +36 -0
  275. package/dist/shims/document-placeholders.d.ts +19 -0
  276. package/dist/shims/document-placeholders.js +45 -0
  277. package/dist/shims/document.js +21 -5
  278. package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
  279. package/dist/shims/dynamic-preload-chunks.js +13 -9
  280. package/dist/shims/dynamic.d.ts +1 -1
  281. package/dist/shims/dynamic.js +60 -8
  282. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  283. package/dist/shims/error-boundary-navigation.js +19 -1
  284. package/dist/shims/error-boundary.d.ts +10 -10
  285. package/dist/shims/error-boundary.js +26 -7
  286. package/dist/shims/fetch-cache-state.d.ts +66 -0
  287. package/dist/shims/fetch-cache-state.js +92 -0
  288. package/dist/shims/fetch-cache.d.ts +3 -61
  289. package/dist/shims/fetch-cache.js +161 -108
  290. package/dist/shims/form.js +1 -1
  291. package/dist/shims/head.d.ts +10 -6
  292. package/dist/shims/head.js +15 -13
  293. package/dist/shims/headers.d.ts +13 -0
  294. package/dist/shims/headers.js +47 -4
  295. package/dist/shims/image.js +2 -1
  296. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
  297. package/dist/shims/internal/app-page-props-cache-key.js +24 -15
  298. package/dist/shims/internal/headers-state.d.ts +0 -1
  299. package/dist/shims/internal/work-store-scope.d.ts +5 -0
  300. package/dist/shims/internal/work-store-scope.js +24 -0
  301. package/dist/shims/metadata.js +3 -3
  302. package/dist/shims/navigation-errors.d.ts +6 -0
  303. package/dist/shims/navigation-errors.js +11 -1
  304. package/dist/shims/navigation.d.ts +7 -0
  305. package/dist/shims/navigation.js +45 -9
  306. package/dist/shims/request-context.d.ts +11 -0
  307. package/dist/shims/request-state-types.d.ts +2 -1
  308. package/dist/shims/router.js +12 -20
  309. package/dist/shims/server.d.ts +16 -0
  310. package/dist/shims/server.js +24 -4
  311. package/dist/shims/thenable-params.d.ts +4 -0
  312. package/dist/shims/thenable-params.js +25 -3
  313. package/dist/shims/unified-request-context.d.ts +1 -1
  314. package/dist/shims/unified-request-context.js +1 -0
  315. package/dist/shims/url-utils.d.ts +2 -0
  316. package/dist/shims/url-utils.js +3 -1
  317. package/dist/utils/client-runtime-metadata.js +1 -1
  318. package/dist/utils/hash.d.ts +7 -0
  319. package/dist/utils/hash.js +11 -1
  320. package/dist/utils/mdx-scan.d.ts +5 -0
  321. package/dist/utils/mdx-scan.js +8 -1
  322. package/dist/utils/package-name.d.ts +6 -0
  323. package/dist/utils/package-name.js +12 -1
  324. package/dist/utils/plugin-rsc-version.d.ts +4 -0
  325. package/dist/utils/plugin-rsc-version.js +15 -0
  326. package/dist/utils/prerender-output-paths.js +15 -4
  327. package/dist/utils/public-file-path.d.ts +10 -2
  328. package/dist/utils/public-file-path.js +13 -9
  329. package/dist/utils/public-routes.js +2 -2
  330. package/dist/utils/react-version.d.ts +3 -0
  331. package/dist/utils/react-version.js +1 -1
  332. package/dist/utils/regex-safety.d.ts +10 -0
  333. package/dist/utils/regex-safety.js +70 -18
  334. package/package.json +9 -5
@@ -0,0 +1,68 @@
1
+ import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
+ import { magicStringTransformResult } from "./transform-result.js";
3
+ import fs from "node:fs";
4
+ import MagicString from "magic-string";
5
+ //#region src/plugins/cache-flight-codec.ts
6
+ const CLIENT_CODEC = /\/react-server-dom-(?:webpack|turbopack)-client\.edge\.(?:development|production)\.js$/;
7
+ const ELEMENT_CASE = /case REACT_ELEMENT_TYPE:[\s\S]*?throw Error\(\s*"React Element cannot be passed/;
8
+ /**
9
+ * Version of the Flight codec package that owns `id`. plugin-rsc resolves the
10
+ * app's own react-server-dom-webpack when installed and its vendored copy
11
+ * otherwise; reading the codec file's own package.json follows that choice.
12
+ */
13
+ function readFlightCodecVersion(id) {
14
+ for (let dir = path.dirname(id);; dir = path.dirname(dir)) {
15
+ const manifest = path.join(dir, "package.json");
16
+ if (fs.existsSync(manifest)) {
17
+ const pkg = JSON.parse(fs.readFileSync(manifest, "utf8"));
18
+ if (/^react-server-dom-(?:webpack|turbopack)$/.test(pkg.name ?? "") && pkg.version) return pkg.version;
19
+ }
20
+ if (path.dirname(dir) === dir) throw new Error(`vinext: cannot find the react-server-dom package version for ${id}`);
21
+ }
22
+ }
23
+ /** React 19.3 ships the branch; 0.0.0-* experimental builds track main. */
24
+ function needsElementTemporaryReferenceBackport(version) {
25
+ const match = /^(\d+)\.(\d+)\./.exec(version);
26
+ if (!match || version.startsWith("0.0.0-")) return false;
27
+ const [major, minor] = [Number(match[1]), Number(match[2])];
28
+ return major < 19 || major === 19 && minor < 3;
29
+ }
30
+ /**
31
+ * Backport React 19.3's root-element temporary reference branch to older Flight
32
+ * codecs, so a "use cache" argument like `Promise<ReactElement>` encodes as a
33
+ * temporary reference instead of throwing. Remove it once React 19.3 is the
34
+ * minimum supported version.
35
+ * https://github.com/facebook/react/blob/v19.3.0/packages/react-client/src/ReactFlightReplyClient.js#L486
36
+ */
37
+ function patchCacheFlightCodec(code, id, version = readFlightCodecVersion(id)) {
38
+ if (!needsElementTemporaryReferenceBackport(version)) return null;
39
+ const elementCase = ELEMENT_CASE.exec(code);
40
+ if (!elementCase) throw new Error(`vinext: react-server-dom-webpack ${version} (${id}) is not supported. Upgrade react, react-dom, and react-server-dom-webpack to 19.3 or later. If your app does not depend on react-server-dom-webpack directly, upgrade @vitejs/plugin-rsc to 0.5.35 or later instead.`);
41
+ const output = new MagicString(code);
42
+ output.appendLeft(elementCase.index + elementCase[0].lastIndexOf("throw Error("), "if (void 0 !== temporaryReferences && modelRoot === value) return (modelRoot = null), \"$T\";\n");
43
+ return magicStringTransformResult(output, {
44
+ hires: "boundary",
45
+ source: id
46
+ });
47
+ }
48
+ function cacheFlightCodecPlugin() {
49
+ const transform = {
50
+ filter: { id: CLIENT_CODEC },
51
+ handler: (code, id) => patchCacheFlightCodec(code, id)
52
+ };
53
+ return {
54
+ name: "vinext:cache-flight-codec",
55
+ enforce: "pre",
56
+ applyToEnvironment: (environment) => environment.name === "rsc",
57
+ configEnvironment(name) {
58
+ if (name !== "rsc") return;
59
+ return { optimizeDeps: { rolldownOptions: { plugins: [{
60
+ name: "vinext:cache-flight-codec-optimizer",
61
+ transform
62
+ }] } } };
63
+ },
64
+ transform
65
+ };
66
+ }
67
+ //#endregion
68
+ export { cacheFlightCodecPlugin, patchCacheFlightCodec, readFlightCodecVersion };
@@ -0,0 +1,35 @@
1
+ import { Plugin } from "vite";
2
+ //#region src/plugins/commonjs-esm-facade.d.ts
3
+ /**
4
+ * Removes the export facade vite-plugin-commonjs appended to `output` when the
5
+ * module it transformed is ESM. Returns `undefined` when there is nothing to
6
+ * remove.
7
+ *
8
+ * Next.js treats a module with ESM syntax as ESM: `require()` still works, but
9
+ * `module` / `exports` never become its exports. The plugin's analyzer is not
10
+ * scope-aware, so for bundled ESM that inlines CommonJS wrappers
11
+ * (`__commonJS((exports, module) => …)`) it exports the wrappers' assignments
12
+ * too, which duplicates the module's own exports. Its `require()` rewrite and
13
+ * its local `module` / `exports` polyfill stay, so free CommonJS assignments
14
+ * still run without becoming exports.
15
+ *
16
+ * Besides the facade, the plugin only prepends imports and its polyfill and
17
+ * rewrites `require()` calls, so the module's own top-level exports are still
18
+ * in `output`. Classifying the output rather than rereading the source keeps
19
+ * the decision tied to the exact code the plugin transformed.
20
+ *
21
+ * The facade is appended after the module's code (only dynamic-require
22
+ * runtimes, which have no source mappings, may follow it), so removing it
23
+ * leaves the plugin's source map valid.
24
+ */
25
+ export declare function stripEsmCommonJsExportFacade(output: string): string | undefined;
26
+ /**
27
+ * Applies {@link stripEsmCommonJsExportFacade} in the client dependency
28
+ * optimizer's Rolldown builds (scan and pre-bundle). vite-plugin-commonjs's
29
+ * pre-bundle plugin loads and converts files there without vinext's transform
30
+ * wrapper, so its output reaches this hook as the loaded code. That code is
31
+ * the optimizer's source, so the removal needs its own map for anything the
32
+ * plugin appended after the facade.
33
+ */
34
+ export declare const commonJsEsmFacadeOptimizeDepsPlugin: Plugin;
35
+ //#endregion
@@ -0,0 +1,80 @@
1
+ import { parseAst } from "vite";
2
+ import MagicString from "magic-string";
3
+ //#region src/plugins/commonjs-esm-facade.ts
4
+ const EXPORT_FACADE_START = "/* [vite-plugin-commonjs] export-statement-S */";
5
+ const EXPORT_FACADE_END = "/* [vite-plugin-commonjs] export-statement-E */";
6
+ const EXPORT_KEYWORD_RE = /\bexport\b(?!-)/;
7
+ /** Whether `code` has a top-level ESM export statement. */
8
+ function hasEsmExports(code) {
9
+ if (!EXPORT_KEYWORD_RE.test(code)) return false;
10
+ let ast;
11
+ try {
12
+ ast = parseAst(code);
13
+ } catch {
14
+ return false;
15
+ }
16
+ return ast.body.some((statement) => statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" || statement.type === "ExportAllDeclaration");
17
+ }
18
+ /**
19
+ * Removes the export facade vite-plugin-commonjs appended to `output` when the
20
+ * module it transformed is ESM. Returns `undefined` when there is nothing to
21
+ * remove.
22
+ *
23
+ * Next.js treats a module with ESM syntax as ESM: `require()` still works, but
24
+ * `module` / `exports` never become its exports. The plugin's analyzer is not
25
+ * scope-aware, so for bundled ESM that inlines CommonJS wrappers
26
+ * (`__commonJS((exports, module) => …)`) it exports the wrappers' assignments
27
+ * too, which duplicates the module's own exports. Its `require()` rewrite and
28
+ * its local `module` / `exports` polyfill stay, so free CommonJS assignments
29
+ * still run without becoming exports.
30
+ *
31
+ * Besides the facade, the plugin only prepends imports and its polyfill and
32
+ * rewrites `require()` calls, so the module's own top-level exports are still
33
+ * in `output`. Classifying the output rather than rereading the source keeps
34
+ * the decision tied to the exact code the plugin transformed.
35
+ *
36
+ * The facade is appended after the module's code (only dynamic-require
37
+ * runtimes, which have no source mappings, may follow it), so removing it
38
+ * leaves the plugin's source map valid.
39
+ */
40
+ function stripEsmCommonJsExportFacade(output) {
41
+ const facade = findEsmCommonJsExportFacade(output);
42
+ return facade && output.slice(0, facade[0]) + output.slice(facade[1]);
43
+ }
44
+ /** The `[start, end)` range of the facade {@link stripEsmCommonJsExportFacade} removes. */
45
+ function findEsmCommonJsExportFacade(output) {
46
+ const start = output.lastIndexOf(EXPORT_FACADE_START);
47
+ if (start === -1) return void 0;
48
+ const end = output.indexOf(EXPORT_FACADE_END, start);
49
+ if (end === -1) return void 0;
50
+ const facadeEnd = end + 47;
51
+ return hasEsmExports(output.slice(0, start) + output.slice(facadeEnd)) ? [start, facadeEnd] : void 0;
52
+ }
53
+ /**
54
+ * Applies {@link stripEsmCommonJsExportFacade} in the client dependency
55
+ * optimizer's Rolldown builds (scan and pre-bundle). vite-plugin-commonjs's
56
+ * pre-bundle plugin loads and converts files there without vinext's transform
57
+ * wrapper, so its output reaches this hook as the loaded code. That code is
58
+ * the optimizer's source, so the removal needs its own map for anything the
59
+ * plugin appended after the facade.
60
+ */
61
+ const commonJsEsmFacadeOptimizeDepsPlugin = {
62
+ name: "vinext:commonjs-esm-facade:optimize-deps",
63
+ transform: {
64
+ filter: { code: { include: EXPORT_FACADE_START } },
65
+ handler(code, id) {
66
+ const facade = findEsmCommonJsExportFacade(code);
67
+ if (!facade) return null;
68
+ const output = new MagicString(code).remove(facade[0], facade[1]);
69
+ return {
70
+ code: output.toString(),
71
+ map: output.generateMap({
72
+ source: id,
73
+ hires: "boundary"
74
+ })
75
+ };
76
+ }
77
+ }
78
+ };
79
+ //#endregion
80
+ export { commonJsEsmFacadeOptimizeDepsPlugin, stripEsmCommonJsExportFacade };
@@ -7,5 +7,5 @@ type TransformResult = {
7
7
  };
8
8
  type ResolveDynamicImport = (specifier: string, importer: string) => Promise<string | null>;
9
9
  export declare function transformNextDynamicPreloadMetadata(code: string, id: string, root: string, resolveDynamicImport: ResolveDynamicImport): Promise<TransformResult | null>;
10
- export declare function createDynamicPreloadMetadataPlugin(): Plugin;
10
+ export declare function createDynamicPreloadMetadataPlugin(getTranspiledPackages: () => readonly string[]): Plugin;
11
11
  //#endregion
@@ -3,7 +3,8 @@ import { collectBindingNames, forEachAstChild, stringLiteralValue, walkAst } fro
3
3
  import { hasTrailingComma } from "../utils/has-trailing-comma.js";
4
4
  import { magicStringTransformResult } from "./transform-result.js";
5
5
  import { stripViteModuleQuery } from "../utils/path.js";
6
- import { relativeWithinRoot, tryRealpathSync } from "../build/ssr-manifest.js";
6
+ import { isForeignNodeModule } from "../utils/package-name.js";
7
+ import { relativeToRoot, relativeWithinRoot, tryRealpathSync } from "../build/ssr-manifest.js";
7
8
  import { parseAst } from "vite";
8
9
  import MagicString from "magic-string";
9
10
  //#region src/plugins/dynamic-preload-metadata.ts
@@ -204,7 +205,7 @@ function toManifestModuleId(root, resolvedId) {
204
205
  const relative = relativeWithinRoot(rootCandidate, moduleCandidate);
205
206
  if (relative) return relative;
206
207
  }
207
- return null;
208
+ return relativeToRoot(root, cleaned) || null;
208
209
  }
209
210
  async function resolveManifestModuleIds(specifiers, importer, root, resolveDynamicImport) {
210
211
  const resolvedIds = [];
@@ -262,24 +263,24 @@ async function transformNextDynamicPreloadMetadata(code, id, root, resolveDynami
262
263
  if (!changed) return null;
263
264
  return magicStringTransformResult(output);
264
265
  }
265
- function createDynamicPreloadMetadataPlugin() {
266
+ function createDynamicPreloadMetadataPlugin(getTranspiledPackages) {
266
267
  let root = toSlash(process.cwd());
268
+ let isBuild = false;
267
269
  return {
268
270
  name: "vinext:dynamic-preload-metadata",
269
271
  configResolved(config) {
270
272
  root = config.root;
273
+ isBuild = config.command === "build";
271
274
  },
272
275
  transform: {
273
276
  filter: {
274
- id: {
275
- include: /\.(tsx?|jsx?|mjs)$/,
276
- exclude: /node_modules/
277
- },
277
+ id: /\.(tsx?|jsx?|mjs)$/,
278
278
  code: "next/dynamic"
279
279
  },
280
280
  async handler(code, id) {
281
- if (id.includes("node_modules") || id.startsWith("\0")) return null;
281
+ if (id.startsWith("\0")) return null;
282
282
  if (!/\.(tsx?|jsx?|mjs)$/.test(id)) return null;
283
+ if (id.includes("node_modules") && (!isBuild || isForeignNodeModule(id, getTranspiledPackages()))) return null;
283
284
  const result = await transformNextDynamicPreloadMetadata(code, id, root, async (specifier, importer) => {
284
285
  return (await this.resolve(specifier, importer, { skipSelf: true }))?.id ?? null;
285
286
  });
@@ -3,9 +3,10 @@ import { Plugin } from "vite";
3
3
  export declare const VIRTUAL_GOOGLE_FONTS = "virtual:vinext-google-fonts";
4
4
  export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
5
5
  /**
6
- * Rewrite absolute filesystem paths in cached Google Fonts CSS so the
7
- * `@font-face { src: url(...) }` references point at the served URL the
8
- * plugin's `writeBundle` hook copies the font files to.
6
+ * Point the `@font-face { src: url(...) }` references of cached Google Fonts
7
+ * CSS at the served URL the plugin's `writeBundle` hook copies the font
8
+ * files to (and the dev middleware serves them from), by replacing
9
+ * `CACHED_FONT_DIR_TOKEN` with `/<assetsDir>/_vinext_fonts`.
9
10
  *
10
11
  * This is called once per transform, before the CSS string is embedded in
11
12
  * the bundle as `_vinext.font.selfHostedCSS`. Every downstream consumer reads
@@ -14,9 +15,9 @@ export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
14
15
  * in `shims/font-google-base.ts`), and the HTTP `Link:` response header
15
16
  * (via `buildAppPageFontLinkHeader` in `server/app-page-execution.ts`).
16
17
  *
17
- * Without this rewrite, all three emit the dev-machine filesystem path
18
- * (e.g. `/home/user/project/.vinext/fonts/geist-<hash>/geist-<hash>.woff2`)
19
- * and any production request fetches `<origin>/home/user/...` → 404.
18
+ * The token is substituted with plain split/join: it is a fixed string
19
+ * vinext wrote itself, so nothing about the checkout's path (spaces, quotes,
20
+ * parentheses, regex metacharacters, Windows separators) is parsed here.
20
21
  *
21
22
  * `assetsDir` must match whatever Vite has resolved for
22
23
  * `build.assetsDir` on the client environment — otherwise the embedded
@@ -26,12 +27,8 @@ export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
26
27
  * passes the resolved value through from plugin state. The default is
27
28
  * kept only so the exported helper can be driven directly from unit
28
29
  * tests without synthesizing a full plugin context.
29
- *
30
- * Uses split/join rather than regex because `cacheDir` is an absolute
31
- * filesystem path that may contain regex metacharacters on unusual
32
- * filesystems.
33
30
  */
34
- export declare function _rewriteCachedFontCssToServedUrls(css: string, cacheDir: string, assetsDir?: string): string;
31
+ export declare function _rewriteCachedFontCssToServedUrls(css: string, assetsDir?: string): string;
35
32
  /**
36
33
  * Safely parse a static JS object literal string into a plain object.
37
34
  * Uses Vite's parseAst (Rollup/acorn) so no code is ever evaluated.
@@ -43,15 +43,15 @@ const GOOGLE_FONT_UTILITY_EXPORTS = /* @__PURE__ */ new Set([
43
43
  /**
44
44
  * Served URL prefix for self-hosted Google Font files.
45
45
  *
46
- * `fetchAndCacheFont()` downloads .woff2 files into `<root>/.vinext/fonts/`
46
+ * `fetchAndCacheFont()` downloads font files into `<root>/.vinext/fonts/`
47
47
  * and writes an `@font-face` CSS snippet whose `src: url(...)` references
48
- * the files by absolute filesystem path — convenient for disk, unusable at
49
- * runtime because browsers resolve relative to the origin. Before the CSS
50
- * is embedded in the bundle as `_vinext.font.selfHostedCSS`, the filesystem
51
- * prefix is rewritten to this URL prefix by `_rewriteCachedFontCssToServedUrls()`,
52
- * and the matching `writeBundle` hook in `createGoogleFontsPlugin` copies
53
- * the font files into `<clientOutDir>/<assetsDir>/_vinext_fonts/` so the
54
- * rewritten URL actually resolves against the origin at request time.
48
+ * name each file relative to that cache directory, behind
49
+ * `CACHED_FONT_DIR_TOKEN`. Before the CSS is embedded in the bundle as
50
+ * `_vinext.font.selfHostedCSS`, `_rewriteCachedFontCssToServedUrls()`
51
+ * replaces the token with this URL prefix, and the matching `writeBundle`
52
+ * hook in `createGoogleFontsPlugin` copies the font files into
53
+ * `<clientOutDir>/<assetsDir>/_vinext_fonts/` so the URL actually resolves
54
+ * against the origin at request time.
55
55
  *
56
56
  * The leading `_` keeps the namespace distinct from Vite's content-hashed
57
57
  * asset names (which are emitted flat into `<assetsDir>/`) and from any
@@ -59,6 +59,25 @@ const GOOGLE_FONT_UTILITY_EXPORTS = /* @__PURE__ */ new Set([
59
59
  */
60
60
  const VINEXT_FONT_URL_NAMESPACE = "_vinext_fonts";
61
61
  const MAX_GOOGLE_FONTS_ERROR_BODY_LENGTH = 500;
62
+ /**
63
+ * Stands in for the font cache directory in every `url()` of a cached
64
+ * stylesheet, so the file on disk holds no absolute path and reads the same
65
+ * wherever the checkout's `.vinext/` ends up: a moved or copied project, a
66
+ * CI cache restored into another workspace, or a Docker build that copies
67
+ * in a host's `.vinext/`. Next.js has no such cache (its Google font loader
68
+ * keeps fetched CSS in memory and emits `/_next/static/media` URLs), so the
69
+ * parity target is output that does not depend on where the cache was
70
+ * written.
71
+ */
72
+ const CACHED_FONT_DIR_TOKEN = "__VINEXT_FONT_CACHE_DIR__";
73
+ /**
74
+ * Cached stylesheet whose `url()` references use `CACHED_FONT_DIR_TOKEN`.
75
+ * The suffix ties the cache to that format: a `style.css` written by an
76
+ * earlier vinext holds the writing checkout's absolute paths, which would
77
+ * 404 once embedded, so it is never read and the font is fetched again.
78
+ * Change the suffix whenever the cached CSS format changes.
79
+ */
80
+ const CACHED_FONT_CSS_FILE = "style-q7f3kd.css";
62
81
  function formatGoogleFontsErrorBody(body) {
63
82
  const trimmed = body.trim();
64
83
  if (!trimmed) return "(empty response body)";
@@ -67,9 +86,10 @@ function formatGoogleFontsErrorBody(body) {
67
86
  return `${trimmed.slice(0, MAX_GOOGLE_FONTS_ERROR_BODY_LENGTH)}\n... (truncated ${omitted} characters)`;
68
87
  }
69
88
  /**
70
- * Rewrite absolute filesystem paths in cached Google Fonts CSS so the
71
- * `@font-face { src: url(...) }` references point at the served URL the
72
- * plugin's `writeBundle` hook copies the font files to.
89
+ * Point the `@font-face { src: url(...) }` references of cached Google Fonts
90
+ * CSS at the served URL the plugin's `writeBundle` hook copies the font
91
+ * files to (and the dev middleware serves them from), by replacing
92
+ * `CACHED_FONT_DIR_TOKEN` with `/<assetsDir>/_vinext_fonts`.
73
93
  *
74
94
  * This is called once per transform, before the CSS string is embedded in
75
95
  * the bundle as `_vinext.font.selfHostedCSS`. Every downstream consumer reads
@@ -78,9 +98,9 @@ function formatGoogleFontsErrorBody(body) {
78
98
  * in `shims/font-google-base.ts`), and the HTTP `Link:` response header
79
99
  * (via `buildAppPageFontLinkHeader` in `server/app-page-execution.ts`).
80
100
  *
81
- * Without this rewrite, all three emit the dev-machine filesystem path
82
- * (e.g. `/home/user/project/.vinext/fonts/geist-<hash>/geist-<hash>.woff2`)
83
- * and any production request fetches `<origin>/home/user/...` → 404.
101
+ * The token is substituted with plain split/join: it is a fixed string
102
+ * vinext wrote itself, so nothing about the checkout's path (spaces, quotes,
103
+ * parentheses, regex metacharacters, Windows separators) is parsed here.
84
104
  *
85
105
  * `assetsDir` must match whatever Vite has resolved for
86
106
  * `build.assetsDir` on the client environment — otherwise the embedded
@@ -90,16 +110,9 @@ function formatGoogleFontsErrorBody(body) {
90
110
  * passes the resolved value through from plugin state. The default is
91
111
  * kept only so the exported helper can be driven directly from unit
92
112
  * tests without synthesizing a full plugin context.
93
- *
94
- * Uses split/join rather than regex because `cacheDir` is an absolute
95
- * filesystem path that may contain regex metacharacters on unusual
96
- * filesystems.
97
113
  */
98
- function _rewriteCachedFontCssToServedUrls(css, cacheDir, assetsDir = DEFAULT_ASSETS_DIR) {
99
- const normalizedCacheDir = toSlash(cacheDir);
100
- if (!normalizedCacheDir || !css.includes(normalizedCacheDir)) return css;
101
- const prefix = assetsDir || DEFAULT_ASSETS_DIR;
102
- return css.split(normalizedCacheDir).join(`/${prefix}/${VINEXT_FONT_URL_NAMESPACE}`);
114
+ function _rewriteCachedFontCssToServedUrls(css, assetsDir = DEFAULT_ASSETS_DIR) {
115
+ return css.split(CACHED_FONT_DIR_TOKEN).join(`/${assetsDir || DEFAULT_ASSETS_DIR}/${VINEXT_FONT_URL_NAMESPACE}`);
103
116
  }
104
117
  /**
105
118
  * Default `build.assetsDir` — matches vinext's resolved default in
@@ -274,24 +287,49 @@ function propertyNameToGoogleFontFamily(prop) {
274
287
  }
275
288
  /**
276
289
  * Fetch Google Fonts CSS, download .woff2 files, cache locally, and return
277
- * @font-face CSS with local file references.
290
+ * @font-face CSS whose `url()` references use `CACHED_FONT_DIR_TOKEN`.
278
291
  *
279
292
  * Cache dir structure: .vinext/fonts/<family-hash>/
280
- * - style.css (the rewritten @font-face CSS)
293
+ * - style-<suffix>.css (the rewritten @font-face CSS, see `CACHED_FONT_CSS_FILE`)
281
294
  * - *.woff2 (downloaded font files)
282
295
  */
283
296
  async function fetchAndCacheFont(cssUrl, family, cacheDir) {
284
297
  const { createHash } = await import("node:crypto");
285
298
  const urlHash = createHash("md5").update(cssUrl).digest("hex").slice(0, 12);
286
- const fontDir = path.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${urlHash}`);
287
- const cachedCSSPath = path.join(fontDir, "style.css");
299
+ const fontDirName = `${family.toLowerCase().replace(/\s+/g, "-")}-${urlHash}`;
300
+ const fontDir = path.join(cacheDir, fontDirName);
301
+ const cachedCSSPath = path.join(fontDir, CACHED_FONT_CSS_FILE);
288
302
  if (fs.existsSync(cachedCSSPath)) return fs.readFileSync(cachedCSSPath, "utf-8");
303
+ const css = await downloadGoogleFont(cssUrl, family, fontDir, fontDirName);
304
+ try {
305
+ writeFileAtomically(cachedCSSPath, css);
306
+ } catch {}
307
+ return css;
308
+ }
309
+ /**
310
+ * Write-then-rename, so a write that fails midway never leaves a partial
311
+ * file for a later build to trust: both font files and the stylesheet are
312
+ * reused as soon as they exist.
313
+ */
314
+ function writeFileAtomically(filePath, data) {
315
+ const tempPath = `${filePath}.${process.pid}.tmp`;
316
+ try {
317
+ fs.writeFileSync(tempPath, data);
318
+ fs.renameSync(tempPath, filePath);
319
+ } catch (err) {
320
+ fs.rmSync(tempPath, { force: true });
321
+ throw err;
322
+ }
323
+ }
324
+ async function downloadGoogleFont(cssUrl, family, fontDir, fontDirName) {
325
+ const { createHash } = await import("node:crypto");
289
326
  const cssResponse = await fetch(cssUrl, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" } });
290
327
  if (!cssResponse.ok) {
291
328
  const body = await cssResponse.text().catch(() => "");
292
329
  throw new GoogleFontsHttpError(cssUrl, cssResponse.status, body);
293
330
  }
294
331
  let css = await cssResponse.text();
332
+ if (!css.trim()) throw new Error(`Google Fonts returned an empty stylesheet: ${cssUrl}`);
295
333
  const urlRe = /url\((https:\/\/fonts\.gstatic\.com\/[^)]+)\)/g;
296
334
  const urls = /* @__PURE__ */ new Map();
297
335
  let urlMatch;
@@ -308,14 +346,13 @@ async function fetchAndCacheFont(cssUrl, family, cacheDir) {
308
346
  const filePath = path.join(fontDir, filename);
309
347
  if (!fs.existsSync(filePath)) {
310
348
  const fontResponse = await fetch(fontUrl);
311
- if (fontResponse.ok) {
312
- const buffer = Buffer.from(await fontResponse.arrayBuffer());
313
- fs.writeFileSync(filePath, buffer);
314
- }
349
+ if (!fontResponse.ok) throw new Error(`Font file download failed with HTTP ${fontResponse.status}: ${fontUrl}`);
350
+ const buffer = Buffer.from(await fontResponse.arrayBuffer());
351
+ if (buffer.byteLength === 0) throw new Error(`Font file download returned an empty body: ${fontUrl}`);
352
+ writeFileAtomically(filePath, buffer);
315
353
  }
316
- css = css.split(fontUrl).join(filePath);
354
+ css = css.split(fontUrl).join(`${CACHED_FONT_DIR_TOKEN}/${fontDirName}/${filename}`);
317
355
  }
318
- fs.writeFileSync(cachedCSSPath, css);
319
356
  return css;
320
357
  }
321
358
  /**
@@ -546,7 +583,7 @@ function createGoogleFontsPlugin(fontGoogleShimPath, shimsDir) {
546
583
  if (err instanceof GoogleFontsHttpError) throw new Error(`[vinext:google-fonts] ${id}: Google Fonts returned HTTP ${err.status} for ${err.url}.\n${formatGoogleFontsErrorBody(err.responseBody)}`);
547
584
  return;
548
585
  }
549
- const servedCSS = _rewriteCachedFontCssToServedUrls(localCSS, cacheDir, transformAssetsDir);
586
+ const servedCSS = _rewriteCachedFontCssToServedUrls(localCSS, transformAssetsDir);
550
587
  const preloadUrls = findFontFilesInCss(servedCSS, validated.preload ? validated.subsets : void 0).filter((file) => file.preloadFontFile).map((file) => file.googleFontFileUrl);
551
588
  const fallbackMetrics = validated.adjustFontFallback === false ? void 0 : getFallbackFontOverrideMetrics(family);
552
589
  const adjustedFallbackCSS = fallbackMetrics ? buildFallbackFontFace(family, fallbackMetrics) : void 0;
@@ -11,7 +11,7 @@ import { Plugin } from "vite";
11
11
  * identifiers, falls through to the AST pass.
12
12
  */
13
13
  declare function mayContainVeryDynamicRequest(code: string): boolean;
14
- declare function transformVeryDynamicRequests(code: string, id: string): MagicStringTransformResult | null;
14
+ declare function transformVeryDynamicRequests(code: string, id: string): MagicStringTransformResult<import("magic-string").SourceMap> | null;
15
15
  export declare function createIgnoreDynamicRequestsPlugin(getTranspiledPackages?: () => readonly string[]): Plugin;
16
16
  export declare const _transformVeryDynamicRequests: typeof transformVeryDynamicRequests;
17
17
  export declare const _mayContainVeryDynamicRequest: typeof mayContainVeryDynamicRequest;
@@ -1,7 +1,8 @@
1
- import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
1
+ import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { DYNAMIC_IMPORT_PRESCAN, SCRIPT_MODULE_ID_RE, collectBindingNames, forEachAstChild, isIdentifierNamed, mayContainDynamicImport, scriptParserLanguage, stringLiteralValue, unwrapExpression } from "./ast-utils.js";
3
3
  import { magicStringTransformResult, omitUnusedBuildSourcemap } from "./transform-result.js";
4
4
  import { stripViteModuleQuery } from "../utils/path.js";
5
+ import { isForeignNodeModule } from "../utils/package-name.js";
5
6
  import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, hasAstBinding, isFunctionNode } from "./ast-scope.js";
6
7
  import { createTransformCache } from "./transform-cache.js";
7
8
  import { fileURLToPath } from "node:url";
@@ -543,9 +544,7 @@ function createIgnoreDynamicRequestsPlugin(getTranspiledPackages = () => []) {
543
544
  }
544
545
  function shouldTransformVeryDynamicRequests(environment, id, transpiledPackages) {
545
546
  if (environment.config.consumer === "server") return true;
546
- const normalizedId = toSlash(id);
547
- if (!normalizedId.includes("/node_modules/")) return false;
548
- return !transpiledPackages.some((packageName) => normalizedId.includes(`/node_modules/${packageName}/`));
547
+ return isForeignNodeModule(id, transpiledPackages);
549
548
  }
550
549
  const _transformVeryDynamicRequests = transformVeryDynamicRequests;
551
550
  const _mayContainVeryDynamicRequest = mayContainVeryDynamicRequest;
@@ -29,10 +29,11 @@ import { Plugin } from "vite";
29
29
  * to the tainted set. This propagates the taint along the import graph
30
30
  * synchronously, before plugin-rsc's `order: "pre"` validate-imports
31
31
  * handler sees the next `server-only` request.
32
- * 3. When a tainted module imports `server-only` in a non-RSC environment,
33
- * short-circuit to the no-op shim path so plugin-rsc's filter (which
34
- * matches the bare `^server-only$` specifier) never fires for that
35
- * import.
32
+ * 3. When a tainted module imports `server-only` in a non-RSC server
33
+ * environment, short-circuit to the no-op shim path so plugin-rsc's
34
+ * filter (which matches the bare `^server-only$` specifier) never fires
35
+ * for that import. Browser environments are skipped entirely, so the
36
+ * client `server-only` validators still see every import there.
36
37
  *
37
38
  * The taint set is scoped to the middleware chain only — `server-only`
38
39
  * imports from anywhere else (including client component code traversing
@@ -1,5 +1,6 @@
1
1
  import { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { stripViteModuleQuery } from "../utils/path.js";
3
+ import { isServerEnvironment } from "./environment.js";
3
4
  //#region src/plugins/middleware-server-only.ts
4
5
  /**
5
6
  * Allow `import 'server-only'` from neutral server targets (and any module
@@ -30,10 +31,11 @@ import { stripViteModuleQuery } from "../utils/path.js";
30
31
  * to the tainted set. This propagates the taint along the import graph
31
32
  * synchronously, before plugin-rsc's `order: "pre"` validate-imports
32
33
  * handler sees the next `server-only` request.
33
- * 3. When a tainted module imports `server-only` in a non-RSC environment,
34
- * short-circuit to the no-op shim path so plugin-rsc's filter (which
35
- * matches the bare `^server-only$` specifier) never fires for that
36
- * import.
34
+ * 3. When a tainted module imports `server-only` in a non-RSC server
35
+ * environment, short-circuit to the no-op shim path so plugin-rsc's
36
+ * filter (which matches the bare `^server-only$` specifier) never fires
37
+ * for that import. Browser environments are skipped entirely, so the
38
+ * client `server-only` validators still see every import there.
37
39
  *
38
40
  * The taint set is scoped to the middleware chain only — `server-only`
39
41
  * imports from anywhere else (including client component code traversing
@@ -71,7 +73,8 @@ function createMiddlewareServerOnlyPlugin(options) {
71
73
  resolveId: {
72
74
  order: "pre",
73
75
  async handler(id, importer, opts) {
74
- if (this.environment?.name === "rsc") return;
76
+ const environment = this.environment;
77
+ if (!environment || !isServerEnvironment(environment) || environment.name === "rsc") return;
75
78
  if (!importer) return;
76
79
  if (!isTainted(importer) && !options.isNeutralServerModule?.(canonicalizeId(importer))) return;
77
80
  if (id === "server-only") return {
@@ -1,8 +1,8 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { SCRIPT_MODULE_ID_RE, mayContainDynamicImport, scriptParserLanguage, staticStringValue, walkAst } from "./ast-utils.js";
3
3
  import { canonicalizeFilePath, isPathInsideOrEqual, stripViteModuleQuery } from "../utils/path.js";
4
- import { packageNameFromSpecifier } from "../utils/package-name.js";
5
4
  import { isServerEnvironment } from "./environment.js";
5
+ import { packageNameFromSpecifier } from "../utils/package-name.js";
6
6
  import fs from "node:fs";
7
7
  import { parseAst } from "vite";
8
8
  //#region src/plugins/pages-node-externals.ts
@@ -0,0 +1,19 @@
1
+ import { Plugin, ResolvedConfig } from "vite";
2
+ import { RscPluginManager } from "@vitejs/plugin-rsc";
3
+ //#region src/plugins/rsc-scan-glob-imports.d.ts
4
+ /**
5
+ * @vitejs/plugin-rsc 0.5.36 and 0.5.37 reduce scan-build modules to their
6
+ * import specifiers with es-module-lexer v3, which reports template-literal
7
+ * dynamic imports as glob patterns (``import(`file://${p}`)`` becomes
8
+ * `"file://*"`). The scan then emits them as plain imports, which fail to
9
+ * resolve (e.g. in @module-federation/vite). Other versions skip these
10
+ * specifiers (0.5.38 via vitejs/vite-plugin-react#1506), so for the affected
11
+ * ones keep the specifiers that don't resolve external during the scan. A real
12
+ * module whose specifier contains `*` still resolves and stays in the scan
13
+ * graph. The scan's output is discarded, so nothing else changes.
14
+ */
15
+ export declare function isRscScanGlobImportsAffected(version: string): boolean;
16
+ export declare function createRscScanGlobImportsPlugin(options: {
17
+ getManager: (config: ResolvedConfig) => Promise<RscPluginManager | undefined>;
18
+ }): Plugin;
19
+ //#endregion
@@ -0,0 +1,50 @@
1
+ import { isVersionBelow } from "../utils/react-version.js";
2
+ //#region src/plugins/rsc-scan-glob-imports.ts
3
+ /**
4
+ * @vitejs/plugin-rsc 0.5.36 and 0.5.37 reduce scan-build modules to their
5
+ * import specifiers with es-module-lexer v3, which reports template-literal
6
+ * dynamic imports as glob patterns (``import(`file://${p}`)`` becomes
7
+ * `"file://*"`). The scan then emits them as plain imports, which fail to
8
+ * resolve (e.g. in @module-federation/vite). Other versions skip these
9
+ * specifiers (0.5.38 via vitejs/vite-plugin-react#1506), so for the affected
10
+ * ones keep the specifiers that don't resolve external during the scan. A real
11
+ * module whose specifier contains `*` still resolves and stays in the scan
12
+ * graph. The scan's output is discarded, so nothing else changes.
13
+ */
14
+ function isRscScanGlobImportsAffected(version) {
15
+ return !isVersionBelow(version, [
16
+ 0,
17
+ 5,
18
+ 36
19
+ ]) && isVersionBelow(version, [
20
+ 0,
21
+ 5,
22
+ 38
23
+ ]);
24
+ }
25
+ function createRscScanGlobImportsPlugin(options) {
26
+ return {
27
+ name: "vinext:rsc-scan-glob-imports",
28
+ apply: "build",
29
+ enforce: "pre",
30
+ resolveId: {
31
+ filter: { id: /\*/ },
32
+ async handler(source, importer, resolveOptions) {
33
+ if (!(await options.getManager(this.environment.config))?.isScanBuild) return;
34
+ try {
35
+ const resolved = await this.resolve(source, importer, {
36
+ ...resolveOptions,
37
+ skipSelf: true
38
+ });
39
+ if (resolved) return resolved;
40
+ } catch {}
41
+ return {
42
+ id: source,
43
+ external: true
44
+ };
45
+ }
46
+ }
47
+ };
48
+ }
49
+ //#endregion
50
+ export { createRscScanGlobImportsPlugin, isRscScanGlobImportsAffected };