@wular/pnext 0.0.3 → 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 -1961
  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 -1887
  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} +152 -143
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +442 -186
  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 +833 -848
  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
@@ -1,13 +1,13 @@
1
- import { createHash } from 'node:crypto';
2
- import { readFileSync, readdirSync, statSync, type Dirent } from 'node:fs';
3
- import path from 'node:path';
4
- import { build, type BuildOptions, type Metafile, type Plugin } from 'esbuild';
5
- import type { ResolvedConfig } from '../config';
6
- import { getImportAliasExtensions } from '../extensions';
7
- import { scanFacts } from '../resolve/scan-facts';
8
- import { ensureDir, writeText } from '../utils/fs';
9
- import { escapeRegex } from '../utils/source';
10
- import { CLIENT_RUNTIME_MODULE } from './entry';
1
+ import { createHash } from 'node:crypto'
2
+ import { readFileSync, readdirSync, statSync, type Dirent } from 'node:fs'
3
+ import path from 'node:path'
4
+ import { build, type BuildOptions, type Metafile, type Plugin } from 'esbuild'
5
+ import type { ResolvedConfig } from '../config'
6
+ import { getImportAliasExtensions } from '../extensions'
7
+ import { scanFacts } from '../resolve/scan-facts'
8
+ import { ensureDir, writeText } from '../utils/fs'
9
+ import { escapeRegex } from '../utils/code'
10
+ import { CLIENT_RUNTIME_MODULE } from './entry'
11
11
 
12
12
  /**
13
13
  * The route-independent half of every client bundle - pnext's own client runtime, the compat
@@ -22,29 +22,29 @@ import { CLIENT_RUNTIME_MODULE } from './entry';
22
22
  */
23
23
  export interface PrebuiltRuntime {
24
24
  /** Content address of (framework source × alias set × build options). */
25
- key: string;
25
+ key: string
26
26
  /** Directory holding the artifact. */
27
- dir: string;
27
+ dir: string
28
28
  /** URL prefix route entries import the artifact from — the SERVED url. */
29
- publicPath: string;
29
+ publicPath: string
30
30
  /**
31
31
  * The same directory as an `assets/…` path, for the preload bookkeeping that
32
32
  * speaks in app-relative asset names rather than urls.
33
33
  */
34
- assetPath: string;
34
+ assetPath: string
35
35
  /** specifier → every export name that module has (learned by a probe build). */
36
- exports: Map<string, string[]>;
36
+ exports: Map<string, string[]>
37
37
  /** specifier → the export names route entries actually bind. What ships. */
38
- surface: Map<string, Set<string>>;
38
+ surface: Map<string, Set<string>>
39
39
  /** Artifact files statically reachable from the aggregate, relative to it. */
40
- closure: { static: string[]; dynamic: string[] };
40
+ closure: { static: string[]; dynamic: string[] }
41
41
  }
42
42
 
43
43
  /** The aggregate's file name inside the artifact dir. */
44
- export const PREBUILT_MODULE = 'pnext-runtime.js';
44
+ export const PREBUILT_MODULE = 'pnext-runtime.js'
45
45
 
46
46
  /** Framework source root — anything resolving inside it is route-independent. */
47
- const frameworkSrc = path.resolve(import.meta.dirname, '..');
47
+ const frameworkSrc = path.resolve(import.meta.dirname, '..')
48
48
 
49
49
  /**
50
50
  * The vendor half of the surface. Single-instance modules (context identity,
@@ -58,7 +58,7 @@ const vendorSpecifiers = [
58
58
  'preact/compat/client',
59
59
  'preact/jsx-runtime',
60
60
  'preact/jsx-dev-runtime',
61
- ];
61
+ ]
62
62
 
63
63
  /**
64
64
  * The react-compat aliases seed the artifact alongside the vendors: their targets are `export *`
@@ -66,37 +66,37 @@ const vendorSpecifiers = [
66
66
  * preact/compat's WHOLE surface. Everything else is discovered lazily - a leaf compat module
67
67
  * bundled once costs only what its importer named.
68
68
  */
69
- const reactAliasSpecifier = /^react(?:-dom)?(?:\/|$)/;
69
+ const reactAliasSpecifier = /^react(?:-dom)?(?:\/|$)/
70
70
 
71
71
  /**
72
72
  * The React Compiler's runtime is resolved per build (and asserted on in the
73
73
  * route bundle), so it stays out of the artifact.
74
74
  */
75
- const isCompilerRuntime = (specifier: string) => specifier.endsWith('compiler-runtime');
75
+ const isCompilerRuntime = (specifier: string) => specifier.endsWith('compiler-runtime')
76
76
 
77
- const identifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
77
+ const identifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/
78
78
 
79
79
  /** (specifier, export name) → one collision-free identifier in the aggregate. */
