@wular/pnext 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1992
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1897
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +318 -296
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +827 -815
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
@@ -4,28 +4,28 @@
4
4
  * an esbuild re-bundle of a renaming barrel plus an import rewrite in every
5
5
  * chunk that referenced a member.
6
6
  */
7
- import { createHash } from 'node:crypto';
8
- import { existsSync } from 'node:fs';
9
- import { unlink } from 'node:fs/promises';
10
- import path from 'node:path';
11
- import { build, type BuildOptions, type Metafile } from 'esbuild';
12
- import { clientProfile } from './profile';
13
- import { readText, writeText } from '../utils/fs';
14
- import { escapeRegex } from '../utils/source';
7
+ import { createHash } from 'node:crypto'
8
+ import { existsSync } from 'node:fs'
9
+ import { unlink } from 'node:fs/promises'
10
+ import path from 'node:path'
11
+ import { build, type BuildOptions, type Metafile } from 'esbuild'
12
+ import { clientProfile } from './profile'
13
+ import { readText, writeText } from '../utils/fs'
14
+ import { escapeRegex } from '../utils/code'
15
15
 
16
16
  /** Unlinking an artifact a concurrent build already removed is not news. */
17
17
  function ignoreMissing() {
18
- return undefined;
18
+ return undefined
19
19
  }
20
20
 
21
21
  /** Import/export forms the rewrite understands; anything else vetoes the fold. */
22
- const namedClause = String.raw`\{([^}]*)\}`;
22
+ const namedClause = String.raw`\{([^}]*)\}`
23
23
 
24
24
  interface FoldOptions {
25
- outDir: string;
26
- metafile: Metafile;
25
+ outDir: string
26
+ metafile: Metafile
27
27
  /** esbuild flags of the build being folded, so the merge is emitted the same way. */
28
- buildOptions: Pick<BuildOptions, 'minify' | 'sourcemap' | 'target' | 'format'>;
28
+ buildOptions: Pick<BuildOptions, 'minify' | 'sourcemap' | 'target' | 'format'>
29
29
  }
30
30
 
31
31
  /**
@@ -34,11 +34,11 @@ interface FoldOptions {
34
34
  */
35
35
  export async function foldInitialChunks(options: FoldOptions): Promise<Metafile> {
36
36
  // eslint-disable-next-line turbo/no-undeclared-env-vars
37
- if (process.env.PNEXT_CHUNK_FOLD === '0') return options.metafile;
37
+ if (process.env.PNEXT_CHUNK_FOLD === '0') return options.metafile
38
38
  // The cost this removes is compressed-transfer only (a gzip header and
39
39
  // dictionary reset per chunk), so the pass rides the minify flag.
40
- if (!options.buildOptions.minify) return options.metafile;
41
- return foldChunks(options);
40
+ if (!options.buildOptions.minify) return options.metafile
41
+ return foldChunks(options)
42
42
  }
43
43
 
44
44
  /**
@@ -47,36 +47,36 @@ export async function foldInitialChunks(options: FoldOptions): Promise<Metafile>
47
47
  * disk have diverged, so it rethrows. `PNEXT_CHUNK_FOLD=strict` throws for both.
48
48
  */
49
49
  async function foldChunks({ outDir, metafile, buildOptions }: FoldOptions): Promise<Metafile> {
50
- let folded = metafile;
51
- const groups = clientProfile.time('foldGroups', () => coLoadGroups(metafile));
52
- clientProfile.count('foldGroup#', groups.length);
53
- clientProfile.count('foldOutput#', Object.keys(metafile.outputs).length);
54
- if (groups.length === 0) return folded;
50
+ let folded = metafile
51
+ const groups = clientProfile.time('foldGroups', () => coLoadGroups(metafile))
52
+ clientProfile.count('foldGroup#', groups.length)
53
+ clientProfile.count('foldOutput#', Object.keys(metafile.outputs).length)
54
+ if (groups.length === 0) return folded
55
55
  // Output text is read once and kept in step with what each group writes, and
56
56
  // the same state indexes specifiers — so a group visits only the files naming
57
57
  // one of its members instead of re-reading and re-filtering every output.
58
- const state = await clientProfile.timeAsync('foldRead', () => createFoldState(outDir, metafile));
58
+ const state = await clientProfile.timeAsync('foldRead', () => createFoldState(outDir, metafile))
59
59
  for (const group of groups) {
60
- const mutation = { started: false };
60
+ const mutation = { started: false }
61
61
  try {
62
- folded = await foldGroup({ outDir, metafile: folded, buildOptions }, group, mutation, state);
62
+ folded = await foldGroup({ outDir, metafile: folded, buildOptions }, group, mutation, state)
63
63
  } catch (error) {
64
- if (mutation.started) throw error;
65
- reportFoldFailure(group, error);
66
- break;
64
+ if (mutation.started) throw error
65
+ reportFoldFailure(group, error)
66
+ break
67
67
  }
68
68
  }
69
- return folded;
69
+ return folded
70
70
  }
