@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
package/src/cli/start.ts CHANGED
@@ -4,8 +4,10 @@
4
4
  * dynamically once the port is bound, so neither the listen syscall nor the
5
5
  * ready banner waits on parsing it.
6
6
  */
7
+ import { existsSync } from 'node:fs'
7
8
  import { readFile } from 'node:fs/promises'
8
9
  import path from 'node:path'
10
+ import { pathToFileURL } from 'node:url'
9
11
  import { loadConfig } from '../config'
10
12
  import type { ResolvedConfig } from '../config'
11
13
  import { bootstrapCompat } from '../compat-bootstrap'
@@ -13,9 +15,11 @@ import { getBuildExtensions } from '../extensions'
13
15
  import { drainWorkUnits } from '../request/context'
14
16
  import { markErrorLogged } from '../utils/error-log'
15
17
  import { isPostpone } from '../render/postpone'
18
+ import { registerPrebundleResolve } from '../runtime/prebundle'
16
19
  import { browserHost, ensurePortFree, openBrowser, printServerReady } from './serve/ui'
17
20
  import type { BuildManifest } from '../types'
18
21
  import type { PeerAddressSource } from '../routing/forwarded'
22
+ import { buildIndexFile, buildManifestFile, linkStandaloneOrigins } from '../runtime/production'
19
23
 