80
80
  export function mangledName(specifier: string, name: string) {
81
- return `__p_${shortHash(specifier)}_${name}`;
81
+ return `__p_${shortHash(specifier)}_${name}`
82
82
  }
83
83
 
84
84
  function shortHash(value: string) {
85
- return createHash('sha1').update(value).digest('hex').slice(0, 8);
85
+ return createHash('sha1').update(value).digest('hex').slice(0, 8)
86
86
  }
87
87
 
88
88
  function seedSpecifiers(aliases: string[]) {
89
89
  const react = aliases.filter(
90
90
  alias => reactAliasSpecifier.test(alias) && !isCompilerRuntime(alias),
91
- );
92
- return [...new Set([...vendorSpecifiers, ...react])];
91
+ )
92
+ return [...new Set([...vendorSpecifiers, ...react])]
93
93
  }
94
94
 
95
95
  /** Every framework specifier this app could demand: aliases + preact + pnext src. */
96
96
  export function prebuiltSpecifierFilter(config: ResolvedConfig): RegExp {
97
- const aliases = Object.keys(getImportAliasExtensions().aliases(config, 'client'));
98
- const bare = [...new Set([...aliases, ...vendorSpecifiers])];
99
- return new RegExp(`^(?:${bare.map(escapeRegex).join('|')}|${escapeRegex(frameworkSrc)}/)`);
97
+ const aliases = Object.keys(getImportAliasExtensions().aliases(config, 'client'))
98
+ const bare = [...new Set([...aliases, ...vendorSpecifiers])]
99
+ return new RegExp(`^(?:${bare.map(escapeRegex).join('|')}|${escapeRegex(frameworkSrc)}/)`)
100
100
  }
101
101
 
102
102
  /**
@@ -106,10 +106,10 @@ export function prebuiltSpecifierFilter(config: ResolvedConfig): RegExp {
106
106
  * glue whose weight - router, compat, preact - is external through it anyway.
107
107
  */
108
108
  export function isFrameworkSpecifier(specifier: string, filter: RegExp) {
109
- if (specifier === CLIENT_RUNTIME_MODULE) return false;
110
- if (isCompilerRuntime(specifier)) return false;
111
- if (specifier.startsWith(frameworkSrc)) return true;
112
- return filter.test(specifier) && !specifier.startsWith('.');
109
+ if (specifier === CLIENT_RUNTIME_MODULE) return false
110
+ if (isCompilerRuntime(specifier)) return false
111
+ if (specifier.startsWith(frameworkSrc)) return true
112
+ return filter.test(specifier) && !specifier.startsWith('.')
113
113
  }
114
114
 
115
115
  /**
@@ -124,59 +124,64 @@ export function prebuiltRuntimeKey(
124
124
  buildOptions: BuildOptions,
125
125
  signature = '',
126
126
  ) {
127
- const hash = createHash('sha1');
128
- hash.update(frameworkSourceHash());
129
- hash.update('\0');
130
- hash.update(JSON.stringify(Object.keys(getImportAliasExtensions().aliases(config, 'client'))));
131
- hash.update('\0');
127
+ const hash = createHash('sha1')
128
+ hash.update(frameworkSourceHash())
129
+ hash.update('\0')
130
+ hash.update(JSON.stringify(Object.keys(getImportAliasExtensions().aliases(config, 'client'))))
131
+ hash.update('\0')
132
132
  hash.update(
133
- JSON.stringify([buildOptions.define, buildOptions.minify, buildOptions.target, buildOptions.pure]),
134
- );
135
- hash.update('\0');
136
- hash.update(signature);
137
- return hash.digest('hex').slice(0, 16);
133
+ JSON.stringify([
134
+ buildOptions.define,
135
+ buildOptions.minify,
136
+ buildOptions.target,
137
+ buildOptions.pure,
138
+ ]),
139
+ )
140
+ hash.update('\0')
141
+ hash.update(signature)
142
+ return hash.digest('hex').slice(0, 16)
138
143
  }
139
144
 
140
- let cachedSourceHash: string | undefined;
145
+ let cachedSourceHash: string | undefined
141
146
 
142
147
  /**
143
148
  * Hash of pnext's own source. Cheap on the cold path: mtime+size per file, not contents - the tree is
144
149
  * pnext's own install, so a same-mtime file is the same file.
145
150
  */