71
71
 
72
72
  function reportFoldFailure(group: string[], error: unknown) {
73
- const names = group.map(member => path.basename(member)).join(', ');
74
- const message = error instanceof Error ? error.message : String(error);
73
+ const names = group.map(member => path.basename(member)).join(', ')
74
+ const message = error instanceof Error ? error.message : String(error)
75
75
  // eslint-disable-next-line turbo/no-undeclared-env-vars
76
76
  if (process.env.PNEXT_CHUNK_FOLD === 'strict') {
77
- throw new Error(`client chunk fold failed for [${names}]: ${message}`);
77
+ throw new Error(`client chunk fold failed for [${names}]: ${message}`)
78
78
  }
79
- console.warn(`pnext: client chunk fold skipped [${names}] — ${message}`);
79
+ console.warn(`pnext: client chunk fold skipped [${names}] — ${message}`)
80
80
  }
81
81
 
82
82
  async function foldGroup(
@@ -85,65 +85,65 @@ async function foldGroup(
85
85
  mutation: { started: boolean },
86
86
  state: FoldState,
87
87
  ): Promise<Metafile> {
88
- if (members.length < 2) return metafile;
88
+ if (members.length < 2) return metafile
89
89
 
90
- const chunksDir = path.join(outDir, 'chunks');
91
- const memberNames = members.map(output => path.basename(output));
92
- if (memberNames.some(name => !existsSync(path.join(chunksDir, name)))) return metafile;
90
+ const chunksDir = path.join(outDir, 'chunks')
91
+ const memberNames = members.map(output => path.basename(output))
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
+ const sources = new Map<string, string>()
95
+ for (const name of memberNames) sources.set(name, await readText(path.join(chunksDir, name)))
96
96
 
97
- const aliases = memberAliases(memberNames, sources);
98
- if (!aliases) return metafile;
97
+ const aliases = memberAliases(memberNames, sources)
98
+ if (!aliases) return metafile
99
99
 
100
100
  // Every file that referenced a member has to be rewritten; if any of them
101
101
  // uses a form the rewriter can't express (`import * as`, `export *`, a bare
102
102
  // dynamic `import()` of a member), the fold is abandoned whole.
103
- const rewrites = new Map<string, string>();
104
- const rewrite = memberRewriter(memberNames, aliases, chunksDir);
103
+ const rewrites = new Map<string, string>()
104
+ const rewrite = memberRewriter(memberNames, aliases, chunksDir)
105
105
  const rewritable = clientProfile.time('foldRewrite', () => {
106
106
  for (const file of state.referrersOf(memberNames)) {
107
- if (memberNames.includes(path.basename(file))) continue;
108
- const output = state.outputs.get(file);
109
- if (!output) continue;
110
- const next = rewrite(output.text, file);
111
- if (next === null) return false;
112
- if (next !== output.text) rewrites.set(file, next);
107
+ if (memberNames.includes(path.basename(file))) continue
108
+ const output = state.outputs.get(file)
109
+ if (!output) continue
110
+ const next = rewrite(output.text, file)
111
+ if (next === null) return false
112
+ if (next !== output.text) rewrites.set(file, next)
113
113
  }
114
- return true;
115
- });
116
- if (!rewritable) return metafile;
114
+ return true
115
+ })
116
+ if (!rewritable) return metafile
117
117
 
118
118
  const merged = await clientProfile.timeAsync('foldBuild', () =>
119
119
  buildMergedChunk(chunksDir, memberNames, aliases, buildOptions),
120
- );
121
- if (!merged) return metafile;
120
+ )
121
+ if (!merged) return metafile
122
122
 
123
123
  // Read-only up to here, so failing is skippable. From the first rewrite on the
124
124
  // metafile and the files on disk must be kept in step, so failures are fatal.
125
- mutation.started = true;
125
+ mutation.started = true
126
126
 
127
127
  // The rewrites were produced against a placeholder href — the merged chunk's
128
128
  // name is its own content hash and so isn't known until it is built.
129
129
  await Promise.all(
130
130
  [...rewrites].map(([file, source]) => {
131
- const next = source.replaceAll(MERGED_PLACEHOLDER, merged.name);
132
- state.set(file, foldOutput(next));
133
- return writeText(file, next);
131
+ const next = source.replaceAll(MERGED_PLACEHOLDER, merged.name)
132
+ state.set(file, foldOutput(next))
133
+ return writeText(file, next)
134
134
  }),
135
- );
135
+ )
136
136
  await Promise.all(
137
137
  memberNames.flatMap(name => [
138
138
  unlink(path.join(chunksDir, name)).catch(ignoreMissing),
139
139
  unlink(path.join(chunksDir, `${name}.map`)).catch(ignoreMissing),
140
140
  ]),
141
- );
142
- for (const name of memberNames) state.remove(path.join(chunksDir, name));
141
+ )
142
+ for (const name of memberNames) state.remove(path.join(chunksDir, name))
143
143
  // A later group can reference this merged chunk, and it is what the previous
