@wular/pnext 0.1.6 → 0.1.8

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 (337) hide show
  1. package/bin/pnext +9 -2
  2. package/dist/server/_chunks/aliases-pycbtjt1.js +46 -0
  3. package/dist/server/_chunks/analyze-4d9e00g9.js +449 -0
  4. package/dist/server/_chunks/boot-bhemypxz.js +38 -0
  5. package/dist/server/_chunks/build-c991dv65.js +86 -0
  6. package/dist/server/_chunks/build-kh5e3x48.js +3341 -0
  7. package/dist/server/_chunks/build-tier-0a96kmx3.js +2456 -0
  8. package/dist/server/_chunks/compile-040r79gj.js +22 -0
  9. package/dist/server/_chunks/config-0tvz03a6.js +24 -0
  10. package/dist/server/_chunks/config-27rj7830.js +36 -0
  11. package/dist/server/_chunks/create-9rvwshsp.js +135 -0
  12. package/dist/server/_chunks/dev-ex9exynt.js +220 -0
  13. package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
  14. package/dist/server/_chunks/generate-myw9hef7.js +22 -0
  15. package/dist/server/_chunks/index-0r5eqfc7.js +279 -0
  16. package/dist/server/_chunks/index-0yjv5v47.js +105 -0
  17. package/dist/server/_chunks/index-11xpbfej.js +17 -0
  18. package/dist/server/_chunks/index-141vcwk6.js +109 -0
  19. package/dist/server/_chunks/index-1pzm1hdy.js +4130 -0
  20. package/dist/server/_chunks/index-29pq0kax.js +590 -0
  21. package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
  22. package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
  23. package/dist/server/_chunks/index-38xpdxwd.js +194 -0
  24. package/dist/server/_chunks/index-3e075kny.js +128 -0
  25. package/dist/server/_chunks/index-3ycf5ckv.js +472 -0
  26. package/dist/server/_chunks/index-4399bvd2.js +18 -0
  27. package/dist/server/_chunks/index-4da76t62.js +297 -0
  28. package/dist/server/_chunks/index-4t92hdxd.js +172 -0
  29. package/dist/server/_chunks/index-4zzebszd.js +10 -0
  30. package/dist/server/_chunks/index-52k54ykj.js +95 -0
  31. package/dist/server/_chunks/index-5hr4062s.js +70 -0
  32. package/dist/server/_chunks/index-68m3mwbd.js +84 -0
  33. package/dist/server/_chunks/index-6b009mt0.js +56 -0
  34. package/dist/server/_chunks/index-6gex3pfa.js +15 -0
  35. package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
  36. package/dist/server/_chunks/index-6q7zvrap.js +134 -0
  37. package/dist/server/_chunks/index-71885zaq.js +284 -0
  38. package/dist/server/_chunks/index-73z4esab.js +38 -0
  39. package/dist/server/_chunks/index-79ngvam8.js +60 -0
  40. package/dist/server/_chunks/index-7wc9n8be.js +25 -0
  41. package/dist/server/_chunks/index-8ct7rqy3.js +198 -0
  42. package/dist/server/_chunks/index-8kcxdfya.js +206 -0
  43. package/dist/server/_chunks/index-9ch50vtq.js +18 -0
  44. package/dist/server/_chunks/index-9f49w76j.js +213 -0
  45. package/dist/server/_chunks/index-9hz3s0m8.js +851 -0
  46. package/dist/server/_chunks/index-akkrvjn6.js +535 -0
  47. package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
  48. package/dist/server/_chunks/index-b7j671dj.js +207 -0
  49. package/dist/server/_chunks/index-bcws5eh2.js +35 -0
  50. package/dist/server/_chunks/index-bzd2ef7t.js +10 -0
  51. package/dist/server/_chunks/index-cjgqs13g.js +65 -0
  52. package/dist/server/_chunks/index-ckkdpht5.js +41 -0
  53. package/dist/server/_chunks/index-cn86z041.js +296 -0
  54. package/dist/server/_chunks/index-cvr4z22m.js +92 -0
  55. package/dist/server/_chunks/index-cyfednwb.js +87 -0
  56. package/dist/server/_chunks/index-d158y67j.js +152 -0
  57. package/dist/server/_chunks/index-d1jsmhhk.js +955 -0
  58. package/dist/server/_chunks/index-dg0f05zs.js +199 -0
  59. package/dist/server/_chunks/index-dgr390q7.js +9438 -0
  60. package/dist/server/_chunks/index-drwv61cc.js +185 -0
  61. package/dist/server/_chunks/index-e3a6yx84.js +18 -0
  62. package/dist/server/_chunks/index-e88tyv35.js +45 -0
  63. package/dist/server/_chunks/index-en7n9f7m.js +22 -0
  64. package/dist/server/_chunks/index-entm8bmz.js +28 -0
  65. package/dist/server/_chunks/index-evhd413j.js +57 -0
  66. package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
  67. package/dist/server/_chunks/index-fjv96re1.js +5295 -0
  68. package/dist/server/_chunks/index-fn1chkkd.js +214 -0
  69. package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
  70. package/dist/server/_chunks/index-gcmj16xy.js +92 -0
  71. package/dist/server/_chunks/index-gkndxkxf.js +736 -0
  72. package/dist/server/_chunks/index-grta8ap3.js +238 -0
  73. package/dist/server/_chunks/index-h2a70tg4.js +7 -0
  74. package/dist/server/_chunks/index-h4xy648y.js +51 -0
  75. package/dist/server/_chunks/index-hdbwtdv2.js +352 -0
  76. package/dist/server/_chunks/index-he6n2bvp.js +1270 -0
  77. package/dist/server/_chunks/index-j0m1jxqa.js +1253 -0
  78. package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
  79. package/dist/server/_chunks/index-j681c48a.js +2530 -0
  80. package/dist/server/_chunks/index-jbj7ehef.js +50 -0
  81. package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
  82. package/dist/server/_chunks/index-jks0x0a1.js +14 -0
  83. package/dist/server/_chunks/index-jn9rbhrx.js +1599 -0
  84. package/dist/server/_chunks/index-jt8e1pje.js +12 -0
  85. package/dist/server/_chunks/index-kdhxpwyq.js +483 -0
  86. package/dist/server/_chunks/index-knp0s912.js +7 -0
  87. package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
  88. package/dist/server/_chunks/index-kresp2n8.js +445 -0
  89. package/dist/server/_chunks/index-m63czgq5.js +590 -0
  90. package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
  91. package/dist/server/_chunks/index-n4hxpng2.js +11 -0
  92. package/dist/server/_chunks/index-n629dy38.js +1071 -0
  93. package/dist/server/_chunks/index-nf3df4jy.js +266 -0
  94. package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
  95. package/dist/server/_chunks/index-pym1cezq.js +39 -0
  96. package/dist/server/_chunks/index-q3r9z8mq.js +213 -0
  97. package/dist/server/_chunks/index-q738kkhj.js +100 -0
  98. package/dist/server/_chunks/index-qcrvt6er.js +112 -0
  99. package/dist/server/_chunks/index-qjj6gddn.js +54 -0
  100. package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
  101. package/dist/server/_chunks/index-r97ptz1q.js +97 -0
  102. package/dist/server/_chunks/index-ras0sdab.js +26 -0
  103. package/dist/server/_chunks/index-rcs322t1.js +19 -0
  104. package/dist/server/_chunks/index-rgj5mx84.js +101 -0
  105. package/dist/server/_chunks/index-rjegyfx4.js +1435 -0
  106. package/dist/server/_chunks/index-rt9qq1va.js +4 -0
  107. package/dist/server/_chunks/index-rthrsed5.js +356 -0
  108. package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
  109. package/dist/server/_chunks/index-stbk3jhn.js +31 -0
  110. package/dist/server/_chunks/index-tf4j19ge.js +130 -0
  111. package/dist/server/_chunks/index-tgcakdxc.js +125 -0
  112. package/dist/server/_chunks/index-tgsfjmep.js +74 -0
  113. package/dist/server/_chunks/index-tq1f96v7.js +51 -0
  114. package/dist/server/_chunks/index-tq3b39a5.js +107 -0
  115. package/dist/server/_chunks/index-typcbcsv.js +819 -0
  116. package/dist/server/_chunks/index-v1ags1na.js +132 -0
  117. package/dist/server/_chunks/index-vmr35jjw.js +170 -0
  118. package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
  119. package/dist/server/_chunks/index-vz0km5qk.js +33 -0
  120. package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
  121. package/dist/server/_chunks/index-web361b8.js +138 -0
  122. package/dist/server/_chunks/index-wm36rj4v.js +311 -0
  123. package/dist/server/_chunks/index-x0y005nh.js +283 -0
  124. package/dist/server/_chunks/index-x2m17v9c.js +6166 -0
  125. package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
  126. package/dist/server/_chunks/index-x9c55pzy.js +871 -0
  127. package/dist/server/_chunks/index-xh1nbk46.js +1299 -0
  128. package/dist/server/_chunks/index-xvj80c3a.js +30 -0
  129. package/dist/server/_chunks/index-xywjg2vc.js +100 -0
  130. package/dist/server/_chunks/index-y4d02znn.js +66 -0
  131. package/dist/server/_chunks/index-y7mzvq2q.js +110 -0
  132. package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
  133. package/dist/server/_chunks/index-yhxkxghe.js +56 -0
  134. package/dist/server/_chunks/index-yrjkqtfj.js +86 -0
  135. package/dist/server/_chunks/index-z88qv16t.js +11 -0
  136. package/dist/server/_chunks/index-zfrwq472.js +154 -0
  137. package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
  138. package/dist/server/_chunks/loader-5en7wpt5.js +80 -0
  139. package/dist/server/_chunks/modules-t92favpj.js +76 -0
  140. package/dist/server/_chunks/pipeline-4t9q43ht.js +836 -0
  141. package/dist/server/_chunks/production-385bw8df.js +55 -0
  142. package/dist/server/_chunks/proxy-config-60gprphe.js +23 -0
  143. package/dist/server/_chunks/proxy-gfhmktbk.js +35 -0
  144. package/dist/server/_chunks/router-xnrva921.js +501 -0
  145. package/dist/server/_chunks/routes-ht868pdc.js +66 -0
  146. package/dist/server/_chunks/run-d40d63ag.js +697 -0
  147. package/dist/server/_chunks/server-2p8fgqq2.js +1839 -0
  148. package/dist/server/_chunks/tsconfig-defaults-bcn34eqb.js +21 -0
  149. package/dist/server/_chunks/typegen-dvtcjtaw.js +37 -0
  150. package/dist/server/api/client-cache.js +14 -0
  151. package/dist/server/cli/index.js +375 -0
  152. package/dist/server/cli/start.js +158 -0
  153. package/dist/server/client/reference.js +16 -0
  154. package/dist/server/compat/next/cache.js +56 -0
  155. package/dist/server/compat/next/canonical-url.js +13 -0
  156. package/dist/server/compat/next/client-cache.js +57 -0
  157. package/dist/server/compat/next/client-navigation.js +232 -0
  158. package/dist/server/compat/next/client-only.js +1 -0
  159. package/dist/server/compat/next/client-script.js +178 -0
  160. package/dist/server/compat/next/client-server.js +34 -0
  161. package/dist/server/compat/next/config-headers.js +34 -0
  162. package/dist/server/compat/next/config-loader.js +25 -0
  163. package/dist/server/compat/next/config.js +10 -0
  164. package/dist/server/compat/next/constants.js +18 -0
  165. package/dist/server/compat/next/custom-server.js +10 -0
  166. package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
  167. package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
  168. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
  169. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
  170. package/dist/server/compat/next/dynamic.js +21 -0
  171. package/dist/server/compat/next/error.js +112 -0
  172. package/dist/server/compat/next/font/cache.js +16 -0
  173. package/dist/server/compat/next/font/google.js +3 -0
  174. package/dist/server/compat/next/font/index.js +1 -0
  175. package/dist/server/compat/next/font/local.js +24 -0
  176. package/dist/server/compat/next/font/runtime-client.js +33 -0
  177. package/dist/server/compat/next/font/runtime.js +43 -0
  178. package/dist/server/compat/next/font/shared.js +22 -0
  179. package/dist/server/compat/next/form.js +129 -0
  180. package/dist/server/compat/next/head.js +10 -0
  181. package/dist/server/compat/next/headers.js +30 -0
  182. package/dist/server/compat/next/image/client.js +11 -0
  183. package/dist/server/compat/next/image/config.js +18 -0
  184. package/dist/server/compat/next/image/optimizer.js +25 -0
  185. package/dist/server/compat/next/image/patterns.js +12 -0
  186. package/dist/server/compat/next/image/props.js +16 -0
  187. package/dist/server/compat/next/image/shared.js +86 -0
  188. package/dist/server/compat/next/image/static-metadata.js +32 -0
  189. package/dist/server/compat/next/image/validate.js +8 -0
  190. package/dist/server/compat/next/image.js +59 -0
  191. package/dist/server/compat/next/index.js +1 -0
  192. package/dist/server/compat/next/legacy-image.js +78 -0
  193. package/dist/server/compat/next/legacy-request-apis.js +24 -0
  194. package/dist/server/compat/next/link-transform.js +15 -0
  195. package/dist/server/compat/next/link.js +14 -0
  196. package/dist/server/compat/next/navigation.js +191 -0
  197. package/dist/server/compat/next/offline.js +45 -0
  198. package/dist/server/compat/next/og.js +8 -0
  199. package/dist/server/compat/next/preferred-region.js +8 -0
  200. package/dist/server/compat/next/redirects.js +32 -0
  201. package/dist/server/compat/next/resource-hints.js +30 -0
  202. package/dist/server/compat/next/rewrites.js +43 -0
  203. package/dist/server/compat/next/root-params.js +121 -0
  204. package/dist/server/compat/next/route-state.js +23 -0
  205. package/dist/server/compat/next/router.js +103 -0
  206. package/dist/server/compat/next/script.js +37 -0
  207. package/dist/server/compat/next/server-only.js +1 -0
  208. package/dist/server/compat/next/server.js +131 -0
  209. package/dist/server/compat/next/svgr.js +14 -0
  210. package/dist/server/compat/next/telemetry.js +10 -0
  211. package/dist/server/compat/next/usage.js +13 -0
  212. package/dist/server/compat/next/user-agent.js +12 -0
  213. package/dist/server/compat/next/web-vitals.js +35 -0
  214. package/dist/server/compat/react/action-state.js +11 -0
  215. package/dist/server/compat/react/client-lite.js +83 -0
  216. package/dist/server/compat/react/client.js +131 -0
  217. package/dist/server/compat/react/compiler-runtime.js +42 -0
  218. package/dist/server/compat/react/dom-client.js +106 -0
  219. package/dist/server/compat/react/dom-react-server.js +37 -0
  220. package/dist/server/compat/react/dom-server.js +40 -0
  221. package/dist/server/compat/react/dom.js +52 -0
  222. package/dist/server/compat/react/hooks-extra.js +12 -0
  223. package/dist/server/compat/react/internals.js +14 -0
  224. package/dist/server/compat/react/parity.js +11 -0
  225. package/dist/server/compat/react/preact.js +113 -0
  226. package/dist/server/compat/react/react-server.js +133 -0
  227. package/dist/server/compat/react/router-shim.js +8 -0
  228. package/dist/server/compat/react/server-component-use.js +14 -0
  229. package/dist/server/compat/react/server-inserted-html.js +14 -0
  230. package/dist/server/compat/react/server.js +194 -0
  231. package/dist/server/compat/react/style-values.js +10 -0
  232. package/dist/server/compat/react/use.js +10 -0
  233. package/dist/server/compat/react/view-transition.js +12 -0
  234. package/dist/server/generation.json +1 -0
  235. package/package.json +4 -1
  236. package/reference/compat.md +1 -1
  237. package/reference/config.md +2 -2
  238. package/reference/dev.md +1 -1
  239. package/reference/getting-started.md +1 -1
  240. package/reference/rendering.md +4 -4
  241. package/src/api/dynamic.tsx +86 -4
  242. package/src/api/server.ts +24 -6
  243. package/src/cli/adapters/vercel-warm.ts +327 -62
  244. package/src/cli/adapters/vercel.ts +164 -1054
  245. package/src/cli/analyze.ts +3 -2
  246. package/src/cli/build/cache.ts +6 -6
  247. package/src/cli/build.ts +78 -45
  248. package/src/cli/index.ts +21 -3
  249. package/src/cli/serve/immutable.ts +31 -0
  250. package/src/cli/serve/pipeline.ts +97 -93
  251. package/src/cli/serve/standalone-worker.ts +8 -0
  252. package/src/cli/serve/standalone.ts +703 -0
  253. package/src/cli/start.ts +31 -8
  254. package/src/client/build.ts +1 -1
  255. package/src/client/chunk-fold.ts +19 -6
  256. package/src/client/react-tier.ts +3 -2
  257. package/src/client/reference-stub.ts +23 -36
  258. package/src/compat/actions/client-plugin.ts +4 -2
  259. package/src/compat/actions/config.ts +6 -5
  260. package/src/compat/actions/extensions.ts +5 -5
  261. package/src/compat/aliases.ts +8 -1
  262. package/src/compat/bundler/config.ts +88 -0
  263. package/src/compat/bundler/optimize-package-imports.ts +86 -26
  264. package/src/compat/bundler/relay-transform.ts +15 -3
  265. package/src/compat/bundler/require-context.ts +2 -1
  266. package/src/compat/bundler/webpack-loaders.ts +3 -2
  267. package/src/compat/bundler/worker.ts +2 -2
  268. package/src/compat/cache-control.ts +16 -8
  269. package/src/compat/css/inline-css.ts +1 -1
  270. package/src/compat/css/modules.ts +18 -5
  271. package/src/compat/export/build-complete.ts +1 -1
  272. package/src/compat/export/emit.ts +4 -4
  273. package/src/compat/export/standalone.ts +30 -65
  274. package/src/compat/image-optimizer/optimize.ts +1 -1
  275. package/src/compat/lifecycle/error-funnel.ts +1 -1
  276. package/src/compat/lifecycle/instrumentation-client.ts +4 -3
  277. package/src/compat/lifecycle/instrumentation.ts +117 -24
  278. package/src/compat/lifecycle/testmode.ts +3 -2
  279. package/src/compat/metadata-artifacts.ts +1 -1
  280. package/src/compat/next/config-loader.ts +140 -13
  281. package/src/compat/next/dynamic.tsx +10 -23
  282. package/src/compat/next/font/cache.ts +2 -1
  283. package/src/compat/next/font/runtime.ts +23 -3
  284. package/src/compat/next/og.ts +3 -3
  285. package/src/compat/next/usage.ts +3 -2
  286. package/src/compat/pages/api.ts +83 -14
  287. package/src/compat/pages/router.ts +30 -14
  288. package/src/compat/register/bundler.ts +3 -1
  289. package/src/compat/register/image.ts +1 -1
  290. package/src/compat/register/middleware.ts +1 -1
  291. package/src/compat/register/otel.ts +5 -9
  292. package/src/compat/register/render.ts +3 -1
  293. package/src/compat/register/use-cache.ts +3 -1
  294. package/src/compat/release.ts +46 -0
  295. package/src/compat/segment/serve.ts +1 -1
  296. package/src/compat/typecheck/check.ts +6 -4
  297. package/src/compat/validation/validate.ts +10 -7
  298. package/src/config.ts +76 -9
  299. package/src/css/assets.ts +213 -0
  300. package/src/css/build.ts +190 -247
  301. package/src/dev/client-chunk-store.ts +2 -1
  302. package/src/dev/restart/client-key.ts +2 -1
  303. package/src/dev/restart/global-css.ts +2 -1
  304. package/src/dev/restart/route-bundle-key.ts +2 -1
  305. package/src/dev/restart/route-facts.ts +2 -1
  306. package/src/dev/server.ts +34 -14
  307. package/src/extensions.ts +4 -0
  308. package/src/out-paths.ts +10 -0
  309. package/src/render/hooks.ts +13 -0
  310. package/src/render/renderer.ts +53 -33
  311. package/src/request/context.ts +9 -0
  312. package/src/resolve/dynamic.ts +7 -1
  313. package/src/resolve/engine.ts +2 -12
  314. package/src/resolve/imports.ts +12 -52
  315. package/src/resolve/package-json.ts +56 -0
  316. package/src/resolve/scan-facts.ts +250 -1
  317. package/src/routing/href.ts +10 -3
  318. package/src/routing/match.ts +287 -0
  319. package/src/routing/metadata-files.ts +20 -6
  320. package/src/routing/proxy-config.ts +137 -0
  321. package/src/routing/proxy.ts +35 -134
  322. package/src/routing/routes.ts +22 -281
  323. package/src/runtime/fingerprint.ts +23 -8
  324. package/src/runtime/load.ts +170 -0
  325. package/src/runtime/loader.ts +218 -44
  326. package/src/runtime/module-cache.ts +15 -1
  327. package/src/runtime/modules.ts +405 -82
  328. package/src/runtime/prebundle.ts +101 -0
  329. package/src/runtime/production.ts +456 -0
  330. package/src/runtime/release-graph.ts +342 -0
  331. package/src/runtime/vendor-build.ts +750 -17
  332. package/src/runtime/vendor.ts +16 -3
  333. package/src/types.ts +4 -3
  334. package/src/utils/directive.ts +40 -0
  335. package/src/utils/fs.ts +95 -4
  336. package/src/utils/resource-query.ts +12 -0
  337. package/src/cli/serve/entry.ts +0 -45