146
151
  function frameworkSourceHash() {
147
- if (cachedSourceHash) return cachedSourceHash;
148
- const hash = createHash('sha1');
152
+ if (cachedSourceHash) return cachedSourceHash
153
+ const hash = createHash('sha1')
149
154
  const walk = (dir: string) => {
150
- let entries: Dirent[];
155
+ let entries: Dirent[]
151
156
  try {
152
- entries = readdirSync(dir, { withFileTypes: true });
157
+ entries = readdirSync(dir, { withFileTypes: true })
153
158
  } catch {
154
- return;
159
+ return
155
160
  }
156
161
  for (const entry of entries.sort((a, b) => (a.name < b.name ? -1 : 1))) {
157
- const file = path.join(dir, entry.name);
158
- if (entry.isDirectory()) walk(file);
162
+ const file = path.join(dir, entry.name)
163
+ if (entry.isDirectory()) walk(file)
159
164
  else if (/\.(?:tsx?|jsx?|mjs|cjs)$/.test(entry.name)) {
160
- const stats = statSync(file, { throwIfNoEntry: false });
161
- if (stats) hash.update(`${file}:${stats.size}:${stats.mtimeMs}\n`);
165
+ const stats = statSync(file, { throwIfNoEntry: false })
166
+ if (stats) hash.update(`${file}:${stats.size}:${stats.mtimeMs}\n`)
162
167
  }
163
168
  }
164
- };
165
- walk(frameworkSrc);
166
- cachedSourceHash = hash.digest('hex').slice(0, 16);
167
- return cachedSourceHash;
169
+ }
170
+ walk(frameworkSrc)
171
+ cachedSourceHash = hash.digest('hex').slice(0, 16)
172
+ return cachedSourceHash
168
173
  }
169
174
 
170
175
  export interface ArtifactOptions {
171
176
  /** The client import aliases in force, part of the key and of the seed. */
172
- aliases: string[];
173
- dir: string;
174
- publicPath: string;
175
- assetPath: string;
176
- key: string;
177
- buildOptions: BuildOptions;
177
+ aliases: string[]
178
+ dir: string
179
+ publicPath: string
180
+ assetPath: string
181
+ key: string
182
+ buildOptions: BuildOptions
178
183
  /** Fresh plugin chain per build — esbuild plugins carry per-build state. */
179
- plugins: () => Plugin[];
184
+ plugins: () => Plugin[]
180
185
  }
181
186
 
182
187
  /**
@@ -187,15 +192,15 @@ export interface ArtifactOptions {
187
192
  * re-export through several levels of their own stars.
188
193
  */
189
194
  async function probeExports(specifiers: string[], options: ArtifactOptions) {
190
- const found = new Map<string, string[]>();
191
- if (specifiers.length === 0) return found;
192
- const probeDir = path.join(options.dir, '.probe');
193
- await ensureDir(probeDir);
194
- const entryPoints: { in: string; out: string }[] = [];
195
+ const found = new Map<string, string[]>()
196
+ if (specifiers.length === 0) return found
197
+ const probeDir = path.join(options.dir, '.probe')
198
+ await ensureDir(probeDir)
199
+ const entryPoints: { in: string; out: string }[] = []
195
200
  for (const specifier of specifiers) {
196
- const file = path.join(probeDir, `${shortHash(specifier)}.ts`);
197
- await writeText(file, `export * from ${JSON.stringify(specifier)};\n`);
198
- entryPoints.push({ in: file, out: shortHash(specifier) });
201
+ const file = path.join(probeDir, `${shortHash(specifier)}.ts`)
202
+ await writeText(file, `export * from ${JSON.stringify(specifier)};\n`)
203
+ entryPoints.push({ in: file, out: shortHash(specifier) })
199
204
  }
200
205
  const result = await build({
201
206
  ...options.buildOptions,
@@ -206,15 +211,18 @@ async function probeExports(specifiers: string[], options: ArtifactOptions) {
206
211
  write: false,
207
212
  metafile: true,
208
213
  plugins: options.plugins(),
209
- });
214
+ })
210
215
  for (const specifier of specifiers) {
211
216
  const output = Object.entries(result.metafile.outputs).find(
212
217
  ([name]) => path.basename(name) === `${shortHash(specifier)}.js`,
213
- );
218
+ )
214
219
  // `export *` never carries `default`; probeSurface asks for it separately.
215
- found.set(specifier, (output?.[1].exports ?? []).filter(name => identifier.test(name)));
220
+ found.set(
221
+ specifier,
222
+ (output?.[1].exports ?? []).filter(name => identifier.test(name)),
223
+ )
216
224
  }
217
- return found;
225
+ return found
218
226
  }
219
227
 
220
228
  /**
@@ -226,18 +234,18 @@ async function probeExports(specifiers: string[], options: ArtifactOptions) {
226
234
  * once, unwritten, and every name that did not materialize is dropped.
227
235
  */
228
236
  async function probeSurface(specifiers: string[], options: ArtifactOptions) {
229
- const probed = await probeExports(specifiers, options);
230
- if (probed.size === 0) return probed;
237
+ const probed = await probeExports(specifiers, options)
238
+ if (probed.size === 0) return probed
231
239
  const candidate = new Map(
232
240
  [...probed].map(([specifier, names]) => [specifier, new Set([...names, 'default'])]),
233
- );
234
- const { text } = await buildAggregate(options, candidate, false);
241
+ )
242
+ const { text } = await buildAggregate(options, candidate, false)
235
243
  return new Map(
236
244
  [...candidate].map(([specifier, names]) => [
237
245
  specifier,
238
246
  [...names].filter(name => text.includes(mangledName(specifier, name))),
239
247
  ]),
240
- );
248
+ )
241
249
  }