144
144
  // per-group re-walk picked up off disk; index it the same way.
145
- state.set(path.join(chunksDir, merged.name), foldOutput(merged.text));
146
- return mergeMetafile(metafile, members, path.join(chunksDir, merged.name), merged.bytes);
145
+ state.set(path.join(chunksDir, merged.name), foldOutput(merged.text))
146
+ return mergeMetafile(metafile, members, path.join(chunksDir, merged.name), merged.bytes)
147
147
  }
148
148
 
149
149
  /**
@@ -153,10 +153,10 @@ async function foldGroup(
153
153
  * what a lazily loaded island's CSS/runtime seam resolves against.
154
154
  */
155
155
  function coLoadGroups(metafile: Metafile) {
156
- const dynamicTargets = new Set<string>();
156
+ const dynamicTargets = new Set<string>()
157
157
  for (const output of Object.values(metafile.outputs)) {
158
158
  for (const imported of output.imports ?? []) {
159
- if (imported.kind === 'dynamic-import') dynamicTargets.add(imported.path);
159
+ if (imported.kind === 'dynamic-import') dynamicTargets.add(imported.path)
160
160
  }
161
161
  }
162
162
  // esbuild records an `entryPoint` for the chunk behind every `import()` too,
@@ -164,19 +164,19 @@ function coLoadGroups(metafile: Metafile) {
164
164
  // route entry.
165
165
  const entries = Object.keys(metafile.outputs).filter(
166
166
  file => metafile.outputs[file]?.entryPoint && !dynamicTargets.has(file),
167
- );
168
- if (entries.length === 0) return [];
167
+ )
168
+ if (entries.length === 0) return []
169
169
 
170
- const available = availability(metafile, entries, dynamicTargets);
171
- const roots = [...available.keys()];
172
- const groups = new Map<string, string[]>();
170
+ const available = availability(metafile, entries, dynamicTargets)
171
+ const roots = [...available.keys()]
172
+ const groups = new Map<string, string[]>()
173
173
  for (const file of Object.keys(metafile.outputs)) {
174
- if (!file.endsWith('.js')) continue;
175
- if (entries.includes(file) || dynamicTargets.has(file)) continue;
176
- const mask = roots.map(root => (available.get(root)!.has(file) ? '1' : '0')).join('');
174
+ if (!file.endsWith('.js')) continue
175
+ if (entries.includes(file) || dynamicTargets.has(file)) continue
176
+ const mask = roots.map(root => (available.get(root)!.has(file) ? '1' : '0')).join('')
177
177
  // A chunk no root can reach is dead output; leave it alone.
178
- if (!mask.includes('1')) continue;
179
- (groups.get(mask) ?? groups.set(mask, []).get(mask)!).push(file);
178
+ if (!mask.includes('1')) continue
179
+ ;(groups.get(mask) ?? groups.set(mask, []).get(mask)!).push(file)
180
180
  }
181
181
  return [...groups.values()]
182
182
  .filter(
@@ -187,7 +187,7 @@ function coLoadGroups(metafile: Metafile) {
187
187
  // nobody waits on.
188
188
  entries.some(entry => available.get(entry)!.has(group[0]!)),
189
189
  )
190
- .map(group => [...group].sort());
190
+ .map(group => [...group].sort())
191
191
  }
192
192
 
193
193
  /**
@@ -199,21 +199,21 @@ function availabilityAt(
199
199
  file: string,
200
200
  memo: Map<string, Set<string>>,
201
201
  ) {
202
- const own = available.get(file);
203
- if (own) return own;
202
+ const own = available.get(file)
203
+ if (own) return own
204
204
  // The fixpoint below asks for the same non-root importers once per round per
205
205
  // target, and each answer scans every root's availability set — quadratic in
206
206
  // roots. The memo is cleared whenever a round changes an answer.
207
- const cached = memo.get(file);
208
- if (cached) return cached;
209
- let acc: Set<string> | undefined;
207
+ const cached = memo.get(file)
208
+ if (cached) return cached
209
+ let acc: Set<string> | undefined
210
210
  for (const set of available.values()) {
211
- if (!set.has(file)) continue;
212
- acc = acc === undefined ? new Set(set) : intersect(acc, set);
211
+ if (!set.has(file)) continue
212
+ acc = acc === undefined ? new Set(set) : intersect(acc, set)
213
213
  }
214
- const answer = acc ?? new Set([file]);
215
- memo.set(file, answer);
216
- return answer;
214
+ const answer = acc ?? new Set([file])
215
+ memo.set(file, answer)
216
+ return answer
217
217
  }
218
218
 
219
219
  /**
@@ -222,97 +222,98 @@ function availabilityAt(
222
222
  * importers whose own availability is still an estimate, and lands pessimistic behind route chunks.
223
223
  */
224
224
  function entryFloors(metafile: Metafile, entries: string[], closures: Map<string, Set<string>>) {
225
- const dynamicEdges = new Map<string, string[]>();
225
+ const dynamicEdges = new Map<string, string[]>()
226
226
  for (const [file, output] of Object.entries(metafile.outputs)) {
227
227
  for (const imported of output.imports ?? []) {
228
- if (imported.kind !== 'dynamic-import') continue;
229
- (dynamicEdges.get(file) ?? dynamicEdges.set(file, []).get(file)!).push(imported.path);
228
+ if (imported.kind !== 'dynamic-import') continue
229
+ ;(dynamicEdges.get(file) ?? dynamicEdges.set(file, []).get(file)!).push(imported.path)
230
230
  }
231
231
  }
232
- const floors = new Map<string, Set<string>>();
232
+ const floors = new Map<string, Set<string>>()
233
233
  for (const entry of entries) {
234
- const own = closures.get(entry)!;
235
- const seen = new Set(own);
236
- const queue = [...own];
234
+ const own = closures.get(entry)!
235
+ const seen = new Set(own)
236
+ const queue = [...own]
237
237
  // `queue` grows inside the loop: every chunk this entry can reach by any
238
238
  // chain of static and dynamic imports.
239
239
  for (const current of queue) {
240
240
  for (const target of dynamicEdges.get(current) ?? []) {
241
- if (seen.has(target)) continue;
241
+ if (seen.has(target)) continue
242
242
  for (const file of closures.get(target) ?? staticClosure(metafile, target)) {
243
- if (seen.has(file)) continue;
244
- seen.add(file);
245
- queue.push(file);
243
+ if (seen.has(file)) continue
244
+ seen.add(file)
245
+ queue.push(file)
246
246
  }
247
- const floor = floors.get(target);
248
- floors.set(target, floor ? intersect(floor, own) : new Set(own));
247
+ const floor = floors.get(target)
248
+ floors.set(target, floor ? intersect(floor, own) : new Set(own))
249
249
  }
250
250
  }
251
251
  }
252
- return floors;
252
+ return floors
253
253
  }
254
254
 
255
255
  /** Per load root, the chunks guaranteed to be on the page once it runs. */
256
256
  function availability(metafile: Metafile, entries: string[], dynamicTargets: Set<string>) {
257
- const available = new Map<string, Set<string>>();
258
- const closures = new Map<string, Set<string>>();
257
+ const available = new Map<string, Set<string>>()
258
+ const closures = new Map<string, Set<string>>()
259
259
  for (const root of [...entries, ...dynamicTargets]) {
260
- closures.set(root, staticClosure(metafile, root));
261
- available.set(root, new Set(closures.get(root)));
260
+ closures.set(root, staticClosure(metafile, root))
261
+ available.set(root, new Set(closures.get(root)))
262
262
  }
263
263
  for (const [target, floor] of entryFloors(metafile, entries, closures)) {
264
- const set = available.get(target);
265
- if (set) for (const file of floor) set.add(file);
264
+ const set = available.get(target)
265
+ if (set) for (const file of floor) set.add(file)
266
266
  }
267
- const importersOf = new Map<string, string[]>();
267
+ const importersOf = new Map<string, string[]>()
268
268
  for (const [file, output] of Object.entries(metafile.outputs)) {
269
269
  for (const imported of output.imports ?? []) {
270
- if (imported.kind !== 'dynamic-import') continue;
271
- (importersOf.get(imported.path) ?? importersOf.set(imported.path, []).get(imported.path)!)
272
- .push(file);
270
+ if (imported.kind !== 'dynamic-import') continue
271
+ ;(
272
+ importersOf.get(imported.path) ?? importersOf.set(imported.path, []).get(imported.path)!
273
+ ).push(file)
273
274
  }
274
275
  }
275
276
  // `available` only ever grows, so iterating to a fixed point terminates; the
276
277
  // bound is the number of roots (each round settles at least one).
277
- const memo = new Map<string, Set<string>>();
278
+ const memo = new Map<string, Set<string>>()
278
279
  for (let round = 0; round < dynamicTargets.size + 1; round += 1) {
279
- let changed = false;
280
+ let changed = false
280
281
  for (const target of dynamicTargets) {
281
- const importers = importersOf.get(target) ?? [];
282
- let inherited: Set<string> | undefined;
282
+ const importers = importersOf.get(target) ?? []
283
+ let inherited: Set<string> | undefined
283
284
  for (const importer of importers) {
284
- const from = availabilityAt(available, importer, memo);
285
- inherited = inherited === undefined ? new Set(from) : intersect(inherited, from);
285
+ const from = availabilityAt(available, importer, memo)
286
+ inherited = inherited === undefined ? new Set(from) : intersect(inherited, from)
286
287
  }
287
- const next = new Set([...closures.get(target)!, ...(inherited ?? [])]);
288
+ const next = new Set([...closures.get(target)!, ...(inherited ?? [])])
288
289
  if (next.size !== available.get(target)!.size) {
289
- available.set(target, next);
290
- memo.clear();
291
- changed = true;
290
+ available.set(target, next)
291
+ memo.clear()
292
+ changed = true
292
293
  }
293
294
  }
294
- if (!changed) break;
295
+ if (!changed) break
295
296
  }
296
- return available;
297
+ return available
297
298
  }
298
299
 
299
300
  function staticClosure(metafile: Metafile, root: string) {
300
- const seen = new Set([root]);
301
- const queue = [root];
301
+ const seen = new Set([root])
302
+ const queue = [root]
302
303
  // `queue` grows inside the loop — a breadth-first walk of the chunk graph.
303
304
  for (const current of queue) {
304
305
  for (const imported of metafile.outputs[current]?.imports ?? []) {
305
- if (imported.kind !== 'import-statement') continue;
306
- if (seen.has(imported.path)) continue;
307
- seen.add(imported.path);
308
- queue.push(imported.path);
306
+ if (imported.kind !== 'import-statement') continue
307
+ if (seen.has(imported.path)) continue
308
+ seen.add(imported.path)
309
+ queue.push(imported.path)
309
310
  }
310
311
  }
311
- return seen;
312
+ return seen
312
313
  }
313
314
 
314
315
  function intersect(a: Set<string>, b: Set<string>) {
315
- return new Set([...a].filter(item => b.has(item)));
316
+ return new Set([...a].filter(item => b.has(item)))
316
317
  }
317
318
 
318
319
  /**
@@ -320,24 +321,26 @@ function intersect(a: Set<string>, b: Set<string>) {
320
321
  * collide across chunks, so the barrel renames them apart.
321
322
  */
322
323
  function memberAliases(memberNames: string[], sources: Map<string, string>) {
323
- const aliases = new Map<string, Map<string, string>>();
324
+ const aliases = new Map<string, Map<string, string>>()
324
325
  for (const [index, name] of memberNames.entries()) {
325
- const source = sources.get(name)!;
326
+ const source = sources.get(name)!
326
327
  // A star re-export can't be aliased name-by-name; nothing to fold safely.
327
- if (/export\s*\*/.test(source)) return undefined;
328
+ if (/export\s*\*/.test(source)) return undefined
328
329
  // The export clause is the chunk's last one — a linked sourcemap comment
329
330
  // can follow it, so anchor on "last `export{…}` that isn't a re-export"
330
331
  // rather than on end-of-file.
331
- const clauses = [...source.matchAll(new RegExp(String.raw`export\s*${namedClause}\s*(?!from)`, 'g'))];
332
- const clause = clauses.at(-1);
333
- const names = new Map<string, string>();
332
+ const clauses = [
333
+ ...source.matchAll(new RegExp(String.raw`export\s*${namedClause}\s*(?!from)`, 'g')),
334
+ ]
335
+ const clause = clauses.at(-1)
336
+ const names = new Map<string, string>()
334
337
  for (const part of clause?.[1]?.split(',') ?? []) {
335
- const exported = part.split(' as ').at(-1)?.trim();
336
- if (exported) names.set(exported, `$${index}${exported}`);
338
+ const exported = part.split(' as ').at(-1)?.trim()
339
+ if (exported) names.set(exported, `$${index}${exported}`)
337
340
  }
338
- aliases.set(name, names);
341
+ aliases.set(name, names)
339
342
  }
340
- return aliases;
343
+ return aliases
341
344
  }
342
345
 
343
346
  /**
@@ -350,53 +353,55 @@ function memberRewriter(
350
353
  aliases: Map<string, Map<string, string>>,
351
354
  chunksDir: string,
352
355
  ) {
353
- const memberPattern = memberNames.map(escapeRegex).join('|');
354
- const specifier = String.raw`"\.[^"]*(?:${memberPattern})"`;
356
+ const memberPattern = memberNames.map(escapeRegex).join('|')
357
+ const specifier = String.raw`"\.[^"]*(?:${memberPattern})"`
355
358
  // Forms that can't be expressed against a renaming barrel.
356
359
  const vetoes = [
357
360
  new RegExp(String.raw`import\s*\*\s*as\s*[\w$]+\s*from\s*${specifier}`),
358
361
  new RegExp(String.raw`export\s*\*[^;]*from\s*${specifier}`),
359
362
  new RegExp(String.raw`import\(\s*${specifier}`),
360
- ];
363
+ ]
361
364
  const namedImport = new RegExp(
362
365
  String.raw`(import|export)\s*${namedClause}\s*from\s*(${specifier})`,
363
366
  'g',
364
- );
365
- const sideEffectImport = new RegExp(String.raw`import\s*(${specifier})`, 'g');
367
+ )
368
+ const sideEffectImport = new RegExp(String.raw`import\s*(${specifier})`, 'g')
366
369
 
367
- const nameOf = (spec: string) => memberNames.find(name => spec.includes(name))!;
370
+ const nameOf = (spec: string) => memberNames.find(name => spec.includes(name))!
368
371
  const rename = (clause: string, member: string) =>
369
372
  clause
370
373
  .split(',')
371
374
  .map(part => {
372
- const [imported, local] = part.split(' as ').map(item => item.trim());
373
- if (!imported) return part;
374
- const alias = aliases.get(member)?.get(imported);
375
- if (!alias) return part;
376
- return `${alias} as ${local ?? imported}`;
375
+ const [imported, local] = part.split(' as ').map(item => item.trim())
376
+ if (!imported) return part
377
+ const alias = aliases.get(member)?.get(imported)
378
+ if (!alias) return part
379
+ return `${alias} as ${local ?? imported}`
377
380
  })
378
- .join(',');
381
+ .join(',')
379
382
 
380
383
  return (source: string, file: string) => {
381
- for (const veto of vetoes) if (veto.test(source)) return null;
384
+ for (const veto of vetoes) if (veto.test(source)) return null
382
385
  const mergedHref = path
383
386
  .relative(path.dirname(file), path.join(chunksDir, MERGED_PLACEHOLDER))
384
387
  .split(path.sep)
385
- .join('/');
386
- const href = mergedHref.startsWith('.') ? mergedHref : `./${mergedHref}`;
387
- return source
388
- .replace(
389
- namedImport,
390
- (_all, keyword: string, clause: string, spec: string) =>
391
- `${keyword}{${rename(clause, nameOf(spec))}}from"${href}"`,
392
- )
393
- // Side-effect-only imports of a member collapse onto the merged chunk.
394
- .replace(sideEffectImport, () => `import"${href}"`);
395
- };
388
+ .join('/')
389
+ const href = mergedHref.startsWith('.') ? mergedHref : `./${mergedHref}`
390
+ return (
391
+ source
392
+ .replace(
393
+ namedImport,
394
+ (_all, keyword: string, clause: string, spec: string) =>
395
+ `${keyword}{${rename(clause, nameOf(spec))}}from"${href}"`,
396
+ )
397
+ // Side-effect-only imports of a member collapse onto the merged chunk.
398
+ .replace(sideEffectImport, () => `import"${href}"`)
399
+ )
400
+ }
396
401
  }
397
402
 
398
403
  /** Stands in for the merged chunk's final (content-hashed) name. */
399
- const MERGED_PLACEHOLDER = 'pnext-merged';
404
+ const MERGED_PLACEHOLDER = 'pnext-merged'
400
405
 
401
406
  async function buildMergedChunk(
402
407
  chunksDir: string,
@@ -406,16 +411,16 @@ async function buildMergedChunk(
406
411
  ) {
407
412
  const barrel = memberNames
408
413
  .map(name => {
409
- const names = aliases.get(name)!;
410
- const spec = JSON.stringify(`./${name}`);
411
- if (names.size === 0) return `import ${spec};`;
412
- const clause = [...names].map(([exported, alias]) => `${exported} as ${alias}`).join(',');
413
- return `export {${clause}} from ${spec};`;
414
+ const names = aliases.get(name)!
415
+ const spec = JSON.stringify(`./${name}`)
416
+ if (names.size === 0) return `import ${spec};`
417
+ const clause = [...names].map(([exported, alias]) => `${exported} as ${alias}`).join(',')
418
+ return `export {${clause}} from ${spec};`
414
419
  })
415
- .join('\n');
420
+ .join('\n')
416
421
 
417
- const barrelPath = path.join(chunksDir, '__pnext-fold-barrel.js');
418
- await writeText(barrelPath, barrel);
422
+ const barrelPath = path.join(chunksDir, '__pnext-fold-barrel.js')
423
+ await writeText(barrelPath, barrel)
419
424
  try {
420
425
  const result = await build({
421
426
  minify: buildOptions.minify,
@@ -433,94 +438,94 @@ async function buildMergedChunk(
433
438
  name: 'pnext-fold-members',
434
439
  setup(builder) {
435
440
  builder.onResolve({ filter: /.*/ }, args => {
436
- if (args.kind === 'entry-point') return undefined;
437
- const base = path.basename(args.path);
438
- if (memberNames.includes(base)) return { path: path.join(chunksDir, base) };
439
- return { path: args.path, external: true };
440
- });
441
+ if (args.kind === 'entry-point') return undefined
442
+ const base = path.basename(args.path)
443
+ if (memberNames.includes(base)) return { path: path.join(chunksDir, base) }
444
+ return { path: args.path, external: true }
445
+ })
441
446
  },
442
447
  },
443
448
  ],
444
- });
445
- const js = result.outputFiles?.find(file => file.path.endsWith('.js'));
446
- if (!js) return undefined;
447
- const hash = createHash('sha256').update(js.contents).digest('hex').slice(0, 8).toUpperCase();
448
- const name = `shared-init-${hash}.js`;
449
- const map = result.outputFiles?.find(file => file.path.endsWith('.js.map'));
450
- let contents = new TextDecoder().decode(js.contents);
449
+ })
450
+ const js = result.outputFiles?.find(file => file.path.endsWith('.js'))
451
+ if (!js) return undefined
452
+ const hash = createHash('sha256').update(js.contents).digest('hex').slice(0, 8).toUpperCase()
453
+ const name = `shared-init-${hash}.js`
454
+ const map = result.outputFiles?.find(file => file.path.endsWith('.js.map'))
455
+ let contents = new TextDecoder().decode(js.contents)
451
456
  if (map) {
452
- contents = contents.replace(/# sourceMappingURL=.*$/m, `# sourceMappingURL=${name}.map`);
453
- await writeText(path.join(chunksDir, `${name}.map`), new TextDecoder().decode(map.contents));
457
+ contents = contents.replace(/# sourceMappingURL=.*$/m, `# sourceMappingURL=${name}.map`)
458
+ await writeText(path.join(chunksDir, `${name}.map`), new TextDecoder().decode(map.contents))
454
459
  }
455
- await writeText(path.join(chunksDir, name), contents);
456
- return { name, text: contents, bytes: Buffer.byteLength(contents) };
460
+ await writeText(path.join(chunksDir, name), contents)
461
+ return { name, text: contents, bytes: Buffer.byteLength(contents) }
457
462
  } finally {
458
- await unlink(barrelPath).catch(ignoreMissing);
463
+ await unlink(barrelPath).catch(ignoreMissing)
459
464
  }
460
465
  }