@@ -1,7 +1,7 @@
1
1
  import { builtinModules } from 'node:module'
2
2
  import os from 'node:os'
3
3
  import path from 'node:path'
4
- import { existsSync, readFileSync, type Dirent } from 'node:fs'
4
+ import { existsSync, readFileSync, readdirSync, realpathSync, statSync, type Dirent } from 'node:fs'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { copyFile, mkdir, readdir, readlink, rm, symlink, writeFile } from 'node:fs/promises'
7
7
  import type { OnResolveResult, Plugin } from 'esbuild'
@@ -23,7 +23,13 @@ import {
23
23
  serverBundleRequireConditions,
24
24
  type ServerBundleTarget,
25
25
  } from './loader'
26
- import { externalServerPackageHref, runtimeServerImportTarget } from '../runtime/vendor-build'
26
+ import {
27
+ clearReleaseDependencyLog,
28
+ externalServerPackageHref,
29
+ noteReleaseModuleLayer,
30
+ runtimeServerImportTarget,
31
+ type ReleaseDependencyLayer,
32
+ } from '../runtime/vendor-build'
27
33
  import { writeFileAtomic } from '../utils/fs'
28
34
  import { traceEnabled, traceValue } from '../utils/trace-flags'
29
35
  import { createHash } from 'node:crypto'