242
250
 
243
251
  /**
@@ -249,20 +257,20 @@ async function buildAggregate(
249
257
  surface: Map<string, Set<string>>,
250
258
  write: boolean,
251
259
  ) {
252
- const lines: string[] = [];
260
+ const lines: string[] = []
253
261
  for (const specifier of [...surface.keys()].sort()) {
254
- const names = [...surface.get(specifier)!].filter(name => identifier.test(name)).sort();
255
- const spec = JSON.stringify(specifier);
256
- if (names.length === 0) lines.push(`import ${spec};`);
262
+ const names = [...surface.get(specifier)!].filter(name => identifier.test(name)).sort()
263
+ const spec = JSON.stringify(specifier)
264
+ if (names.length === 0) lines.push(`import ${spec};`)
257
265
  else {
258
- const clause = names.map(name => `${name} as ${mangledName(specifier, name)}`).join(', ');
259
- lines.push(`export { ${clause} } from ${spec};`);
266
+ const clause = names.map(name => `${name} as ${mangledName(specifier, name)}`).join(', ')
267
+ lines.push(`export { ${clause} } from ${spec};`)
260
268
  }
261
269
  }
262
- const aggregateDir = path.join(options.dir, '.aggregate');
263
- await ensureDir(aggregateDir);
264
- const entry = path.join(aggregateDir, 'runtime.ts');
265
- await writeText(entry, `${lines.join('\n')}\n`);
270
+ const aggregateDir = path.join(options.dir, '.aggregate')
271
+ await ensureDir(aggregateDir)
272
+ const entry = path.join(aggregateDir, 'runtime.ts')
273
+ await writeText(entry, `${lines.join('\n')}\n`)
266
274
 
267
275
  const result = await build({
268
276
  ...options.buildOptions,
@@ -273,17 +281,17 @@ async function buildAggregate(
273
281
  write,
274
282
  metafile: true,
275
283
  plugins: options.plugins(),
276
- });
277
- const emitted = result.outputFiles?.find(file => path.basename(file.path) === PREBUILT_MODULE);
278
- const text = emitted?.text ?? readFileSafe(path.join(options.dir, PREBUILT_MODULE));
279
- return { text, metafile: result.metafile };
284
+ })
285
+ const emitted = result.outputFiles?.find(file => path.basename(file.path) === PREBUILT_MODULE)
286
+ const text = emitted?.text ?? readFileSafe(path.join(options.dir, PREBUILT_MODULE))
287
+ return { text, metafile: result.metafile }
280
288
  }
281
289
 
282
290
  function readFileSafe(file: string) {
283
291
  try {
284
- return readFileSync(file, 'utf8');
292
+ return readFileSync(file, 'utf8')
285
293
  } catch {
286
- return '';
294
+ return ''
287
295
  }
288
296
  }
289
297
 
@@ -297,7 +305,7 @@ export async function buildPrebuiltRuntime(
297
305
  exportsBySpecifier: Map<string, string[]>,
298
306
  surface: Map<string, Set<string>>,
299
307
  ): Promise<PrebuiltRuntime> {
300
- const { metafile } = await buildAggregate(options, surface, true);
308
+ const { metafile } = await buildAggregate(options, surface, true)
301
309
  return {
302
310
  key: options.key,
303
311
  dir: options.dir,
@@ -306,33 +314,32 @@ export async function buildPrebuiltRuntime(
306
314
  exports: exportsBySpecifier,
307
315
  surface,
308
316
  closure: aggregateClosure(metafile),
309
- };
317
+ }
310
318
  }
311
319
 
312
-
313
320
  function aggregateClosure(metafile: Metafile) {
314
- const entry = Object.keys(metafile.outputs).find(name => path.basename(name) === PREBUILT_MODULE);
315
- const statics = new Set<string>();
316
- const dynamics = new Set<string>();
317
- if (!entry) return { static: [], dynamic: [] };
318
- const seen = new Set([`${entry}:static`]);
319
- const queue = [{ output: entry, dynamic: false }];
321
+ const entry = Object.keys(metafile.outputs).find(name => path.basename(name) === PREBUILT_MODULE)
322
+ const statics = new Set<string>()
323
+ const dynamics = new Set<string>()
324
+ if (!entry) return { static: [], dynamic: [] }
325
+ const seen = new Set([`${entry}:static`])
326
+ const queue = [{ output: entry, dynamic: false }]
320
327
  // eslint-disable-next-line @typescript-eslint/prefer-for-of
321
328
  for (let head = 0; head < queue.length; head += 1) {
322
- const current = queue[head]!;
329
+ const current = queue[head]!
323
330
  for (const imported of metafile.outputs[current.output]?.imports ?? []) {
324
- if (imported.kind !== 'import-statement' && imported.kind !== 'dynamic-import') continue;
325
- const dynamic = current.dynamic || imported.kind === 'dynamic-import';
326
- const visitKey = `${imported.path}:${dynamic ? 'dynamic' : 'static'}`;
327
- if (seen.has(visitKey)) continue;
328
- seen.add(visitKey);
329
- queue.push({ output: imported.path, dynamic });
330
- const relative = path.relative(path.dirname(entry), imported.path).split(path.sep).join('/');
331
- (dynamic ? dynamics : statics).add(relative);
331
+ if (imported.kind !== 'import-statement' && imported.kind !== 'dynamic-import') continue
332
+ const dynamic = current.dynamic || imported.kind === 'dynamic-import'
333
+ const visitKey = `${imported.path}:${dynamic ? 'dynamic' : 'static'}`
334
+ if (seen.has(visitKey)) continue
335
+ seen.add(visitKey)
336
+ queue.push({ output: imported.path, dynamic })
337
+ const relative = path.relative(path.dirname(entry), imported.path).split(path.sep).join('/')
338
+ ;(dynamic ? dynamics : statics).add(relative)
332
339
  }
333
340
  }
334
- for (const name of statics) dynamics.delete(name);
335
- return { static: [...statics], dynamic: [...dynamics] };
341
+ for (const name of statics) dynamics.delete(name)
342
+ return { static: [...statics], dynamic: [...dynamics] }
336
343
  }
337
344
  /**
338
345
  * Route-build seam. A framework specifier resolves to a virtual module that re-exports the target's
@@ -347,50 +354,48 @@ export function prebuiltExternalPlugin(
347
354
  unprobed: Set<string>,
348
355
  sourceOf: (importer: string) => string | undefined,
349
356
  ): Plugin {
350
- const namespace = 'pnext-prebuilt';
351
- const moduleUrl = prebuiltModuleUrl(runtime);
357
+ const namespace = 'pnext-prebuilt'
358
+ const moduleUrl = prebuiltModuleUrl(runtime)
352
359
  return {
353
360
  name: 'pnext-prebuilt-runtime',
354
361
  setup(build) {
355
362
  build.onResolve({ filter: new RegExp(`^${escapeRegex(moduleUrl)}$`) }, () => ({
356
363
  path: moduleUrl,
357
364
  external: true,
358
- }));
365
+ }))
359
366
  build.onResolve({ filter }, args => {
360
- if (args.namespace === namespace) return undefined;
361
- if (!isFrameworkSpecifier(args.path, filter)) return undefined;
367
+ if (args.namespace === namespace) return undefined
368
+ if (!isFrameworkSpecifier(args.path, filter)) return undefined
362
369
  if (!runtime.exports.has(args.path)) {
363
- unprobed.add(args.path);
364
- return undefined;
370
+ unprobed.add(args.path)
371
+ return undefined
365
372
  }
366
373
  // A dynamic import takes the module as a NAMESPACE - every export is live - so routing one
367
374
  // through the artifact would drag the whole surface into the initial tier that the dynamic
368
375
  // import exists to stay out of. Leave it deferred, unless the artifact already ships that
369
376
  // module, in which case serving it from there keeps the single instance.
370
- if (args.kind === 'dynamic-import' && !runtime.surface.has(args.path)) return undefined;
377
+ if (args.kind === 'dynamic-import' && !runtime.surface.has(args.path)) return undefined
371
378
  // The importer travels in the path because onLoad is not told it, and
372
379
  // the demanded names are a property of the IMPORTER, not the specifier:
373
380
  // esbuild cannot shake named imports out of an external module, so
374
381
  // whatever the virtual module offers is what ships.
375
- return { path: `${args.path}\0${args.importer}`, namespace };
376
- });
382
+ return { path: `${args.path}\0${args.importer}`, namespace }
383
+ })
377
384
  build.onLoad({ filter: /.*/, namespace }, args => {
378
- const separator = args.path.lastIndexOf('\0');
379
- const specifier = args.path.slice(0, separator);
380
- const importer = args.path.slice(separator + 1);
381
- const available = runtime.exports.get(specifier) ?? [];
382
- const demanded = demandedNames(importer, specifier, sourceOf(importer), available);
383
- const clause = demanded
384
- .map(name => `${mangledName(specifier, name)} as ${name}`)
385
- .join(', ');
385
+ const separator = args.path.lastIndexOf('\0')
386
+ const specifier = args.path.slice(0, separator)
387
+ const importer = args.path.slice(separator + 1)
388
+ const available = runtime.exports.get(specifier) ?? []
389
+ const demanded = demandedNames(importer, specifier, sourceOf(importer), available)
390
+ const clause = demanded.map(name => `${mangledName(specifier, name)} as ${name}`).join(', ')
386
391
  const contents =
387
392
  clause.length > 0
388
393
  ? `export { ${clause} } from ${JSON.stringify(moduleUrl)};\n`
389
- : `import ${JSON.stringify(moduleUrl)};\n`;
390
- return { contents, loader: 'js', resolveDir: path.dirname(specifier) };
391
- });
394
+ : `import ${JSON.stringify(moduleUrl)};\n`
395
+ return { contents, loader: 'js', resolveDir: path.dirname(specifier) }
396
+ })
392
397
  },