461
466
 
462
467
  /** An output file's text plus the relative specifiers it imports through. */
463
468
  interface FoldOutput {
464
- text: string;
465
- specifiers: string[];
469
+ text: string
470
+ specifiers: string[]
466
471
  }
467
472
 
468
473
  function foldOutput(text: string): FoldOutput {
469
- return { text, specifiers: [...text.matchAll(/"\.[^"]*"/g)].map(match => match[0]) };
474
+ return { text, specifiers: [...text.matchAll(/"\.[^"]*"/g)].map(match => match[0]) }
470
475
  }
471
476
 
472
477
  /** Every output's text plus a basename->referrers index, read once. Chunk names
473
478
  * are content-hashed, so a specifier naming a member spells it as its basename. */
474
479
  interface FoldState {
475
- outputs: Map<string, FoldOutput>;
480
+ outputs: Map<string, FoldOutput>
476
481
  /** Files whose specifiers name any of `names`, each visited once. */
477
- referrersOf(names: string[]): Iterable<string>;
478
- set(file: string, output: FoldOutput): void;
479
- remove(file: string): void;
482
+ referrersOf(names: string[]): Iterable<string>
483
+ set(file: string, output: FoldOutput): void
484
+ remove(file: string): void
480
485
  }
481
486
 
482
487
  async function createFoldState(outDir: string, metafile: Metafile): Promise<FoldState> {
483
- const outputs = new Map<string, FoldOutput>();
484
- const referrers = new Map<string, Set<string>>();
488
+ const outputs = new Map<string, FoldOutput>()
489
+ const referrers = new Map<string, Set<string>>()
485
490
 
486
491
  const index = (file: string, output: FoldOutput, add: boolean) => {
487
492
  for (const spec of output.specifiers) {
488
- const base = path.basename(spec.slice(1, -1));
489
- const set = referrers.get(base) ?? referrers.set(base, new Set()).get(base)!;
490
- if (add) set.add(file);
491
- else set.delete(file);
493
+ const base = path.basename(spec.slice(1, -1))
494
+ const set = referrers.get(base) ?? referrers.set(base, new Set()).get(base)!
495
+ if (add) set.add(file)
496
+ else set.delete(file)
492
497
  }
493
- };
498
+ }
494
499
 
495
500
  for (const name of Object.keys(metafile.outputs)) {
496
- if (!name.endsWith('.js')) continue;
497
- const resolved = path.resolve(name);
498
- const local = existsSync(resolved) ? resolved : path.join(outDir, path.basename(name));
499
- if (outputs.has(local) || !existsSync(local)) continue;
500
- const output = foldOutput(await readText(local));
501
- outputs.set(local, output);
502
- index(local, output, true);
501
+ if (!name.endsWith('.js')) continue
502
+ const resolved = path.resolve(name)
503
+ const local = existsSync(resolved) ? resolved : path.join(outDir, path.basename(name))
504
+ if (outputs.has(local) || !existsSync(local)) continue
505
+ const output = foldOutput(await readText(local))
506
+ outputs.set(local, output)
507
+ index(local, output, true)
503
508
  }
504
509
 
505
510
  return {
506
511
  outputs,
507
512
  referrersOf(names) {
508
- const seen = new Set<string>();
509
- for (const name of names) for (const file of referrers.get(name) ?? []) seen.add(file);
510
- return seen;
513
+ const seen = new Set<string>()
514
+ for (const name of names) for (const file of referrers.get(name) ?? []) seen.add(file)
515
+ return seen
511
516
  },
512
517
  set(file, output) {
513
- const previous = outputs.get(file);
514
- if (previous) index(file, previous, false);
515
- outputs.set(file, output);
516
- index(file, output, true);
518
+ const previous = outputs.get(file)
519
+ if (previous) index(file, previous, false)
520
+ outputs.set(file, output)
521
+ index(file, output, true)
517
522
  },
518
523
  remove(file) {
519
- const previous = outputs.get(file);
520
- if (previous) index(file, previous, false);
521
- outputs.delete(file);
524
+ const previous = outputs.get(file)
525
+ if (previous) index(file, previous, false)
526
+ outputs.delete(file)
522
527
  },
523
- };
528
+ }
524
529
  }
525
530
 
526
531
  /** The shipped graph, with the members collapsed into the merged chunk. */
@@ -530,37 +535,37 @@ function mergeMetafile(
530
535
  mergedPath: string,
531
536
  bytes: number,
532
537
  ): Metafile {
533
- const memberSet = new Set(members);
534
- const merged = path.relative(process.cwd(), mergedPath);
535
- const outputs: Metafile['outputs'] = {};
536
- const mergedImports: Metafile['outputs'][string]['imports'] = [];
537
- const mergedInputs: Metafile['outputs'][string]['inputs'] = {};
538
+ const memberSet = new Set(members)
539
+ const merged = path.relative(process.cwd(), mergedPath)
540
+ const outputs: Metafile['outputs'] = {}
541
+ const mergedImports: Metafile['outputs'][string]['imports'] = []
542
+ const mergedInputs: Metafile['outputs'][string]['inputs'] = {}
538
543
 
539
544
  for (const [file, output] of Object.entries(metafile.outputs)) {
540
545
  const remap = (list: typeof output.imports) => {
541
- const seen = new Set<string>();
546
+ const seen = new Set<string>()
542
547
  return list.flatMap(imported => {
543
- const target = memberSet.has(imported.path) ? merged : imported.path;
544
- const key = `${target}:${imported.kind}`;
545
- if (seen.has(key)) return [];
546
- seen.add(key);
547
- return [{ ...imported, path: target }];
548
- });
549
- };
548
+ const target = memberSet.has(imported.path) ? merged : imported.path
549
+ const key = `${target}:${imported.kind}`
550
+ if (seen.has(key)) return []
551
+ seen.add(key)
552
+ return [{ ...imported, path: target }]
553
+ })
554
+ }
550
555
  if (memberSet.has(file)) {
551
- Object.assign(mergedInputs, output.inputs);
556
+ Object.assign(mergedInputs, output.inputs)
552
557
  for (const imported of remap(output.imports ?? [])) {
553
- if (imported.path !== merged) mergedImports.push(imported);
558
+ if (imported.path !== merged) mergedImports.push(imported)
554
559
  }
555
- continue;
560
+ continue
556
561
  }
557
- outputs[file] = { ...output, imports: remap(output.imports ?? []) };
562
+ outputs[file] = { ...output, imports: remap(output.imports ?? []) }
558
563
  }
559
564
  outputs[merged] = {
560
565
  imports: mergedImports,
561
566
  exports: [],
562
567
  inputs: mergedInputs,
563
568
  bytes,
564
- };
565
- return { ...metafile, outputs };
569
+ }
570
+ return { ...metafile, outputs }
566
571
  }