@@ -55,9 +61,12 @@ import {
55
61
  resolvePackageSpecifier,
56
62
  } from '../resolve/imports'
57
63
  import {
64
+ absolutePathLiterals,
58
65
  importSpecifiers,
66
+ lineComments,
59
67
  moduleSpecifierEdges,
60
68
  rewriteSpecifierLiterals,
69
+ stripJsonImportAttributes,
61
70
  } from '../resolve/scan-facts'
62
71
  import {
63
72
  cacheRoot,
@@ -76,7 +85,20 @@ import {
76
85
  transformServerModule,
77
86
  type SpecifierKind,
78
87
  } from './module-transform'
88
+ import { splitResourceQuery } from '../resolve/engine'
79
89
  import { findShakeableDynamicImports } from '../resolve/tree-shake'
90
+ import { productionRelease, releaseModuleHref } from './production'
91
+ import {
92
+ clearModuleGraphFailure,
93
+ forgetModuleEvalError,
94
+ importModuleOnce,
95
+ isReleaseCompile,
96
+ noteModuleGraphFailure,
97
+ setReleaseCompileFlag,
98
+ throwIfModuleEvalFailed,
99
+ } from './load'
100
+
101
+ export { importModuleOnce, isReleaseCompile, throwIfModuleGraphFailed } from './load'
80
102
  import type { RouteManifestEntry } from '../types'
81
103
  import { uniqueIdentifier } from '../utils/code'
82
104
  import { formatDuration } from '../utils/verbose'
@@ -114,37 +136,13 @@ const routeBundleBuilds = new Map<string, Promise<string>>()
114
136
  // present during an earlier check. This avoids repeated reads/parses without
115
137
  // turning one observation into a permanent claim that the closure still exists.
116
138
  const completeArtifactClosures = new Map<string, readonly string[]>()
117
- let moduleGraphFailure: Error | undefined
118
139
 
119
140
  /** Reset build-only graph state before starting another build in this process. */
120
141
  export function resetModuleGraphFailure(): void {
121
- moduleGraphFailure = undefined
142
+ clearModuleGraphFailure()
122
143
  completeArtifactClosures.clear()
123
144
  }
124
145
 
125
- /**
126
- * Fail a build even when its renderer converted a module-resolution exception
127
- * into a 500 response. Rendering may recover from user-code errors, but a
128
- * missing content-addressed artifact means the build output itself is broken.
129
- */
130
- export function throwIfModuleGraphFailed(): void {
131
- if (moduleGraphFailure !== undefined) throw moduleGraphFailure
132
- }
133
-
134
- function noteModuleGraphFailure(error: unknown): void {
135
- moduleGraphFailure ??= error instanceof Error ? error : new Error(String(error))
136
- }
137
-
138
- function isCompiledModuleResolutionError(error: unknown, href: string): boolean {
139
- const message = error instanceof Error ? error.message : String(error)
140
- if (!message.includes('Cannot find module')) return false
141
- return (
142
- href.includes('/cache/server/') ||
143
- /[/\\]cache[/\\]server[/\\]/.test(message) ||
144
- message.includes('/cache/server/')
145
- )
146
- }
147
-
148
146
  // PNEXT_TRACE=server: attribute every per-module compile to its profile,
149
147
  // so cross-profile duplicate work is countable rather than inferred. Counts are
150
148
  // load-insensitive, which is what makes them usable on a contended box.
@@ -222,35 +220,10 @@ function reportModuleStats() {
222
220
  }
223
221
  const routeModuleLoaders = new Map<string, Promise<DevRouteModuleLoaders>>()
224
222
 
225
- // A module that throws while evaluating stays failed in Bun's registry for the process lifetime, and
226
- // re-importing it surfaces downstream symptoms (a missing bundle entry, TDZ on an export) instead of
227
- // the original error. Record the first failure per compiled href and re-throw THAT on every later
228
- // request. Compiled hrefs are content-addressed, so a save that fixes the module yields a new href
229
- // and the entry is never consulted again.
230
- const moduleEvalErrors = new Map<string, unknown>()
231
223
  const warmRetryHrefs = new Map<string, Promise<string>>()
232
224
  const warmImports = new Map<string, Promise<void>>()
233
225
  let warmRetryGeneration = 0
234
226
 
235
- /**
236
- * Import a compiled module, re-throwing its first evaluation error on later imports.
237
- *
238
- * Production needs this as much as dev: a re-import resolves with a half-evaluated namespace whose
239
- * `export const` bindings are still in TDZ, so the render's next read (`module.metadata`) throws
240
- * `Cannot access 'metadata' before initialization` and that replaces the real error in the response.
241
- * Prod hrefs are content-addressed too, so the entry keys the same way dev's does.
242
- */
243
- export async function importModuleOnce<T>(href: string): Promise<T> {
244
- if (moduleEvalErrors.has(href)) throw moduleEvalErrors.get(href)
245
- try {
246
- return (await import(href)) as T
247
- } catch (error) {
248
- if (isCompiledModuleResolutionError(error, href)) noteModuleGraphFailure(error)
249
- moduleEvalErrors.set(href, error)
250
- throw error
251
- }
252
- }
253
-
254
227
  interface ImportDevModuleOptions {
255
228
  /** A speculative import whose evaluation failure must not become render state. */
256
229
  warm?: boolean
@@ -298,7 +271,7 @@ export async function importDevModule<T>(
298
271
  let attemptedEvaluation = false
299
272
  try {
300
273
  importHref = (await warmRetryHrefs.get(href)) ?? href
301
- if (moduleEvalErrors.has(importHref)) throw moduleEvalErrors.get(importHref)
274
+ throwIfModuleEvalFailed(importHref)
302
275
  // Pre-planned vendor builds are enqueued without an awaiter; nothing
303
276
  // evaluates until they all settle (no-op when the pipeline is empty).
304
277
  await drainPreplanBuilds()
@@ -312,7 +285,7 @@ export async function importDevModule<T>(
312
285
  // the real render a fresh module identity, so speculative work can never poison the request.
313
286
  const retryHref = nextWarmRetryHref(href)
314
287
  warmRetryHrefs.set(href, retryHref)
315
- if (moduleEvalErrors.get(importHref) === error) moduleEvalErrors.delete(importHref)
288
+ forgetModuleEvalError(importHref, error)
316
289
  await retryHref
317
290
  }
318
291
  throw error
@@ -338,6 +311,7 @@ const moduleCaches = new WeakMap<ResolvedConfig, DevModuleCache>()
338
311
  export function devModuleGraph(config: ResolvedConfig): DevModuleCache {
339
312
  const existing = moduleCaches.get(config)
340
313
  if (existing) return existing
314
+ if (isReleaseCompile()) releaseAnchors.set(cacheRoot(config.outPath), portableAnchors(config))
341
315
  const cache = devModuleCache(config, {
342
316
  compileKey: devCompileKey(config),
343
317
  edges: (file, source) => graphEdges(config, file, source),
@@ -429,6 +403,14 @@ function devAliasKeys(config: ResolvedConfig) {
429
403
  return keys
430
404
  }
431
405
 
406
+ /** The out dir is compiled output, save the pages sources a build materializes into it. */
407
+ function isCompiledOutput(config: ResolvedConfig, file: string) {
408
+ return (
409
+ isInside(config.outPath, file) &&
410
+ !isInside(path.join(config.outRootPath, 'pnext-pages-compat'), file)
411
+ )
412
+ }
413
+
432
414
  /**
433
415
  * Source edges the graph hash follows. A superset of the compiled graph is safe - it only widens what
434
416
  * a save invalidates - but a subset would leave a dependent holding a name that no longer describes
@@ -444,7 +426,7 @@ function graphEdges(config: ResolvedConfig, file: string, source: string) {
444
426
  const resolved = resolveLocalImport(config, file, sourcePath.replace(/\?.*$/, ''))
445
427
  const isLocalSource = sourcePath.startsWith('.') || path.isAbsolute(sourcePath)
446
428
  // Compiled output is never a source of the graph that produced it.
447
- if (resolved && isInside(config.outPath, resolved)) continue
429
+ if (resolved && isCompiledOutput(config, resolved)) continue
448
430
  if (resolved && (isLocalSource || isInside(config.workspaceRoot, resolved))) {
449
431
  imports.push(path.resolve(resolved))
450
432
  continue
@@ -547,6 +529,9 @@ export async function devServerModuleHref(
547
529
  _version?: string,
548
530
  moduleOptions: DevServerModuleOptions = {},
549
531
  ) {
532
+ const served = productionRelease(config)
533
+ if (served)
534
+ return releaseModuleHref(served, 'server', moduleOptions.conditionTarget ?? 'server', file)
550
535
  const conditionTarget = pagesLayerConditionTarget(
551
536
  config,
552
537
  file,
@@ -585,6 +570,8 @@ export async function devClientModuleHref(
585
570
  _version?: string,
586
571
  serverTarget?: ServerBundleTarget,
587
572
  ) {
573
+ const served = productionRelease(config)
574
+ if (served) return releaseModuleHref(served, 'client', serverTarget ?? 'server', file)
588
575
  const conditionTarget = clientLayerConditionTarget(config, file, serverTarget ?? 'server')
589
576
  const throughPackage = await packageClientModuleHref(config, file, conditionTarget)
590
577
  if (throughPackage) return throughPackage
@@ -1414,30 +1401,284 @@ export function setEmitCompiledSpecifiersManifest(enabled: boolean) {
1414
1401
  }
1415
1402
  }
1416
1403
 
1404
+ // A production build compiles for its release: `.js` artifact names, one asset-context link per
1405
+ // directory, core CSS module class maps. Dev keeps its own compile.
1406
+ // A build's sources do not change under it, so each directory's asset context links once; dev relinks.
1407
+ const linkedAssetContexts = new Map<string, Promise<void>>()
1408
+
1409
+ /** @internal The build sets this for its own duration. Returns a restore function. */
1410
+ export function setReleaseCompile(enabled: boolean) {
1411
+ const previous = isReleaseCompile()
1412
+ setReleaseCompileFlag(enabled)
1413
+ // Each build starts from an emptied out dir, so nothing linked or stubbed before still stands.
1414
+ linkedAssetContexts.clear()
1415
+ assetStubs.clear()
1416
+ releaseAnchors.clear()
1417
+ packageCandidates.clear()
1418
+ packageSpecifiers.clear()
1419
+ clearReleaseDependencyLog()
1420
+ return () => setReleaseCompileFlag(previous)
1421
+ }
1422
+
1417
1423
  /** Sidecar suffix for a compiled artifact's recorded specifiers. */
1418
1424
  export const compiledSpecifiersManifestSuffix = '.pnext-specifiers.json'
1419
1425
 
1420
1426
  const compiledScriptFilePattern = /\.(?:m?js|cjs|jsx|tsx?)$/
1421
1427
 
1428
+ /** Where a release may move with its app: the root, its node_modules links, the workspace. */
1429
+ interface PortableAnchors {
1430
+ roots: string[]
1431
+ /** Real directory -> the logical path the app's node_modules names it by. */
1432
+ links: Map<string, string>
1433
+ }
1434
+
1435
+ const releaseAnchors = new Map<string, PortableAnchors>()
1436
+
1437
+ function portableAnchors(config: ResolvedConfig): PortableAnchors {
1438
+ const links = new Map<string, string>()
1439
+ const link = (logical: string) => {
1440
+ try {
1441
+ const real = realpathSync(logical)
1442
+ if (real !== logical && !links.has(real)) links.set(real, logical)
1443
+ } catch {
1444
+ // A dangling entry links nothing.
1445
+ }
1446
+ }
1447
+ const nodeModules = path.join(config.root, 'node_modules')
1448
+ link(nodeModules)
1449
+ for (const name of listDirectory(nodeModules)) {
1450
+ const entry = path.join(nodeModules, name)
1451
+ if (name.startsWith('@'))
1452
+ for (const scoped of listDirectory(entry)) link(path.join(entry, scoped))
1453
+ else link(entry)
1454
+ }
1455
+ return { roots: [config.root, config.workspaceRoot], links }
1456
+ }
1457
+
1458
+ function listDirectory(dir: string) {
1459
+ try {
1460
+ return readdirSync(dir)
1461
+ } catch {
1462
+ return []
1463
+ }
1464
+ }
1465
+
1466
+ /**
1467
+ * Rewrite `file://` URLs in compiled output relative to `file`: import specifiers become relative
1468
+ * specifiers, and (for a release) inlined URL literals become `new URL(<relative>, import.meta.url)`.
1469
+ * `locate` maps an absolute target to the path to link, or undefined to leave it. A release names an
1470
+ * installed package file by the bare specifier that resolves back to it, so the serving install wins.
1471
+ */
1472
+ function relocateSource(
1473
+ file: string,
1474
+ contents: string,
1475
+ locate: (absolute: string) => string | undefined,
1476
+ installed: (absolute: string) => boolean = () => false,
1477
+ ) {
1478
+ const relativeTo = (target: string) => {
1479
+ const relative = toPosixPath(path.relative(path.dirname(file), target))
1480
+ return relative.startsWith('.') ? relative : `./${relative}`
1481
+ }
1482
+ const edits: { start: number; end: number; value: string }[] = []
1483
+ for (const found of outputSpecifiers(contents)) {
1484
+ const { sourcePath, hash } = splitHash(found.value)
1485
+ const url = sourcePath.startsWith('file://')
1486
+ // A release also re-links plain absolute specifiers (a bundled `require('/abs/path')`).
1487
+ if (!url && !(isReleaseCompile() && path.isAbsolute(sourcePath))) continue
1488
+ const absolute = url ? fileURLToPath(sourcePath) : sourcePath
1489
+ const target = locate(absolute)
1490
+ const bare = isReleaseCompile() && installed(absolute) && packageSpecifier(file, absolute)
1491
+ const value = bare || (target && relativeTo(target))
1492
+ if (!value) continue
1493
+ const query = url ? new URL(sourcePath).search : ''
1494
+ edits.push({
1495
+ start: found.start,
1496
+ end: found.end,
1497
+ value: JSON.stringify(`${value}${query}${hash}`),
1498
+ })
1499
+ }
1500
+ const specifiers = spliceSource(contents, edits)
1501
+ if (!isReleaseCompile()) return specifiers
1502
+ // Path literals (client-reference targets, module URLs) resolve beside the artifact at runtime.
1503
+ const expression = (value: string) => {
1504
+ const url = value.startsWith('file:')
1505
+ const target = locate(url ? fileURLToPath(value) : value)
1506
+ if (!target) return undefined
1507
+ const href = `new URL(${JSON.stringify(relativeTo(target))}, import.meta.url)`
1508
+ return url ? `${href}.href` : `decodeURIComponent(${href}.pathname)`
1509
+ }
1510
+ const literals = absolutePathLiterals(file, specifiers)
1511
+ if (!literals) {
1512
+ // A recovered parse: the textual form, double-quoted literals only.
1513
+ return specifiers.replace(
1514
+ /(?<!\\)"((?:file:\/\/)?\/[^"\\\n]+)"(\s*:)?/g,
1515
+ (literal, value: string, key: string | undefined) => {
1516
+ const replacement = expression(value)
1517
+ if (!replacement) return literal
1518
+ return key ? `[${replacement}]${key}` : replacement
1519
+ },
1520
+ )
1521
+ }
1522
+ return spliceSource(
1523
+ specifiers,
1524
+ literals.flatMap(literal => {
1525
+ const replacement = expression(literal.value)
1526
+ if (!replacement) return []
1527
+ return [
1528
+ {
1529
+ start: literal.start,
1530
+ end: literal.end,
1531
+ value: literal.key ? `[${replacement}]` : replacement,
1532
+ },
1533
+ ]
1534
+ }),
1535
+ )
1536
+ }
1537
+
1538
+ const isInstalled = (file: string) => file.includes(`${path.sep}node_modules${path.sep}`)
1539
+ const packageCandidates = new Map<string, string | null>()
1540
+ const packageSpecifiers = new Map<string, boolean>()
1541
+
1542
+ /** The bare specifier that resolves from `from` back to installed `file`, if one does. */
1543
+ function packageSpecifier(from: string, file: string) {
1544
+ const candidate = packageCandidate(file)
1545
+ // One miss settles it: the fallback path is always correct, only less portable.
1546
+ if (!candidate || packageSpecifiers.get(candidate) === false) return undefined
1547
+ const key = `${path.dirname(from)}\0${candidate}`
1548
+ let resolves = packageSpecifiers.get(key)
1549
+ if (resolves === undefined) {
1550
+ try {
1551
+ resolves = realpathSync(Bun.resolveSync(candidate, path.dirname(from))) === realpathSync(file)
1552
+ } catch {
1553
+ resolves = false
1554
+ }
1555
+ packageSpecifiers.set(key, resolves)
1556
+ if (!resolves) packageSpecifiers.set(candidate, false)
1557
+ }
1558
+ return resolves ? candidate : undefined
1559
+ }
1560
+
1561
+ /** How installed `file` is named bare: the exports subpath that targets it, else its deep path. */
1562
+ function packageCandidate(file: string) {
1563
+ let candidate = packageCandidates.get(file)
1564
+ if (candidate !== undefined) return candidate
1565
+ candidate = null
1566
+ const packageDir = nodeModulesPackageDir(file)
1567
+ const name = packageDir && packageNameOfDirectory(packageDir)
1568
+ if (packageDir && name) {
1569
+ const subpath = `./${toPosixPath(path.relative(packageDir, file))}`
1570
+ const exports = packageExportsMap(packageDir)
1571
+ if (!exports) candidate = `${name}/${subpath.slice(2)}`
1572
+ for (const [key, value] of Object.entries(exports ?? {})) {
1573
+ if (key.includes('*') || !exportTargets(value).includes(subpath)) continue
1574
+ candidate = key === '.' ? name : `${name}/${key.slice(2)}`
1575
+ break
1576
+ }
1577
+ }
1578
+ packageCandidates.set(file, candidate)
1579
+ return candidate
1580
+ }
1581
+
1582
+ /** A package's exports as a subpath map (`"."` for a bare entry), or undefined when it has none. */
1583
+ function packageExportsMap(packageDir: string): Record<string, unknown> | undefined {
1584
+ try {
1585
+ const { exports } = JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')) as {
1586
+ exports?: unknown
1587
+ }
1588
+ if (exports === undefined || exports === null) return undefined
1589
+ if (typeof exports !== 'object' || Array.isArray(exports)) return { '.': exports }
1590
+ return Object.keys(exports).some(key => key.startsWith('.'))
1591
+ ? (exports as Record<string, unknown>)
1592
+ : { '.': exports }
1593
+ } catch {
1594
+ return undefined
1595
+ }
1596
+ }
1597
+
1598
+ function exportTargets(value: unknown): string[] {
1599
+ if (typeof value === 'string') return [value]
1600
+ if (Array.isArray(value)) return value.flatMap(exportTargets)
1601
+ return value && typeof value === 'object' ? Object.values(value).flatMap(exportTargets) : []
1602
+ }
1603
+
1604
+ /** A release bundle emitted outside the module graph, rewritten to reach its targets relatively. */
1605
+ export function relocateReleaseBundle(config: ResolvedConfig, file: string, contents: string) {
1606
+ const anchors = portableAnchors(config)
1607
+ return relocateSource(file, contents, absolute => portableTarget(anchors, absolute), isInstalled)
1608
+ }
1609
+
1610
+ /** A release artifact written outside writeCompiledFile (vendor bundles), re-linked like one. */
1611
+ export function releaseArtifactSource(file: string, contents: string) {
1612
+ if (!isReleaseCompile()) return contents
1613
+ const cacheRoot = [...releaseAnchors.keys()].find(root => isInside(root, file))
1614
+ const anchors = cacheRoot && releaseAnchors.get(cacheRoot)
1615
+ if (!cacheRoot || !anchors) return contents
1616
+ return relocateSource(
1617
+ file,
1618
+ releaseInputComments(file, contents),
1619
+ absolute => (isInside(cacheRoot, absolute) ? absolute : portableTarget(anchors, absolute)),
1620
+ absolute => !isInside(cacheRoot, absolute) && isInstalled(absolute),
1621
+ )
1622
+ }
1623
+
1624
+ /**
1625
+ * esbuild's per-input `// <path>` comments, cut to the file name (or its `node_modules/` path, which
1626
+ * names a vendored font caller): their paths walk the build machine.
1627
+ */
1628
+ function releaseInputComments(file: string, contents: string) {
1629
+ const shorten = (comment: string) => {
1630
+ const installed = comment.indexOf('node_modules/')
1631
+ return `// ${installed === -1 ? path.basename(comment) : comment.slice(installed)}`
1632
+ }
1633
+ const inputPath = /^ (?:[\w-]+:)?\.{0,2}\/\S*$/
1634
+ const comments = lineComments(file, contents)
1635
+ // A recovered parse: the textual form, whole lines only.
1636
+ if (!comments) return contents.replace(/^\/\/ (?:[\w-]+:)?\.{0,2}\/[^\s]*$/gm, shorten)
1637
+ return spliceSource(
1638
+ contents,
1639
+ comments
1640
+ .filter(comment => inputPath.test(comment.value))
1641
+ .map(comment => ({ ...comment, value: shorten(`//${comment.value}`) })),
1642
+ )
1643
+ }
1644
+
1645
+ /** `target` as a path a moved release still reaches: through the app's own tree, never the machine's. */
1646
+ function portableTarget(anchors: PortableAnchors, target: string) {
1647
+ if (anchors.roots.some(root => isInside(root, target))) return target
1648
+ // Nearest linked ancestor first, so a package link wins over the node_modules link that holds it.
1649
+ for (let dir = path.dirname(target); dir !== path.dirname(dir); dir = path.dirname(dir)) {
1650
+ const logical = anchors.links.get(dir)
1651
+ if (logical) return path.join(logical, path.relative(dir, target))
1652
+ }
1653
+ return undefined
1654
+ }
1655
+
1656
+ const compiledJsonModule = /\.json\.js(?:[?#]|$)/
1657
+
1422
1658
  async function writeCompiledFile(file: string, contents: string) {
1423
1659
  const profileRoot = compiledArtifactProfileRoot(file)
1424
- if (profileRoot && contents.includes('file://')) {
1660
+ const anchors =
1661
+ profileRoot && isReleaseCompile() ? releaseAnchors.get(path.dirname(profileRoot)) : undefined
1662
+ if (
1663
+ profileRoot &&
1664
+ (anchors
1665
+ ? /["'](?:file:\/\/)?\/|^\/\/ (?:[\w-]+:)?\.{0,2}\//m.test(contents)
1666
+ : contents.includes('file://'))
1667
+ ) {
1425
1668
  const cacheRoot = path.dirname(profileRoot)
1426
- const edits: { start: number; end: number; value: string }[] = []
1427
- for (const found of outputSpecifiers(contents)) {
1428
- const { sourcePath, hash } = splitHash(found.value)
1429
- if (!sourcePath.startsWith('file://')) continue
1430
- const target = fileURLToPath(sourcePath)
1431
- if (!isInside(cacheRoot, target)) continue
1432
- const relative = toPosixPath(path.relative(path.dirname(file), target))
1433
- edits.push({
1434
- start: found.start,
1435
- end: found.end,
1436
- value: JSON.stringify(`${relative.startsWith('.') ? relative : `./${relative}`}${hash}`),
1437
- })
1438
- }
1439
- contents = spliceSource(contents, edits)
1669
+ contents = relocateSource(
1670
+ file,
1671
+ anchors ? releaseInputComments(file, contents) : contents,
1672
+ absolute =>
1673
+ isInside(cacheRoot, absolute) ? absolute : anchors && portableTarget(anchors, absolute),
1674
+ absolute => !isInside(cacheRoot, absolute) && isInstalled(absolute),
1675
+ )
1440
1676
  }
1677
+ // A compiled `.json.js` is JS: a release loads it natively, where `type: "json"` would parse it as JSON.
1678
+ if (anchors && contents.includes('.json.js'))
1679
+ contents = stripJsonImportAttributes(contents, file, specifier =>
1680
+ compiledJsonModule.test(specifier),
1681
+ )
1441
1682
  await writeFileAtomic(file, contents)
1442
1683
  noteDevArtifactWritten(file)
1443
1684
  if (emitCompiledSpecifiersManifest && compiledScriptFilePattern.test(file)) {
@@ -1497,7 +1738,7 @@ function missingCompiledArtifact(entry: string): string | undefined {
1497
1738
  try {
1498
1739
  target = sourcePath.startsWith('file://')
1499
1740
  ? fileURLToPath(sourcePath)
1500
- : path.resolve(path.dirname(file), sourcePath)
1741
+ : path.resolve(path.dirname(file), splitResourceQuery(sourcePath).path)
1501
1742
  } catch {
1502
1743
  return sourcePath
1503
1744
  }
@@ -1668,6 +1909,9 @@ async function writeDevModuleUncached(
1668
1909
  clientLayerConditionTarget(config, file, options.conditionTarget),
1669
1910
  )
1670
1911
  : options
1912
+ if (effectiveOptions !== options) {
1913
+ noteReleaseModuleLayer(config, outFile, 'client', effectiveOptions.conditionTarget)
1914
+ }
1671
1915
  // The asset-context link walk is pure I/O against directories nothing below
1672
1916
  // reads, so it overlaps the shaking/scan/child-compile work and is only
1673
1917
  // awaited before the write.
@@ -2212,7 +2456,7 @@ async function assetStubModule(config: ResolvedConfig, resolved: string, profile
2212
2456
  if (existing) return existing
2213
2457
  const next = (async () => {
2214
2458
  const contents =
2215
- getCssExtensions().loadCssModuleForClient(resolved) ??
2459
+ (await serverCssModuleSource(config, resolved)) ??
2216
2460
  (isCssFile(base)
2217
2461
  ? ''
2218
2462
  : isStaticImageFile(base)
@@ -2309,7 +2553,7 @@ function serverAssetPlugin(config: ResolvedConfig): Plugin {
2309
2553
  build.onLoad({ filter: /.*/, namespace: serverAssetNamespace }, async args => {
2310
2554
  // Registry-provided CSS modules (e.g. *.module.scss) export their class
2311
2555
  // map on the server instead of the empty-asset stub.
2312
- const cssModule = getCssExtensions().loadCssModuleForClient(args.path)
2556
+ const cssModule = await serverCssModuleSource(config, args.path)
2313
2557
  return {
2314
2558
  contents:
2315
2559
  cssModule ??
@@ -2347,7 +2591,7 @@ async function resolveDevModuleSpecifier(
2347
2591
  if (
2348
2592
  options.stubClientImports &&
2349
2593
  !isCssFile(target) &&
2350
- !isInside(config.outPath, target) &&
2594
+ !isCompiledOutput(config, target) &&
2351
2595
  existsSync(target) &&
2352
2596
  (await fileHasUseClientDirective(target))
2353
2597
  ) {
@@ -2374,6 +2618,23 @@ async function resolveDevModuleSpecifier(
2374
2618
 
2375
2619
  const { sourcePath, hash } = splitHash(specifier)
2376
2620
 
2621
+ // A release compiles an unclaimed `?query` import's base module; the query keeps its own instance.
2622
+ const queried = splitResourceQuery(sourcePath)
2623
+ if (
2624
+ isReleaseCompile() &&
2625
+ queried.query &&
2626
+ sourcePath.startsWith('.') &&
2627
+ compiledScriptFilePattern.test(queried.path)
2628
+ ) {
2629
+ const from = importer && !importer.startsWith('<') ? importer : file
2630
+ const base = resolveImport(config.root, from, queried.path, config.workspaceRoot)
2631
+ if (base && isInside(config.workspaceRoot, base)) {
2632
+ await writeDevModule(config, base, visited, options)
2633
+ const href = pathToFileHref(await devModulePath(config, base, options))
2634
+ return { path: `${href}${queried.query}${hash}`, external: true }
2635
+ }
2636
+ }
2637
+
2377
2638
  const compatAlias =
2378
2639
  pagesCompatSourceAlias(config, specifier, importer, options) ?? options.aliases[specifier]
2379
2640
  if (compatAlias) {
@@ -2893,7 +3154,7 @@ function localImportTargets(
2893
3154
  // vendor bundle) are already compiled modules Bun imports directly. Feeding one back through the
2894
3155
  // pipeline compiles it a SECOND time, splitting module identity and pulling artifact names into the
2895
3156
  // source graph, where every boot's fresh names look like edits.
2896
- if (resolved && !isInside(config.outPath, resolved)) {
3157
+ if (resolved && !isCompiledOutput(config, resolved)) {
2897
3158
  targets.push({
2898
3159
  target: resolved,
2899
3160
  isLocalSource: sourcePath.startsWith('.') || path.isAbsolute(sourcePath),
@@ -2941,9 +3202,20 @@ async function writeClientReferenceModules(
2941
3202
  return { specifiers, files }
2942
3203
  }
2943
3204
 
3205
+ /** How a release's stub names its source portably (see ClientReferenceModuleOptions.portable). */
3206
+ function portableReference(file: string, sourceFile: string) {
3207
+ const profileRoot = compiledArtifactProfileRoot(file)
3208
+ const anchors = isReleaseCompile() && profileRoot && releaseAnchors.get(path.dirname(profileRoot))
3209
+ const target = anchors && portableTarget(anchors, sourceFile)
3210
+ return target ? { portable: { from: file, target, real: target !== sourceFile } } : {}
3211
+ }
3212
+
2944
3213
  async function writeClientReferenceModule(file: string, sourceFile: string, exportNames: string[]) {
2945
3214
  await mkdir(path.dirname(file), { recursive: true })
2946
- await writeCompiledFile(file, clientReferenceModuleSource(sourceFile, exportNames))
3215
+ await writeCompiledFile(
3216
+ file,
3217
+ clientReferenceModuleSource(sourceFile, exportNames, portableReference(file, sourceFile)),
3218
+ )
2947
3219
  }
2948
3220
 
2949
3221
  async function fileHasUseClientDirective(file: string) {
@@ -2964,6 +3236,20 @@ function isInside(root: string, file: string) {
2964
3236
  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
2965
3237
  }
2966
3238
 
3239
+ /** Where an App Router layer's release modules compile to. */
3240
+ export function releaseLayerArtifactDir(config: ResolvedConfig, layer: ReleaseDependencyLayer) {
3241
+ const profile =
3242
+ layer === 'client:client'
3243
+ ? devModuleProfile(clientLayerOptions(config))
3244
+ : devModuleProfile({
3245
+ profile: 'compat',
3246
+ conditionTarget: 'server',
3247
+ externalLoadTarget: externalLoadTargetForConditionTarget('server'),
3248
+ reactServerLayer: true,
3249
+ } as DevModuleOptions)
3250
+ return path.join(cacheRoot(config.outPath), `modules-${profile}`)
3251
+ }
3252
+
2967
3253
  function devModuleProfile(options: DevModuleOptions) {
2968
3254
  if (options.profile === 'client') {
2969
3255
  // Pages-router SSR layers ('pages'/'pages-edge') resolve package exports
@@ -2989,7 +3275,13 @@ function devServerPath(config: ResolvedConfig, file: string, profile: string, ha
2989
3275
  // A compiled `.json` module is JS (esbuild's json loader wraps it in exports),
2990
3276
  // so it must not keep the `.json` name — the runtime would parse the artifact
2991
3277
  // as JSON. Keeping the source name in front of `.js` keeps it collision-free.
2992
- const outExt = ext === '.json' ? '.json.js' : ext
3278
+ // Build output names compiled scripts `.js`, so production imports them without a TS/MDX loader.
3279
+ const outExt =
3280
+ ext === '.json'
3281
+ ? '.json.js'
3282
+ : isReleaseCompile() && /\.(?:[jt]sx?|mdx?)$/.test(ext)
3283
+ ? '.js'
3284
+ : ext
2993
3285
  return path.join(
2994
3286
  cacheRoot(config.outPath),
2995
3287
  profile === 'server' ? 'modules' : `modules-${profile}`,
@@ -3082,6 +3374,15 @@ function isCssFile(file: string) {
3082
3374
  return file.endsWith('.css')
3083
3375
  }
3084
3376
 
3377
+ /** A CSS module's class map as a build's server output imports it; core's plain CSS modules map here. */
3378
+ async function serverCssModuleSource(config: ResolvedConfig, file: string) {
3379
+ const registered = getCssExtensions().loadCssModuleForClient(file)
3380
+ const coreBuild = isReleaseCompile() && !reactCompatEnabled(config)
3381
+ if (registered !== undefined || !coreBuild || !file.endsWith('.module.css')) return registered
3382
+ const { cssModuleMapping } = await import('../css/build')
3383
+ return `export default ${JSON.stringify(await cssModuleMapping(file))};`
3384
+ }
3385
+
3085
3386
  function isStaticImageFile(file: string) {
3086
3387
  return /\.(?:png|jpe?g|gif|webp|avif|svg|ico|bmp)(?:$|[?#])/.test(file)
3087
3388
  }
@@ -3133,9 +3434,20 @@ function resolveLocalImport(config: ResolvedConfig, fromFile: string, specifier:
3133
3434
 
3134
3435
  async function linkAssetContext(config: ResolvedConfig, file: string, profile: string) {
3135
3436
  if (!isInside(config.root, file)) return
3136
- const sourceDirs = ancestorDirs(config.root, path.dirname(file))
3437
+ const sourceDirs = ancestorDirs(config.root, path.dirname(file)).filter(
3438
+ dir => !isCompiledOutput(config, dir),
3439
+ )
3137
3440
  await Promise.all(
3138
- sourceDirs.map(sourceDir => linkDirectoryAssetContext(config, sourceDir, profile)),
3441
+ sourceDirs.map(sourceDir => {
3442
+ if (!isReleaseCompile()) return linkDirectoryAssetContext(config, sourceDir, profile)
3443
+ const key = `${config.outPath}\0${profile}\0${sourceDir}`
3444
+ let linked = linkedAssetContexts.get(key)
3445
+ if (!linked) {
3446
+ linked = linkDirectoryAssetContext(config, sourceDir, profile)
3447
+ linkedAssetContexts.set(key, linked)
3448
+ }
3449
+ return linked
3450
+ }),
3139
3451
  )
3140
3452
  }
3141
3453
 
@@ -3168,6 +3480,14 @@ async function linkDirectoryAssetContext(
3168
3480
  if (!assetContextEntry(config, sourceDir, entry.name, entry.isDirectory())) return
3169
3481
  const source = path.join(sourceDir, entry.name)
3170
3482
  const target = path.join(targetDir, entry.name)
3483
+ // A linked directory below the root (pages-compat's `source-pages`) compiles on its own path:
3484
+ // staging the link would write its artifacts through it, into the source tree.
3485
+ if (
3486
+ entry.isSymbolicLink() &&
3487
+ sourceDir !== config.root &&
3488
+ statSync(source, { throwIfNoEntry: false })?.isDirectory()
3489
+ )
3490
+ return
3171
3491
  // Root-level sibling asset directories are mirrored, not symlinked wholesale: a `dir` symlink
3172
3492
  // would make every path beneath it - including code modules that must be compiled through the
3173
3493
  // alias transform - resolve straight back to raw source, shadowing the staged compile.
@@ -3208,9 +3528,11 @@ async function stagedManifestSource(file: string) {
3208
3528
  async function linkOrCopyAsset(source: string, target: string) {
3209
3529
  const resolvedSource = path.resolve(source)
3210
3530
  // Concurrent walkers keep a repaired link and remove only the stale target.
3531
+ // A release links relatively: moved with its app, it names no build-machine path.
3532
+ const linkTarget = isReleaseCompile() ? path.relative(path.dirname(target), source) : source
3211
3533
  for (let attempt = 0; attempt < 4; attempt += 1) {
3212
3534
  try {
3213
- await symlink(source, target, 'file')
3535
+ await symlink(linkTarget, target, 'file')
3214
3536
  return
3215
3537
  } catch (error) {
3216
3538
  if ((error as NodeJS.ErrnoException).code !== 'EEXIST') break
@@ -3266,7 +3588,8 @@ function assetContextEntry(
3266
3588
  'pages',
3267
3589
  'public',
3268
3590
  'node_modules',
3269
- path.basename(config.outRootPath),
3591
+ // The out dir's top segment (`dist` for `dist/build`): mirroring it would recurse into its own output.
3592
+ path.relative(config.root, config.outRootPath).split(path.sep)[0],
3270
3593
  ]).has(name)
3271
3594
  }
3272
3595
 
@@ -3296,7 +3619,7 @@ async function staticImageModuleSource(config: ResolvedConfig, file: string) {
3296
3619
  const compat = await getAssetExtensions().staticAssetModule({ sourcePath, bytes, emit })
3297
3620
  const source = compat ?? coreStaticAssetModule(sourcePath, bytes, emit)
3298
3621
  for (const relative of emitted) {
3299
- const target = path.join(config.outPath, 'public', ...relative.split('/'))
3622
+ const target = path.join(config.outPath, 'static', ...relative.split('/'))
3300
3623
  await mkdir(path.dirname(target), { recursive: true })
3301
3624
  if (!existsSync(target)) await copyFile(sourcePath, target)
3302
3625
  }