393
- };
398
+ }
394
399
  }
395
400
  /**
396
401
  * The names one importer binds off one specifier. A namespace import, an `export * from`, or an import
@@ -403,110 +408,113 @@ function demandedNames(
403
408
  source: string | undefined,
404
409
  available: string[],
405
410
  ) {
406
- if (source === undefined) return available;
411
+ if (source === undefined) return available
407
412
  // The generated entries are virtual and their importer id carries no extension; scanFacts picks
408
413
  // the parser off the name, so an id like `index` would parse as plain JS, leaving the entry's
409
414
  // TypeScript unreadable - which reads as "demands everything".
410
- const sourceFile = /\.[cm]?[jt]sx?$/i.test(importer) ? importer : `${importer}.tsx`;
411
- let edges;
415
+ const sourceFile = /\.[cm]?[jt]sx?$/i.test(importer) ? importer : `${importer}.tsx`
416
+ let edges
412
417
  try {
413
- edges = scanFacts(sourceFile, source).imports;
418
+ edges = scanFacts(sourceFile, source).imports
414
419
  } catch {
415
- return available;
420
+ return available
416
421
  }
417
- const names = new Set<string>();
418
- let named = false;
422
+ const names = new Set<string>()
423
+ let named = false
419
424
  for (const edge of edges) {
420
- if (edge.specifier !== specifier) continue;
421
- named = true;
422
- if (edge.star || edge.exports.includes('*')) return available;
423
- for (const name of edge.exports) names.add(name);
425
+ if (edge.specifier !== specifier) continue
426
+ named = true
427
+ if (edge.star || edge.exports.includes('*')) return available
428
+ for (const name of edge.exports) names.add(name)
424
429
  }
425
- if (!named) return available;
426
- const offered = available.filter(name => names.has(name));
430
+ if (!named) return available
431
+ const offered = available.filter(name => names.has(name))
427
432
  // A name the target does not export is the build's error to report, not
428
433
  // something to silently drop — offer it and let esbuild say so.
429
- for (const name of names) if (!available.includes(name)) offered.push(name);
430
- return offered;
434
+ for (const name of names) if (!available.includes(name)) offered.push(name)
435
+ return offered
431
436
  }
432
437
 
433
438
  export function prebuiltModuleUrl(runtime: Pick<PrebuiltRuntime, 'publicPath'>) {
434
- return `${runtime.publicPath}/${PREBUILT_MODULE}`;
439
+ return `${runtime.publicPath}/${PREBUILT_MODULE}`
435
440
  }
436
441
  /**
437
442
  * Read the surface the build actually demanded back off its own output: every mangled name imported
438
443
  * from the artifact url. Exact by construction - it is the same list the browser will ask for.
439
444
  */