20
24
  interface StartOptions {
21
25
  root?: string
@@ -33,8 +37,25 @@ type RequestHandler = (request: Request, server?: PeerAddressSource) => Promise<
33
37
  export async function createRequestHandler(
34
38
  options: { root?: string; config?: ResolvedConfig; manifest?: BuildManifest } = {},
35
39
  ): Promise<RequestHandler> {
40
+ registerPrebundleResolve()
41
+ const config = options.config ?? (await loadConfig(options.root, { serve: true }))
42
+ // A release this copy cannot serve in place runs on the framework copy it ships.
43
+ if (shipsElsewhere(config)) {
44
+ const shipped = await shippedStart(config)
45
+ return shipped.createRequestHandler({ root: options.root, manifest: options.manifest })
46
+ }
36
47
  const { createRequestHandler: create } = await import('./serve/pipeline')
37
- return create(options)
48
+ return create({ ...options, config })
49
+ }
50
+
51
+ /** A built release this copy cannot serve in place; a missing build falls through to its error. */
52
+ function shipsElsewhere(config: ResolvedConfig) {
53
+ return existsSync(buildIndexFile(config.outPath)) && !linkStandaloneOrigins(config.outPath)
54
+ }
55
+
56
+ function shippedStart(config: ResolvedConfig) {
57
+ const entry = pathToFileURL(path.join(config.outPath, 'server', 'entry.js')).href
58
+ return import(entry) as Promise<typeof import('./start')>
38
59
  }
39
60
 
40
61
  export async function maybeBuiltFile(
@@ -49,8 +70,14 @@ export async function start(options: StartOptions = {}) {
49
70
  const port = options.port ?? 3000
50
71
  // Next's documented default. Bun resolves 'localhost' to ::1 only, refusing IPv4 clients.
51
72
  const hostname = options.hostname ?? '0.0.0.0'
73
+ const config = await loadConfig(options.root, { serve: true })
74
+ // Delegate before compat bootstraps here, so only the shipped copy patches process globals.
75
+ if (shipsElsewhere(config)) {
76
+ await (await shippedStart(config)).start(options)
77
+ return
78
+ }
52
79
  // Export builds are not served; pnext serves its standalone output directly.
53
- const config = await guardUnservableOutputMode(options.root)
80
+ await guardUnservableOutputMode(config)
54
81
  const manifest = await readProductionManifest(config)
55
82
  await ensurePortFree(port, hostname)
56
83
 
@@ -108,9 +135,7 @@ function installProcessErrorHandlers(): void {
108
135
 
109
136
  export async function readProductionManifest(config: ResolvedConfig): Promise<BuildManifest> {
110
137
  try {
111
- return JSON.parse(
112
- await readFile(path.join(config.outPath, 'manifest.json'), 'utf8'),
113
- ) as BuildManifest
138
+ return JSON.parse(await readFile(buildManifestFile(config.outPath), 'utf8')) as BuildManifest
114
139
  } catch (error) {
115
140
  if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
116
141
  throw new Error("No production build found. Run 'pnext build' first.")
@@ -120,8 +145,7 @@ export async function readProductionManifest(config: ResolvedConfig): Promise<Bu
120
145
  }
121
146
 
122
147
  // Export output is unservable; pnext production output remains serveable for standalone apps.
123
- async function guardUnservableOutputMode(root?: string): Promise<ResolvedConfig> {
124
- const config = await loadConfig(root, { serve: true })
148
+ async function guardUnservableOutputMode(config: ResolvedConfig) {
125
149
  await bootstrapCompat(config)
126
150
  const mode = getBuildExtensions().compat.nextOutputMode()
127
151
  if (mode === 'export') {
@@ -140,7 +164,6 @@ async function guardUnservableOutputMode(root?: string): Promise<ResolvedConfig>
140
164
  'Use "node .next/standalone/server.js" instead.',
141
165
  )
142
166
  }
143
- return config
144
167
  }
145
168
 
146
169
  // Graceful stop: quit accepting connections, wait for in-flight after() flushes (bounded), then exit
@@ -1438,7 +1438,7 @@ async function staticImageModuleSource(config: ResolvedConfig, file: string) {
1438
1438
  const compat = await getAssetExtensions().staticAssetModule({ sourcePath, bytes, emit })
1439
1439
  const source = compat ?? coreStaticAssetModule(sourcePath, bytes, emit)
1440
1440
  for (const relative of emitted) {
1441
- const target = path.join(config.outPath, 'public', ...relative.split('/'))
1441
+ const target = path.join(config.outPath, 'static', ...relative.split('/'))
1442
1442
  await mkdir(path.dirname(target), { recursive: true })
1443
1443
  if (!existsSync(target)) await copyFile(sourcePath, target)
1444
1444
  }
@@ -91,8 +91,15 @@ async function foldGroup(
91
91
  const memberNames = members.map(output => path.basename(output))
92
92
  if (memberNames.some(name => !existsSync(path.join(chunksDir, name)))) return metafile
93
93
 
94
- const sources = new Map<string, string>()
95
- for (const name of memberNames) sources.set(name, await readText(path.join(chunksDir, name)))
94
+ // The state holds every output's current text, in step with what earlier groups wrote.
95
+ const sources = new Map(
96
+ await Promise.all(
97
+ memberNames.map(async name => {
98
+ const file = path.join(chunksDir, name)
99
+ return [name, state.outputs.get(file)?.text ?? (await readText(file))] as const
100
+ }),
101
+ ),
102
+ )
96
103
 
97
104
  const aliases = memberAliases(memberNames, sources)
98
105
  if (!aliases) return metafile
@@ -503,14 +510,20 @@ async function createFoldState(outDir: string, metafile: Metafile): Promise<Fold
503
510
  }
504
511
  }
505
512
 
513
+ const files = new Set<string>()
506
514
  for (const name of Object.keys(metafile.outputs)) {
507
515
  if (!name.endsWith('.js')) continue
508
516
  const resolved = path.resolve(name)
509
517
  const local = existsSync(resolved) ? resolved : path.join(outDir, path.basename(name))
510
- if (outputs.has(local) || !existsSync(local)) continue
511
- const output = foldOutput(await readText(local))
512
- outputs.set(local, output)
513
- index(local, output, true)
518
+ if (existsSync(local)) files.add(local)
519
+ }
520
+ // Read concurrently, indexed in metafile order.
521
+ const list = [...files]
522
+ const texts = await Promise.all(list.map(file => readText(file)))
523
+ for (const [at, file] of list.entries()) {
524
+ const output = foldOutput(texts[at]!)
525
+ outputs.set(file, output)
526
+ index(file, output, true)
514
527
  }
515
528
 
516
529
  return {
@@ -1,5 +1,6 @@
1
- import { existsSync, readFileSync, statSync } from 'node:fs'
1
+ import { existsSync, statSync } from 'node:fs'
2
2
  import path from 'node:path'
3
+ import { readSourceSync } from '../resolve/source-text'
3
4
 
4
5
  /**
5
6
  * Conservative static scan of a compat app's client graph deciding whether the client bundle can ship
@@ -87,7 +88,7 @@ export function clientSuspenseFree(seeds: Iterable<string>): boolean {
87
88
  if (!SOURCE_EXTENSION.test(file) || !existsSync(file)) return false
88
89
  let source: string
89
90
  try {
90
- source = readFileSync(file, 'utf8')
91
+ source = readSourceSync(file)
91
92
  } catch {
92
93
  return false
93
94
  }
@@ -11,6 +11,7 @@ import type { ResolvedConfig } from '../config'
11
11
  import { resolveImport } from '../resolve/imports'
12
12
  import { moduleExportNames, moduleExportStars } from '../resolve/scan-facts'
13
13
  import { readText } from '../utils/fs'
14
+ import { hasModuleDirective } from '../utils/directive'
14
15
 
15
16
  export const clientReferenceRuntimeFile = path.resolve(import.meta.dirname, 'reference.ts')
16
17
 
@@ -22,6 +23,12 @@ export interface ClientReferenceModuleOptions {
22
23
  * inlined lookup is the same symbol the renderer tests for.
23
24
  */
24
25
  inlineSymbol?: boolean
26
+ /**
27
+ * For a release: the reference names its source relative to the stub (`from`), at `target` - the
28
+ * source itself, or its path through the app's node_modules (`real`: resolved to the installed file).
29
+ * A moved build then still identifies the module its release indexed.
30
+ */
31
+ portable?: { from: string; target: string; real: boolean }
25
32
  }
26
33
 
27
34
  export function clientReferenceModuleSource(
@@ -29,8 +36,17 @@ export function clientReferenceModuleSource(
29
36
  exportNames: string[],
30
37
  options: ClientReferenceModuleOptions = {},
31
38
  ) {
39
+ const portable = options.portable
40
+ const located = portable
41
+ ? `decodeURIComponent(new URL(${JSON.stringify(path.relative(path.dirname(portable.from), portable.target).split(path.sep).join('/'))}, import.meta.url).pathname)`
42
+ : undefined
43
+ const file = !located
44
+ ? JSON.stringify(sourceFile)
45
+ : portable?.real
46
+ ? `__pnextRealpath(${located})`
47
+ : located
32
48
  const reference = (exportName: string) =>
33
- `createReference({ id: ${JSON.stringify(`c-${clientReferenceId(sourceFile, exportName)}`)}, file: ${JSON.stringify(sourceFile)}, exportName: ${JSON.stringify(exportName)} })`
49
+ `createReference({ id: ${JSON.stringify(`c-${clientReferenceId(sourceFile, exportName)}`)}, file: ${file}, exportName: ${JSON.stringify(exportName)} })`
34
50
  const defaultExport = exportNames.includes('default')
35
51
  ? `export default ${reference('default')};`
36
52
  : ''
@@ -41,7 +57,11 @@ export function clientReferenceModuleSource(
41
57
  ? `const clientReferenceSymbol = Symbol.for('pnext.clientReference');`
42
58
  : `import { clientReferenceSymbol } from ${JSON.stringify(pathToFileHref(clientReferenceRuntimeFile))};`
43
59
 
44
- return `${symbol}
60
+ const realpath = portable?.real
61
+ ? `import { realpathSync as __pnextRealpath } from 'node:fs';\n`
62
+ : ''
63
+
64
+ return `${realpath}${symbol}
45
65
 
46
66
  function createReference(reference) {
47
67
  function ClientReference({ children }) {
@@ -103,40 +123,7 @@ export async function clientReferenceExportNames(
103
123
  * linear and allocation-free.
104
124
  */
105
125
  export function hasUseClientDirective(source: string) {
106
- const isSpace = (index: number) => {
107
- const code = source.charCodeAt(index)
108
- return code === 32 || (code >= 9 && code <= 13) || (code > 127 && /\s/.test(source[index]!))
109
- }
110
- let i = 0
111
- for (;;) {
112
- while (i < source.length && isSpace(i)) i += 1
113
- if (source.startsWith('//', i)) {
114
- const newline = source.indexOf('\n', i)
115
- if (newline === -1) return false
116
- i = newline + 1
117
- continue
118
- }
119
- if (source.startsWith('/*', i)) {
120
- const end = source.indexOf('*/', i + 2)
121
- if (end === -1) return false
122
- i = end + 2
123
- continue
124
- }
125
- // Anything that is not a string literal ends the prologue.
126
- const quote = source[i]
127
- if (quote !== '"' && quote !== "'") return false
128
- let end = i + 1
129
- while (end < source.length) {
130
- const char = source[end]!
131
- if (char === quote || char === '\n' || char === '\\') break
132
- end += 1
133
- }
134
- if (source[end] !== quote) return false
135
- if (source.slice(i + 1, end) === 'use client') return true
136
- i = end + 1
137
- while (i < source.length && isSpace(i)) i += 1
138
- if (source[i] === ';') i += 1
139
- }
126
+ return hasModuleDirective(source, 'use client')
140
127
  }
141
128
 
142
129
  function isInside(root: string, file: string) {
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path'
2
2
  import { realpathSync } from 'node:fs'
3
3
  import type { Plugin } from 'esbuild'
4
- import { readText } from '../../utils/fs'
4
+ import { readText, toPosixPath } from '../../utils/fs'
5
5
  import { escapeRegex } from '../../utils/code'
6
6
  import { actionId } from './ids'
7
7
  import { moduleActionExports, moduleLevelUseCache, moduleLevelUseServer } from './detect'
@@ -125,7 +125,9 @@ export function stubSourceFromSource(file: string, source: string, root?: string
125
125
  const exports = moduleActionExports(source)
126
126
  const actionIds: Record<string, string> = {}
127
127
  for (const name of exports) actionIds[name] = canonicalActionId(file, name, root)
128
- return clientStubSource({ modulePath: file, exports, actionIds })
128
+ // Root-relative: the stub ships in client bundles and release artifacts.
129
+ const modulePath = root ? toPosixPath(path.relative(root, file)) : file
130
+ return clientStubSource({ modulePath, exports, actionIds })
129
131
  }
130
132
 
131
133
  export async function loadClientActionSource(file: string, root?: string) {
@@ -3,6 +3,7 @@ import { createRequire } from 'node:module'
3
3
  import path from 'node:path'
4
4
  import { pathToFileHref } from '../../config'
5
5
  import { DEFAULT_BODY_LIMIT_BYTES } from './endpoint'
6
+ import { getNextConfig, nextConfigReleased } from '../next/config-loader'
6
7
 
7
8
  /**
8
9
  * Server-actions options read from the app's next.config in compat mode:
@@ -39,7 +40,7 @@ export async function loadServerActionsConfig(root: string): Promise<ServerActio
39
40
  }
40
41
 
41
42
  export async function loadResolvedNextConfig(root: string): Promise<NextConfigShape | undefined> {
42
- return (await loadNextConfigFromStore()) ?? (await loadNextConfig(root))
43
+ return loadNextConfigFromStore() ?? (await loadNextConfig(root))
43
44
  }
44
45
 
45
46
  /**
@@ -50,9 +51,8 @@ export async function loadResolvedNextConfig(root: string): Promise<NextConfigSh
50
51
  * silently dropped the configured bodySizeLimit. Returns undefined when the store is empty so the
51
52
  * caller falls back to a direct file read.
52
53
  */
53
- async function loadNextConfigFromStore(): Promise<NextConfigShape | undefined> {
54
+ function loadNextConfigFromStore(): NextConfigShape | undefined {
54
55
  try {
55
- const { getNextConfig } = await import('../next/config-loader')
56
56
  const store: NextConfigShape = getNextConfig()
57
57
  return store && Object.keys(store).length > 0 ? store : undefined
58
58
  } catch {
@@ -61,6 +61,7 @@ async function loadNextConfigFromStore(): Promise<NextConfigShape | undefined> {
61
61
  }
62
62
 
63
63
  export async function loadNextConfig(root: string): Promise<NextConfigShape | undefined> {
64
+ if (nextConfigReleased()) return getNextConfig()
64
65
  for (const name of ['next.config.js', 'next.config.mjs', 'next.config.cjs']) {
65
66
  const file = path.join(root, name)
66
67
  if (!existsSync(file)) continue
@@ -109,9 +110,9 @@ export async function loadNextConfig(root: string): Promise<NextConfigShape | un
109
110
  * skipped here - the lazy per-request path still validates.
110
111
  */
111
112
  export function validateServerActionsConfigSync(root: string): void {
112
- let config: NextConfigShape | undefined
113
+ let config: NextConfigShape | undefined = nextConfigReleased() ? getNextConfig() : undefined
113
114
  const requireFrom = createRequire(path.join(root, 'noop.js'))
114
- for (const name of ['next.config.js', 'next.config.cjs']) {
115
+ for (const name of config ? [] : ['next.config.js', 'next.config.cjs']) {
115
116
  const file = path.join(root, name)
116
117
  if (!existsSync(file)) continue
117
118
  try {
@@ -21,8 +21,7 @@ import {
21
21
  import { getRequestRuntime, type RequestRuntime } from '../../routing/request-environment'
22
22
  import { toPosixPath } from '../../utils/fs'
23
23
  import type { ActionManifestEntry, BuildManifest, RouteManifestEntry } from '../../types'
24
- import { devServerModuleHref } from '../../runtime/modules'
25
- import { serverBundleTargetForRuntime } from '../../runtime/loader'
24
+ import { devServerModuleHref, serverBundleTargetForRuntime } from '../../runtime/load'
26
25
  import {
27
26
  renderActionReturnElement,
28
27
  renderGlobalNotFoundResponse,
@@ -31,7 +30,7 @@ import {
31
30
  renderPageResponse,
32
31
  } from '../../render/renderer'
33
32
  import { routeParamsFromPath } from '../../routing/handler'
34
- import { selectRouteForRequest } from '../../routing/routes'
33
+ import { selectRouteForRequest } from '../../routing/match'
35
34
  import { discoverActions, registerDiscoveredActions } from './discovery'
36
35
  import { clearActions, lookupActionSource, registerActionModule } from './registry'
37
36
  import {
@@ -71,6 +70,7 @@ import { serverActionId, tagServerAction } from './server-tag'
71
70
  import { opensWithUseServerDirective } from './detect'
72
71
  import { inlineActionModuleKey, isInlineActionId } from './rewrite'
73
72
  import { reportActionErrorToUser } from '../lifecycle/error-funnel'
73
+ import { buildManifestFile } from '../../runtime/production'
74
74
 
75
75
  // ---------------------------------------------------------------------------
76
76
  // Build step: action discovery/bundling + server-reference manifest.
@@ -542,7 +542,7 @@ export async function ensureActionsRegistered(runtime: RequestRuntime): Promise<
542
542
  // client-action module set (normally armed by the build): render-time form/prop
543
543
  // tagging reads it to give module-level actions their stable wire ids.
544
544
  async function registerManifestActions(config: ResolvedConfig): Promise<void> {
545
- const manifestPath = path.join(config.outPath, 'manifest.json')
545
+ const manifestPath = buildManifestFile(config.outPath)
546
546
  let manifest: BuildManifest
547
547
  try {
548
548
  manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as BuildManifest
@@ -701,7 +701,7 @@ function requestWouldMiss(config: ResolvedConfig, pathname: string): boolean {
701
701
  }
702
702
 
703
703
  function servableFile(config: ResolvedConfig, pathname: string): boolean {
704
- const publicRoot = path.join(config.outPath, 'public')
704
+ const publicRoot = path.join(config.outPath, 'static')
705
705
  const trimmed = pathname.replace(/^\/+|\/+$/g, '')
706
706
  const file = trimmed ? path.join(publicRoot, trimmed) : publicRoot
707
707
  // Never let a traversal-shaped path claim to be servable (it is not).
@@ -1,4 +1,6 @@
1
1
  import path from 'node:path'
2
+ import { isReleaseCompile } from '../runtime/load'
3
+ import { toPosixPath } from '../utils/fs'
2
4
  import { createRequire } from 'node:module'
3
5
  import type { Plugin } from 'esbuild'
4
6
  import { frameworkRuntimeAliasEntries, pnextAliases, type CompatAliasTarget } from '../config'
@@ -329,7 +331,12 @@ export function rewriteNextFontSource(
329
331
  let next = rewriteNextGoogleFontImports(source, runtimePath)
330
332
  const localFontNames = nextLocalFontImportNames(next)
331
333
  if (localFontNames.size === 0) return next
332
- const callerFile = localFontCallerFile(file, root)
334
+ // A release names the caller root-relative, so its font identity survives moving the build.
335
+ const absoluteCaller = localFontCallerFile(file, root)
336
+ const callerFile =
337
+ isReleaseCompile() && root && path.isAbsolute(absoluteCaller)
338
+ ? toPosixPath(path.relative(root, absoluteCaller))
339
+ : absoluteCaller
333
340
  // Rewrite each `NAME(...)` call to `NAME.withFile(<file>)(...)` so the runtime
334
341
  // gets the caller path (for `src` resolution + a stable per-caller hash). The
335
342
  // client runtime only uses `callerFile` for the hash (which must match the
@@ -20,6 +20,89 @@ const PREDEFINED_SERVER_EXTERNAL_PACKAGES = [
20
20
  '@node-rs/bcrypt',
21
21
  ]
22
22
 
23
+ /** Next's `next/dist/lib/server-external-packages.jsonc`. */
24
+ const NEXT_SERVER_EXTERNAL_PACKAGES = new Set([
25
+ '@alinea/generated',
26
+ '@appsignal/nodejs',
27
+ '@aws-sdk/client-s3',
28
+ '@aws-sdk/s3-presigned-post',
29
+ '@blockfrost/blockfrost-js',
30
+ '@highlight-run/node',
31
+ '@huggingface/transformers',
32
+ '@jpg-store/lucid-cardano',
33
+ '@libsql/client',
34
+ '@mikro-orm/core',
35
+ '@mikro-orm/knex',
36
+ '@node-rs/argon2',
37
+ '@node-rs/bcrypt',
38
+ '@prisma/client',
39
+ '@react-pdf/renderer',
40
+ '@sentry/profiling-node',
41
+ '@sparticuz/chromium',
42
+ '@sparticuz/chromium-min',
43
+ '@statsig/statsig-node-core',
44
+ '@swc/core',
45
+ '@xenova/transformers',
46
+ '@zenstackhq/runtime',
47
+ 'argon2',
48
+ 'autoprefixer',
49
+ 'aws-crt',
50
+ 'bcrypt',
51
+ 'better-sqlite3',
52
+ 'canvas',
53
+ 'chromadb-default-embed',
54
+ 'config',
55
+ 'cpu-features',
56
+ 'cypress',
57
+ 'dd-trace',
58
+ 'eslint',
59
+ 'express',
60
+ 'firebase-admin',
61
+ 'htmlrewriter',
62
+ 'import-in-the-middle',
63
+ 'isolated-vm',
64
+ 'jest',
65
+ 'jsdom',
66
+ 'keyv',
67
+ 'libsql',
68
+ 'mdx-bundler',
69
+ 'mongodb',
70
+ 'mongoose',
71
+ 'newrelic',
72
+ 'next-mdx-remote',
73
+ 'next-seo',
74
+ 'node-cron',
75
+ 'node-pty',
76
+ 'node-web-audio-api',
77
+ 'onnxruntime-node',
78
+ 'oslo',
79
+ 'pg',
80
+ 'pino',
81
+ 'pino-pretty',
82
+ 'pino-roll',
83
+ 'playwright',
84
+ 'playwright-core',
85
+ 'postcss',
86
+ 'prettier',
87
+ 'prisma',
88
+ 'puppeteer',
89
+ 'puppeteer-core',
90
+ 'ravendb',
91
+ 'require-in-the-middle',
92
+ 'rimraf',
93
+ 'sharp',
94
+ 'shiki',
95
+ 'sqlite3',
96
+ 'thread-stream',
97
+ 'ts-morph',
98
+ 'ts-node',
99
+ 'typescript',
100
+ 'vscode-oniguruma',
101
+ 'webpack',
102
+ 'websocket',
103
+ 'zeromq',
104
+ ])
105
+
23
106
  function stringArray(value: unknown): string[] {
24
107
  return Array.isArray(value)
25
108
  ? value.filter((item): item is string => typeof item === 'string')
@@ -51,6 +134,11 @@ export function deploymentId(): string | undefined {
51
134
  return fromEnv && fromEnv.length > 0 ? fromEnv : undefined
52
135
  }
53
136
 
137
+ /** Next's built-in server externals, which a release keeps out of its dependency graph. */
138
+ export function builtInServerExternalPackages(): ReadonlySet<string> {
139
+ return NEXT_SERVER_EXTERNAL_PACKAGES
140
+ }
141
+
54
142
  /** `publicRuntimeConfig`: the subset of runtime config safe to inline into client bundles. */
55
143
  export function publicRuntimeConfig(): Record<string, unknown> {
56
144
  const config = getNextConfig().publicRuntimeConfig
@@ -181,9 +181,33 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
181
181
  if (isGeneratedFontAwesomePackage(packageDir)) {
182
182
  return parseGeneratedFontAwesomeBarrel(entry, source)
183
183
  }
184
+ const plain = plainReExports(source)
185
+ const exported = plain
186
+ ? { exports: plain, count: plain.size, reExportsOnly: () => true }
187
+ : parsedReExports(entry, source)
188
+ if (!exported || exported.count < GENERATED_BARREL_MIN_EXPORTS) return undefined
189
+ const { exports, count: exportCount } = exported
190
+ const siblings = siblingFilesByStem(path.dirname(entry), entry)
191
+ const members = new Map<string, BarrelMember>()
192
+ for (const [name, member] of exports) {
193
+ const files = siblings.get(name)
194
+ const file = files?.[0]
195
+ if (
196
+ file &&
197
+ files.length === 1 &&
198
+ path.resolve(path.dirname(entry), member.source) === path.resolve(path.dirname(entry), file)
199
+ ) {
200
+ members.set(name, member)
201
+ }
202
+ }
203
+ if (members.size / exportCount >= GENERATED_BARREL_LEAF_RATIO) return members
204
+ return exported.reExportsOnly() ? manyToFewBarrelMembers(exports, entry) : undefined
205
+ }
206
+
207
+ /** The entry's re-export records off oxc's module record; the AST is read only if asked for. */
208
+ function parsedReExports(entry: string, source: string) {
184
209
  const parsed = parseSync(entry, source, { lang: 'js' })
185
210
  if (parsed.errors.length > 0) return undefined
186
- const siblings = siblingFilesByStem(path.dirname(entry), entry)
187
211
  const exports = new Map<string, BarrelMember>()
188
212
  const exportNames = new Set<string>()
189
213
  let exportCount = 0
@@ -206,22 +230,56 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
206
230
  exports.set(name, { source: request, imported })
207
231
  }
208
232
  }
209
- if (exportCount < GENERATED_BARREL_MIN_EXPORTS) return undefined
233
+ return {
234
+ exports,
235
+ count: exportCount,
236
+ // Re-exports and nothing else: no statement runs code or declares a binding.
237
+ reExportsOnly: () =>
238
+ parsed.program.body.every(
239
+ node => node.type === 'ExportNamedDeclaration' && !node.declaration,
240
+ ),
241
+ }
242
+ }
210
243
 
211
- const members = new Map<string, BarrelMember>()
212
- for (const [name, member] of exports) {
213
- const files = siblings.get(name)
214
- const file = files?.[0]
215
- if (
216
- file &&
217
- files.length === 1 &&
218
- path.resolve(path.dirname(entry), member.source) === path.resolve(path.dirname(entry), file)
219
- ) {
220
- members.set(name, member)
244
+ const PLAIN_RE_EXPORT = /export\s*\{([^{}]*)\}\s*from\s*(['"])([^'"\\\n]*)\2[ \t]*;?/y
245
+ const PLAIN_GAP = /(?:\s+|\/\/[^\n]*|\/\*[\s\S]*?\*\/)*/y
246
+ const PLAIN_SPECIFIER = /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/
247
+
248
+ /**
249
+ * A generated catalogue is usually nothing but `export { a as b } from './x'` lines. Read that
250
+ * exact shape without building an AST (oxc's module record alone costs more than the parse on a
251
+ * 1 MB entry); anything else - or a repeated name - answers undefined and takes the oxc path.
252
+ */
253
+ function plainReExports(source: string): Map<string, BarrelMember> | undefined {
254
+ // The scan knows only LF as a line end; CR, U+2028 and U+2029 also end a `//` comment.
255
+ if (/[\r\u2028\u2029]/.test(source)) return undefined
256
+ const exports = new Map<string, BarrelMember>()
257
+ let at = 0
258
+ for (;;) {
259
+ PLAIN_GAP.lastIndex = at
260
+ PLAIN_GAP.exec(source)
261
+ if (PLAIN_GAP.lastIndex >= source.length) break
262
+ // Without a `;`, only a line break can end the statement before the next one.
263
+ if (at > 0 && source[at - 1] !== ';' && !source.slice(at, PLAIN_GAP.lastIndex).includes('\n'))
264
+ return undefined
265
+ PLAIN_RE_EXPORT.lastIndex = PLAIN_GAP.lastIndex
266
+ const statement = PLAIN_RE_EXPORT.exec(source)
267
+ if (!statement) return undefined
268
+ at = PLAIN_RE_EXPORT.lastIndex
269
+ const parts = statement[1]!.split(',')
270
+ for (const [index, part] of parts.entries()) {
271
+ const specifier = PLAIN_SPECIFIER.exec(part.trim())
272
+ if (!specifier) {
273
+ if (part.trim() === '' && index === parts.length - 1 && index > 0) continue
274
+ return undefined
275
+ }
276
+ const imported = specifier[1]!
277
+ const name = specifier[2] ?? imported
278
+ if (exports.has(name)) return undefined
279
+ exports.set(name, { source: statement[3]!, imported })
221
280
  }
222
281
  }
223
- if (members.size / exportCount >= GENERATED_BARREL_LEAF_RATIO) return members
224
- return manyToFewBarrelMembers(parsed.program.body, exports, entry)
282
+ return exports
225
283
  }
226
284
 
227
285
  /**
@@ -234,26 +292,28 @@ function parseGeneratedBarrel(entry: string): BarrelMap | undefined {
234
292
  * read for demanded members.
235
293
  */
236
294
  function manyToFewBarrelMembers(
237
- body: readonly { type: string; declaration?: unknown }[],
238
295
  exports: ReadonlyMap<string, BarrelMember>,
239
296
  entry: string,
240
297
  ): BarrelMap | undefined {
241
- for (const node of body) {
242
- if (node.type !== 'ExportNamedDeclaration' || node.declaration) return undefined
243
- }
244
298
  const byDirectory = new Map<string, Map<string, string[]>>()
299
+ // Thousands of names share a handful of leaves: judge each leaf once.
300
+ const unambiguous = new Map<string, boolean>()
245
301
  const members = new Map<string, BarrelMember>()
246
302
  for (const [name, member] of exports) {
247
303
  if (!member.source.startsWith('.')) continue
248
- const file = path.resolve(path.dirname(entry), member.source)
249
- const directory = path.dirname(file)
250
- let siblings = byDirectory.get(directory)
251
- if (!siblings) {
252
- siblings = siblingFilesByStem(directory, entry)
253
- byDirectory.set(directory, siblings)
304
+ let leaf = unambiguous.get(member.source)
305
+ if (leaf === undefined) {
306
+ const file = path.resolve(path.dirname(entry), member.source)
307
+ const directory = path.dirname(file)
308
+ let siblings = byDirectory.get(directory)
309
+ if (!siblings) {
310
+ siblings = siblingFilesByStem(directory, entry)
311
+ byDirectory.set(directory, siblings)
312
+ }
313
+ leaf = siblings.get(path.basename(file).replace(/\.(?:c|m)?js$/, ''))?.length === 1
314
+ unambiguous.set(member.source, leaf)
254
315
  }
255
- if (siblings.get(path.basename(file).replace(/\.(?:c|m)?js$/, ''))?.length !== 1) continue
256
- members.set(name, member)
316
+ if (leaf) members.set(name, member)
257
317
  }
258
318
  return members.size > 0 ? members : undefined
259
319
  }