440
445
  export function demandedFromOutputs(runtime: PrebuiltRuntime, outDir: string) {
441
- const moduleUrl = prebuiltModuleUrl(runtime);
442
- const byMangled = new Map<string, { specifier: string; name: string }>();
446
+ const moduleUrl = prebuiltModuleUrl(runtime)
447
+ const byMangled = new Map<string, { specifier: string; name: string }>()
443
448
  for (const [specifier, names] of runtime.exports) {
444
- for (const name of names) byMangled.set(mangledName(specifier, name), { specifier, name });
449
+ for (const name of names) byMangled.set(mangledName(specifier, name), { specifier, name })
445
450
  }
446
- const demanded = new Map<string, Set<string>>();
451
+ const demanded = new Map<string, Set<string>>()
447
452
  const walk = (dir: string) => {
448
- let entries: Dirent[];
453
+ let entries: Dirent[]
449
454
  try {
450
- entries = readdirSync(dir, { withFileTypes: true });
455
+ entries = readdirSync(dir, { withFileTypes: true })
451
456
  } catch {
452
- return;
457
+ return
453
458
  }
454
459
  for (const entry of entries) {
455
- const file = path.join(dir, entry.name);
460
+ const file = path.join(dir, entry.name)
456
461
  // The artifact itself lives under the out dir in prod; it is where these
457
462
  // names come from, not a consumer of them.
458
463
  if (entry.isDirectory()) {
459
- if (file !== runtime.dir) walk(file);
460
- continue;
464
+ if (file !== runtime.dir) walk(file)
465
+ continue
461
466
  }
462
- if (!entry.name.endsWith('.js')) continue;
463
- let source: string;
467
+ if (!entry.name.endsWith('.js')) continue
468
+ let source: string
464
469
  try {
465
- source = readFileSync(file, 'utf8');
470
+ source = readFileSync(file, 'utf8')
466
471
  } catch {
467
- continue;
472
+ continue
468
473
  }
469
- if (!source.includes(moduleUrl)) continue;
474
+ if (!source.includes(moduleUrl)) continue
470
475
  for (const edge of scanFacts(file, source).imports) {
471
- if (edge.specifier !== moduleUrl) continue;
476
+ if (edge.specifier !== moduleUrl) continue
472
477
  for (const bound of edge.exports) {
473
- const origin = byMangled.get(bound);
474
- if (!origin) continue;
475
- const names = demanded.get(origin.specifier) ?? new Set<string>();
476
- demanded.set(origin.specifier, names);
477
- names.add(origin.name);
478
+ const origin = byMangled.get(bound)
479
+ if (!origin) continue
480
+ const names = demanded.get(origin.specifier) ?? new Set<string>()
481
+ demanded.set(origin.specifier, names)
482
+ names.add(origin.name)
478
483
  }
479
484
  }
480
485
  }
481
- };
482
- walk(outDir);
483
- return demanded;
486
+ }
487
+ walk(outDir)
488
+ return demanded
484
489
  }
485
490
 
486
491
  /** Is every demanded name already in the artifact on disk? */
487
492
  export function surfaceCovered(runtime: PrebuiltRuntime, demanded: Map<string, Set<string>>) {
488
493
  for (const [specifier, names] of demanded) {
489
- const have = runtime.surface.get(specifier);
490
- if (!have) return false;
491
- for (const name of names) if (!have.has(name)) return false;
494
+ const have = runtime.surface.get(specifier)
495
+ if (!have) return false
496
+ for (const name of names) if (!have.has(name)) return false
492
497
  }
493
- return true;
498
+ return true
494
499
  }
495
500
 
496
- const manifestName = 'pnext-runtime.json';
501
+ const manifestName = 'pnext-runtime.json'
497
502
 
498
503
  /**
499
504
  * One artifact address is shared by every route build in the process, and in
500
505
  * dev several routes compile at once. Serialize per address so two esbuild runs
501
506
  * never write the same directory concurrently.
502
507
  */
503
- const artifactLocks = new Map<string, Promise<unknown>>();
508
+ const artifactLocks = new Map<string, Promise<unknown>>()
504
509
 
505
510
  function underLock<T>(dir: string, run: () => Promise<T>): Promise<T> {
506
- const previous = artifactLocks.get(dir) ?? Promise.resolve();
507
- const next = previous.then(run, run);
508
- artifactLocks.set(dir, next.catch(() => undefined));
509
- return next;
511
+ const previous = artifactLocks.get(dir) ?? Promise.resolve()
512
+ const next = previous.then(run, run)
513
+ artifactLocks.set(
514
+ dir,
515
+ next.catch(() => undefined),
516
+ )
517
+ return next
510
518
  }
511
519
 
512
520
  /**
@@ -516,11 +524,11 @@ function underLock<T>(dir: string, run: () => Promise<T>): Promise<T> {
516
524
  * probed and folded in by the build that first demands it.
517
525
  */
518
526
  export function ensurePrebuiltRuntime(options: ArtifactOptions) {
519
- return underLock(options.dir, () => openPrebuiltRuntime(options));
527
+ return underLock(options.dir, () => openPrebuiltRuntime(options))
520
528
  }
521
529
 
522
530
  async function openPrebuiltRuntime(options: ArtifactOptions) {
523
- const manifest = readManifest(options.dir);
531
+ const manifest = readManifest(options.dir)
524
532
  if (manifest) {
525
533
  return {
526
534
  key: options.key,
@@ -528,14 +536,14 @@ async function openPrebuiltRuntime(options: ArtifactOptions) {
528
536
  publicPath: options.publicPath,
529
537
  assetPath: options.assetPath,
530
538
  ...manifest,
531
- } satisfies PrebuiltRuntime;
539
+ } satisfies PrebuiltRuntime
532
540
  }
533
- const exportsBySpecifier = await probeSurface(seedSpecifiers(options.aliases), options);
541
+ const exportsBySpecifier = await probeSurface(seedSpecifiers(options.aliases), options)
534
542
  // Seed surface: nothing is demanded yet, so the aggregate starts empty and
535
543
  // the first route build's own output says what belongs in it.
536
- const runtime = await buildPrebuiltRuntime(options, exportsBySpecifier, new Map());
537
- await writeManifest(runtime);
538
- return runtime;
544
+ const runtime = await buildPrebuiltRuntime(options, exportsBySpecifier, new Map())
545
+ await writeManifest(runtime)
546
+ return runtime
539
547
  }
540
548
  /**
541
549
  * Fold what the build demanded - and any specifier it met for the first time - into the artifact. A
@@ -547,7 +555,7 @@ export function settlePrebuiltRuntime(
547
555
  outDir: string,
548
556
  unprobed: Set<string>,
549
557
  ) {
550
- return underLock(options.dir, () => growPrebuiltRuntime(runtime, options, outDir, unprobed));
558
+ return underLock(options.dir, () => growPrebuiltRuntime(runtime, options, outDir, unprobed))
551
559
  }
552
560
 
553
561
  async function growPrebuiltRuntime(
@@ -558,43 +566,43 @@ async function growPrebuiltRuntime(
558
566
  ) {
559
567
  // Another build may have grown the artifact while this one ran; merge onto
560
568
  // what is on disk now, not onto the snapshot this build opened.
561
- const current = readManifest(options.dir);
562
- if (current) runtime = { ...runtime, ...current };
563
- const demanded = demandedFromOutputs(runtime, outDir);
564
- if (unprobed.size === 0 && surfaceCovered(runtime, demanded)) return runtime;
565
- const exportsBySpecifier = new Map(runtime.exports);
569
+ const current = readManifest(options.dir)
570
+ if (current) runtime = { ...runtime, ...current }
571
+ const demanded = demandedFromOutputs(runtime, outDir)
572
+ if (unprobed.size === 0 && surfaceCovered(runtime, demanded)) return runtime
573
+ const exportsBySpecifier = new Map(runtime.exports)
566
574
  for (const [specifier, names] of await probeSurface([...unprobed], options)) {
567
- exportsBySpecifier.set(specifier, names);
575
+ exportsBySpecifier.set(specifier, names)
568
576
  }
569
- const surface = new Map(runtime.surface);
577
+ const surface = new Map(runtime.surface)
570
578
  for (const [specifier, names] of demanded) {
571
- const target = surface.get(specifier) ?? new Set<string>();
572
- surface.set(specifier, target);
573
- for (const name of names) target.add(name);
579
+ const target = surface.get(specifier) ?? new Set<string>()
580
+ surface.set(specifier, target)
581
+ for (const name of names) target.add(name)
574
582
  }
575
- const grown = await buildPrebuiltRuntime(options, exportsBySpecifier, surface);
576
- await writeManifest(grown);
577
- return grown;
583
+ const grown = await buildPrebuiltRuntime(options, exportsBySpecifier, surface)
584
+ await writeManifest(grown)
585
+ return grown
578
586
  }
579
587
 
580
588
  interface Manifest {
581
- key: string;
582
- exports: Record<string, string[]>;
583
- surface: Record<string, string[]>;
584
- closure: { static: string[]; dynamic: string[] };
589
+ key: string
590
+ exports: Record<string, string[]>
591
+ surface: Record<string, string[]>
592
+ closure: { static: string[]; dynamic: string[] }
585
593
  }
586
594
 
587
595
  function readManifest(dir: string) {
588
596
  try {
589
- const parsed = JSON.parse(readFileSync(path.join(dir, manifestName), 'utf8')) as Manifest;
590
- if (!parsed.exports) return undefined;
597
+ const parsed = JSON.parse(readFileSync(path.join(dir, manifestName), 'utf8')) as Manifest
598
+ if (!parsed.exports) return undefined
591
599
  return {
592
600
  exports: new Map(Object.entries(parsed.exports)),
593
601
  surface: new Map(Object.entries(parsed.surface).map(([spec, n]) => [spec, new Set(n)])),
594
602
  closure: parsed.closure,
595
- };
603
+ }
596
604
  } catch {
597
- return undefined;
605
+ return undefined
598
606
  }
599
607
  }
600
608
 
@@ -604,8 +612,8 @@ async function writeManifest(runtime: PrebuiltRuntime) {
604
612
  exports: Object.fromEntries(runtime.exports),
605
613
  surface: Object.fromEntries([...runtime.surface].map(([s, n]) => [s, [...n].sort()])),
606
614
  closure: runtime.closure,
607
- };
608
- await writeText(path.join(runtime.dir, manifestName), JSON.stringify(manifest));
615
+ }
616
+ await writeText(path.join(runtime.dir, manifestName), JSON.stringify(manifest))
609
617
  }
610
618
 
611
619
  /**
@@ -613,9 +621,9 @@ async function writeManifest(runtime: PrebuiltRuntime) {
613
621
  * `assets/…` names — what the rendered page's modulepreload list is written in.
614
622
  */
615
623
  export function prebuiltAssets(runtime: PrebuiltRuntime) {
616
- const join = (name: string) => `${runtime.assetPath}/${name}`;
624
+ const join = (name: string) => `${runtime.assetPath}/${name}`
617
625
  return {
618
626
  static: [join(PREBUILT_MODULE), ...runtime.closure.static.map(join)],
619
627
  dynamic: runtime.closure.dynamic.map(join),
620
- };
628
+ }
621
629
  }