@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
@@ -0,0 +1,952 @@
1
+ /**
2
+ * The ESM loader: Bun module-resolve/load plugin registration for the app's own source (and its
3
+ * node_modules-relative requires), plus the on-demand transform pipeline (source rewrites, CJS
4
+ * sidecar generation) that feeds compiled code to those plugins. The alias-resolution and
5
+ * asset-stub helpers here are shared with vendor package bundling in `./vendor-build`, which
6
+ * imports them; this module never imports from `./vendor-build`.
7
+ */
8
+
9
+ import { createHash } from 'node:crypto'
10
+ import { createRequire } from 'node:module'
11
+ import { existsSync, realpathSync } from 'node:fs'
12
+ import { mkdir, readFile, stat, writeFile } from 'node:fs/promises'
13
+ import path from 'node:path'
14
+ import { fileURLToPath } from 'node:url'
15
+ import type { Loader, Plugin } from 'esbuild'
16
+ import { build, transform } from '../utils/esbuild'
17
+ import {
18
+ applyBundledSourceTransforms,
19
+ applyServerSourcePreTransforms,
20
+ applyServerSourceTransforms,
21
+ extraLoadableExtensions,
22
+ getAssetExtensions,
23
+ getBundlerExtensions,
24
+ getCssExtensions,
25
+ getImportAliasExtensions,
26
+ onLoadableExtensionsChanged,
27
+ serverDefineOptions,
28
+ sourceNeedsServerTransforms,
29
+ } from '../extensions'
30
+ import {
31
+ frameworkRuntimeAliasEntries,
32
+ pathToFileHref,
33
+ pnextAliases,
34
+ type CompatAliasTarget,
35
+ type ResolvedConfig,
36
+ } from '../config'
37
+ import {
38
+ rewriteDynamicCallTargets,
39
+ rewriteLiteralDynamicCalls,
40
+ sourceHasDynamicImport,
41
+ } from '../resolve/dynamic'
42
+ import { cacheRoot } from './module-cache'
43
+ import { readNodeModuleBundle, writeNodeModuleBundle } from '../dev/restart/node-modules'
44
+ import { setBasePathPrefix, setTrailingSlashUrls } from '../routing/href'
45
+ import { resolveExternalLoadTarget, resolveImport, workspacePackageRoots } from '../resolve/imports'
46
+ import { escapeRegex } from '../utils/code'
47
+ import { writeFileAtomic } from '../utils/fs'
48
+
49
+ const require = createRequire(import.meta.url)
50
+
51
+ // B4/B5: extra esbuild resolve conditions layered onto the server (RSC) vendor
52
+ // bundle. Core always applies `react-server` (the server graph IS the RSC
53
+ // layer). Compat can add `next-js` (only when cacheComponents is on) via the
54
+ // setter. Kept as a module-level seam so core carries no static edge into
55
+ // compat's config reader.
56
+ export type ServerBundleTarget =
57
+ CompatAliasTarget | 'edge' | 'pages-api' | 'pages-api-edge' | 'pages' | 'pages-edge'
58
+
59
+ let extraServerBundleConditions: (target: ServerBundleTarget) => string[] = () => []
60
+
61
+ /** Install compat-driven extra vendor-bundle conditions (B5 `next-js`). */
62
+ export function setServerBundleConditions(
63
+ factory: ((target: ServerBundleTarget) => string[]) | undefined,
64
+ ): void {
65
+ extraServerBundleConditions = factory ?? (() => [])
66
+ }
67
+
68
+ export function serverBundleTargetForRuntime(runtime: string | undefined): ServerBundleTarget {
69
+ return runtime === 'edge' || runtime === 'experimental-edge' ? 'edge' : 'server'
70
+ }
71
+
72
+ export function pagesApiBundleTargetForRuntime(runtime: string | undefined): ServerBundleTarget {
73
+ return runtime === 'edge' || runtime === 'experimental-edge' ? 'pages-api-edge' : 'pages-api'
74
+ }
75
+
76
+ /**
77
+ * Pages-router PAGE SSR layer: Next compiles it in the server bundle with `node` (or
78
+ * `edge-light`/`browser` for edge) export conditions but WITHOUT `react-server` - a pages page is
79
+ * not part of the RSC layer, so `library/react`-style react-server splits must resolve to `default`.
80
+ */
81
+ export function pagesBundleTargetForRuntime(runtime: string | undefined): ServerBundleTarget {
82
+ return runtime === 'edge' || runtime === 'experimental-edge' ? 'pages-edge' : 'pages'
83
+ }
84
+
85
+ export function serverBundleConditions(target: ServerBundleTarget): string[] {
86
+ // Preserve the original client-target conditions (module/import) to avoid
87
+ // regressing the browser SSR vendor bundle; only the RSC/server layer gains
88
+ // `react-server`. Compat-added conditions (next-js) prepend for either target.
89
+ const base =
90
+ target === 'client'
91
+ ? ['module', 'import']
92
+ : target === 'edge'
93
+ ? ['react-server', 'edge-light', 'browser', 'module', 'import']
94
+ : target === 'pages-api-edge'
95
+ ? ['edge-light', 'browser', 'module', 'import']
96
+ : target === 'pages-api'
97
+ ? ['node', 'require', 'import']
98
+ : target === 'pages-edge'
99
+ ? ['edge-light', 'browser', 'module', 'import']
100
+ : target === 'pages'
101
+ ? ['node', 'module', 'import']
102
+ : ['react-server', 'node', 'module', 'import']
103
+ return [...new Set([...extraServerBundleConditions(target), ...base])]
104
+ }
105
+
106
+ export function serverBundleRequireConditions(target: ServerBundleTarget): string[] {
107
+ const base =
108
+ target === 'client'
109
+ ? ['module', 'require']
110
+ : target === 'edge'
111
+ ? ['react-server', 'edge-light', 'browser', 'module', 'require']
112
+ : target === 'pages-api-edge'
113
+ ? ['edge-light', 'browser', 'module', 'require']
114
+ : target === 'pages-api'
115
+ ? ['node', 'require']
116
+ : target === 'pages-edge'
117
+ ? ['edge-light', 'browser', 'module', 'require']
118
+ : target === 'pages'
119
+ ? ['node', 'module', 'require']
120
+ : ['react-server', 'node', 'module', 'require']
121
+ return [...new Set([...extraServerBundleConditions(target), ...base])]
122
+ }
123
+
124
+ const runtimeConfigs = new Map<string, RuntimeConfig>()
125
+ const aliasCache = new WeakMap<ResolvedConfig, Map<string, string>>()
126
+ const packageRootCache = new WeakMap<ResolvedConfig, string[]>()
127
+ const registeredSignatures = new WeakMap<ResolvedConfig, Set<string>>()
128
+ const rootPathCache = new Map<string, string[]>()
129
+ const runtimeConfigLookupCache = new Map<string, RuntimeConfig | null>()
130
+ const firstAliasCache = new Map<string, string | null>()
131
+ const transformCache = new Map<string, TransformCacheEntry>()
132
+ const nodeModuleTransformCache = new Map<string, TransformCacheEntry>()
133
+ // Freshness of generated `.pnext-require.cjs` sidecars (see inlineModuleScopeRequires).
134
+ const requireSidecarCache = new Map<string, { mtimeMs: number; size: number }>()
135
+ const registeredLoadRoots = new Set<string>()
136
+ let resolveRegistered = false
137
+ let nodeModulesLoadRegistered = false
138
+ // A live Bun.plugin forces every later import through the plugin pipeline (and
139
+ // pnext's own src through transformSource), so importing the compat graph with
140
+ // the plugins already up costs ~5x. build/start load compat before they ever
141
+ // register a runtime; dev arms the plugins on the first request instead.
142
+ let pluginsDeferred = false
143
+ const deferredPluginRoots = new Set<string>()
144
+
145
+ export const packageJsxLoaders = {
146
+ '.js': 'jsx',
147
+ '.mjs': 'jsx',
148
+ '.cjs': 'jsx',
149
+ } satisfies Record<string, Loader>
150
+
151
+ interface RuntimeConfig {
152
+ root: string
153
+ roots: Set<string>
154
+ aliases: Map<string, string>
155
+ /** Full resolved config, so compile sites can invoke config-aware extensions. */
156
+ resolved: ResolvedConfig
157
+ missingImportError: (specifier: string) => string | undefined
158
+ }
159
+
160
+ interface TransformCacheEntry {
161
+ mtimeMs: number
162
+ size: number
163
+ code: string
164
+ }
165
+
166
+ export function registerServerRuntime(config: ResolvedConfig, sourceFiles: string[] = []) {
167
+ // Server-rendered Links emit canonical (slashed) hrefs under trailingSlash.
168
+ setTrailingSlashUrls(Boolean(config.trailingSlash))
169
+ // File-convention metadata asset hrefs (og-image, manifest) carry the
170
+ // basePath prefix; core render reads it through the href seam.
171
+ setBasePathPrefix(typeof config.basePath === 'string' ? config.basePath : '')
172
+ if (typeof Bun === 'undefined') return
173
+ const sourceRoots = [...new Set(sourceFiles.map(file => sourceRootForFile(config, file)))].sort()
174
+ const signature = sourceRoots.join('\0')
175
+ let registered = registeredSignatures.get(config)
176
+ if (!registered) {
177
+ registered = new Set()
178
+ registeredSignatures.set(config, registered)
179
+ }
180
+ if (registered.has(signature)) return
181
+ registered.add(signature)
182
+
183
+ const aliases = aliasesForConfig(config)
184
+ const roots = [
185
+ ...rootPaths(config.appPath),
186
+ ...rootPaths(path.join(config.outPath, 'cache', 'server')),
187
+ // The pnext src root, so the framework's own source transforms too.
188
+ ...rootPaths(path.join(import.meta.dirname, '..')),
189
+ ...sourceRoots.flatMap(rootPaths),
190
+ ]
191
+ const key = rootPaths(config.appPath).join('\0')
192
+ const missingImportError = (specifier: string) =>
193
+ getImportAliasExtensions().missingImportError(config, specifier)
194
+ const existing = runtimeConfigs.get(key)
195
+ if (existing) {
196
+ for (const root of roots) existing.roots.add(root)
197
+ for (const [specifier, target] of aliases) existing.aliases.set(specifier, target)
198
+ existing.resolved = config
199
+ existing.missingImportError = missingImportError
200
+ } else {
201
+ runtimeConfigs.set(key, {
202
+ root: config.root,
203
+ roots: new Set(roots),
204
+ aliases: new Map(aliases),
205
+ resolved: config,
206
+ missingImportError,
207
+ })
208
+ }
209
+ runtimeConfigLookupCache.clear()
210
+ firstAliasCache.clear()
211
+ if (pluginsDeferred) {
212
+ for (const root of roots) deferredPluginRoots.add(root)
213
+ return
214
+ }
215
+ registerResolvePlugin()
216
+ registerNodeModulesLoadPlugin()
217
+ for (const root of roots) registerLoadPlugin(root)
218
+ }
219
+
220
+ /**
221
+ * Hold the Bun module plugins back until installServerRuntimePlugins() runs, so
222
+ * whatever the process still has to import of its own code loads natively.
223
+ */
224
+ export function deferServerRuntimePlugins(): void {
225
+ pluginsDeferred = true
226
+ }
227
+
228
+ /** Arm the plugins deferServerRuntimePlugins() held back. Idempotent, cheap. */
229
+ export function installServerRuntimePlugins(): void {
230
+ if (!pluginsDeferred) return
231
+ pluginsDeferred = false
232
+ registerResolvePlugin()
233
+ registerNodeModulesLoadPlugin()
234
+ for (const root of deferredPluginRoots) registerLoadPlugin(root)
235
+ deferredPluginRoots.clear()
236
+ }
237
+
238
+ function resolveRuntimeTarget(target: string) {
239
+ return path.isAbsolute(target) ? target : require.resolve(target)
240
+ }
241
+
242
+ function aliasesForConfig(config: ResolvedConfig) {
243
+ let aliases = aliasCache.get(config)
244
+ if (!aliases) {
245
+ aliases = new Map<string, string>()
246
+ for (const [specifier, target] of Object.entries(coreAliases(config, 'server'))) {
247
+ aliases.set(specifier, resolveRuntimeTarget(target))
248
+ }
249
+ aliasCache.set(config, aliases)
250
+ }
251
+ return aliases
252
+ }
253
+
254
+ export function coreAliases(
255
+ config: ResolvedConfig,
256
+ target: CompatAliasTarget,
257
+ ): Record<string, string> {
258
+ return {
259
+ ...frameworkRuntimeAliasEntries(),
260
+ ...pnextAliases(target),
261
+ ...getImportAliasExtensions().aliases(config, target),
262
+ }
263
+ }
264
+
265
+ export const aliasSpecifierFilter =
266
+ /^(?:@wular\/pnext\/cache|preact(?:\/|$)|react(?:-dom)?(?:\/|$)|react-compiler-runtime$|next(?:\/|$)|server-only$|client-only$|@vercel\/og$)/
267
+
268
+ function registerResolvePlugin() {
269
+ if (resolveRegistered) return
270
+ resolveRegistered = true
271
+ Bun.plugin({
272
+ name: 'pnext-server-runtime-resolve',
273
+ setup(plugin) {
274
+ plugin.onResolve({ filter: aliasSpecifierFilter }, args => {
275
+ const runtime = runtimeConfigForFile(args.importer)
276
+ const resolved = runtime?.aliases.get(args.path) ?? firstAliasForSpecifier(args.path)
277
+ const target = resolved ? serverRequireAlias(args.path, resolved, args.kind) : undefined
278
+ if (target) return { path: target }
279
+ const message = (runtime ?? firstRuntimeConfig())?.missingImportError(args.path)
280
+ if (message) throw new Error(message)
281
+ return undefined
282
+ })
283
+ plugin.onResolve({ filter: /^[^./].*/ }, ({ path: specifier, importer }) => {
284
+ const runtime = runtimeConfigForFile(importer)
285
+ const target =
286
+ runtime &&
287
+ resolveExternalLoadTarget({
288
+ root: runtime.root,
289
+ fromFile: importer,
290
+ specifier,
291
+ target: 'server',
292
+ })
293
+ if (!target) return undefined
294
+ return { path: target }
295
+ })
296
+ },
297
+ })
298
+ }
299
+
300
+ function registerLoadPlugin(root: string) {
301
+ if (registeredLoadRoots.has(root)) return
302
+ registeredLoadRoots.add(root)
303
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
304
+ if (process.env.PNEXT_DEBUG_LOADPLUGIN) {
305
+ console.error(`[loadplugin] register root=${root} extras=${currentLoadExtras().join(',')}`)
306
+ }
307
+ loadPluginExtras.set(root, currentLoadExtras())
308
+ Bun.plugin({
309
+ name: `pnext-server-runtime-load-${hashRoot(root)}`,
310
+ setup(plugin) {
311
+ plugin.onLoad({ filter: rootFilter(root) }, async ({ path: file }) => ({
312
+ contents: await transformSource(file),
313
+ loader: 'js',
314
+ }))
315
+ },
316
+ })
317
+ }
318
+
319
+ // The load plugin's filter regex latches the page extensions known at registration time. A root registered
320
+ // BEFORE compat adds `mdx`/`md` (boot order shifts under load) would let those modules fall through to Bun's
321
+ // file loader, whose default export is the file path and renders as a bogus JSX tag - so a late registration
322
+ // extends every latched root with an extras-only plugin.
323
+ const loadPluginExtras = new Map<string, string[]>()
324
+
325
+ function currentLoadExtras(): string[] {
326
+ return extraLoadableExtensions().filter(ext => /^[a-z0-9]+$/i.test(ext))
327
+ }
328
+
329
+ onLoadableExtensionsChanged(() => {
330
+ for (const [root, seen] of loadPluginExtras) {
331
+ const fresh = currentLoadExtras().filter(ext => !seen.includes(ext))
332
+ if (fresh.length === 0) continue
333
+ loadPluginExtras.set(root, [...seen, ...fresh])
334
+ const exts = fresh.map(escapeRegex).join('|')
335
+ const filter = new RegExp(
336
+ `^${escapeRegex(root)}(?!.*\\/node_modules\\/)(?:/.*)?\\.(?:${exts})$`,
337
+ )
338
+ Bun.plugin({
339
+ name: `pnext-server-runtime-load-extras-${hashRoot(root)}-${fresh.join('-')}`,
340
+ setup(plugin) {
341
+ plugin.onLoad({ filter }, async ({ path: file }) => ({
342
+ contents: await transformSource(file),
343
+ loader: 'js',
344
+ }))
345
+ },
346
+ })
347
+ }
348
+ })
349
+
350
+ function registerNodeModulesLoadPlugin() {
351
+ if (nodeModulesLoadRegistered) return
352
+ nodeModulesLoadRegistered = true
353
+ Bun.plugin({
354
+ name: 'pnext-server-node-modules-load',
355
+ setup(plugin) {
356
+ plugin.onLoad(
357
+ {
358
+ filter:
359
+ /\/node_modules\/.*(?:\.mjs|\.esm\.js|\/(?:es|esm|dist\/esm|build\/modern)\/.*\.js)$/,
360
+ },
361
+ async ({ path: file }) => {
362
+ const code = await transformNodeModuleSource(file)
363
+ return { contents: code, loader: 'js' }
364
+ },
365
+ )
366
+ },
367
+ })
368
+ }
369
+
370
+ function runtimeConfigForFile(file: string | undefined) {
371
+ if (!file) return undefined
372
+ const key = path.resolve(file)
373
+ if (runtimeConfigLookupCache.has(key)) {
374
+ return runtimeConfigLookupCache.get(key) ?? undefined
375
+ }
376
+ for (const config of runtimeConfigs.values()) {
377
+ for (const root of config.roots) {
378
+ if (isInside(root, file)) {
379
+ runtimeConfigLookupCache.set(key, config)
380
+ return config
381
+ }
382
+ }
383
+ }
384
+ runtimeConfigLookupCache.set(key, null)
385
+ return undefined
386
+ }
387
+
388
+ function sourceRootForFile(config: ResolvedConfig, file: string) {
389
+ const dir = path.dirname(file)
390
+ if (isInside(config.appPath, dir)) return config.appPath
391
+ return packageRootsForConfig(config).find(root => isInside(root, dir)) ?? dir
392
+ }
393
+
394
+ function packageRootsForConfig(config: ResolvedConfig) {
395
+ let roots = packageRootCache.get(config)
396
+ if (!roots) {
397
+ roots = workspacePackageRoots(config.workspaceRoot)
398
+ packageRootCache.set(config, roots)
399
+ }
400
+ return roots
401
+ }
402
+
403
+ function firstRuntimeConfig() {
404
+ for (const config of runtimeConfigs.values()) return config
405
+ return undefined
406
+ }
407
+
408
+ export function firstAliasForSpecifier(specifier: string) {
409
+ if (firstAliasCache.has(specifier)) return firstAliasCache.get(specifier) ?? undefined
410
+ for (const config of runtimeConfigs.values()) {
411
+ const target = config.aliases.get(specifier)
412
+ if (target) {
413
+ firstAliasCache.set(specifier, target)
414
+ return target
415
+ }
416
+ }
417
+ firstAliasCache.set(specifier, null)
418
+ return undefined
419
+ }
420
+
421
+ async function transformSource(file: string) {
422
+ const fileStat = await stat(file)
423
+ const cached = transformCache.get(file)
424
+ if (cached?.mtimeMs === fileStat.mtimeMs && cached.size === fileStat.size) {
425
+ return cached.code
426
+ }
427
+ // The in-memory cache is empty on every restart, so a restarted server
428
+ // re-transforms the whole materialized module set on the request path.
429
+ const diskCache = transformCacheFile(file, fileStat)
430
+ if (diskCache) {
431
+ const code = await readFile(diskCache, 'utf8').catch(() => undefined)
432
+ if (code !== undefined) {
433
+ transformCache.set(file, { mtimeMs: fileStat.mtimeMs, size: fileStat.size, code })
434
+ return code
435
+ }
436
+ }
437
+
438
+ const runtime = runtimeConfigForFile(file)
439
+ let raw = await readFile(file, 'utf8')
440
+ // Raw markdown compiles through the MDX pipeline first; materialized
441
+ // cache/server copies were already compiled in place (runtime/modules) and would
442
+ // be corrupted by a second pass.
443
+ if (/\.mdx?$/.test(file) && !file.includes(`${path.sep}cache${path.sep}server${path.sep}`)) {
444
+ const { compileMdx } = await import('../compat/mdx/compile')
445
+ raw = (await compileMdx(raw, file, runtime?.root ?? path.dirname(file))).code
446
+ }
447
+ const source = await inlineModuleScopeRequires(
448
+ rewriteServerSource(raw, file, {
449
+ root: runtime?.root,
450
+ }),
451
+ file,
452
+ runtime?.root,
453
+ )
454
+ const result = await transform(source, {
455
+ loader: esbuildLoader(file),
456
+ jsx: 'automatic',
457
+ jsxImportSource: 'preact',
458
+ sourcefile: file,
459
+ target: 'es2022',
460
+ ...serverDefineOptions(),
461
+ })
462
+ transformCache.set(file, {
463
+ mtimeMs: fileStat.mtimeMs,
464
+ size: fileStat.size,
465
+ code: result.code,
466
+ })
467
+ if (diskCache) {
468
+ await mkdir(path.dirname(diskCache), { recursive: true }).catch(() => undefined)
469
+ void writeFileAtomic(diskCache, result.code).catch(() => undefined)
470
+ }
471
+ return result.code
472
+ }
473
+
474
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
475
+ const transformDiskCacheDisabled = process.env.PNEXT_TRANSFORM_DISK_CACHE === '0'
476
+ const materializedSegment = `${path.sep}cache${path.sep}server${path.sep}`
477
+
478
+ /**
479
+ * Where a transform of `file` is remembered across restarts. Only for the
480
+ * materialized `cache/server` modules: they are hash-named build output under
481
+ * our own cache root, so the key (path + mtime + size + the define/extension
482
+ * inputs of the transform) is complete, and the whole tree is discarded when
483
+ * a build or a config change rewrites it.
484
+ */
485
+ function transformCacheFile(file: string, fileStat: { mtimeMs: number; size: number }) {
486
+ if (transformDiskCacheDisabled) return undefined
487
+ const at = file.lastIndexOf(materializedSegment)
488
+ if (at === -1) return undefined
489
+ const cacheRoot = file.slice(0, at + materializedSegment.length)
490
+ const key = `${file}\0${fileStat.mtimeMs}\0${fileStat.size}\0${currentLoadExtras().join(',')}\0${JSON.stringify(serverDefineOptions())}`
491
+ return path.join(cacheRoot, 'transform', `${hashBundleSpecifier(key)}.js`)
492
+ }
493
+
494
+ // A synchronous `require('./x')` of an app source module fails at runtime with `require() async
495
+ // module ... is unsupported`: the load plugin's onLoad hook makes every app `[jt]sx?` module an
496
+ // ASYNC Bun module, and Bun cannot `require` one. Bun does not route relative `require-call`s
497
+ // through onResolve plugins (only bare specifiers reach them), so the alias trick cannot intercept
498
+ // them at resolve time. Instead each such require is rewritten to a sibling
499
+ // `<x>.pnext-require.cjs` compiled to CommonJS: a real `.cjs` on disk is deliberately excluded by
500
+ // rootFilter, so Bun loads it natively and synchronously.
501
+ //
502
+ // Only requires that resolve to a rootFilter-matched app module are rewritten (a
503
+ // `.cjs`/`.json`/node_modules require already loads synchronously). The sidecar is a distinct module
504
+ // instance from the module's ESM copy - acceptable here, since the require path was an outright
505
+ // crash before and such modules are typically leaf value modules.
506
+ //
507
+ // Both the source form and the BUILT form are matched: the server bundle keeps such a require
508
+ // unbundled and emits esbuild's `__require("file:///abs/path/...")` shim call, which loads the very
509
+ // same async app module at runtime.
510
+ const REQUIRE_CALL = /\b(?:__)?require\(\s*(['"])((?:\.\.?\/|\/|file:\/\/)[^'"]+)\1\s*\)/g
511
+
512
+ async function inlineModuleScopeRequires(
513
+ source: string,
514
+ file: string,
515
+ root: string | undefined,
516
+ ): Promise<string> {
517
+ if (!root || !source.includes('require(')) return source
518
+ const filter = rootFilter(root)
519
+ const sidecars = new Map<string, string>()
520
+ const pending: Promise<void>[] = []
521
+ const seen = new Set<string>()
522
+ for (const match of source.matchAll(REQUIRE_CALL)) {
523
+ const specifier = match[2]!
524
+ if (seen.has(specifier)) continue
525
+ seen.add(specifier)
526
+ const target = requireCallTarget(root, file, specifier)
527
+ if (!target || !filter.test(target)) continue
528
+ pending.push(
529
+ requireCjsSidecar(target).then(sidecar => {
530
+ if (sidecar) sidecars.set(specifier, sidecar)
531
+ }),
532
+ )
533
+ }
534
+ if (pending.length === 0) return source
535
+ await Promise.all(pending)
536
+ if (sidecars.size === 0) return source
537
+ return source.replace(REQUIRE_CALL, (whole, quote: string, specifier: string) => {
538
+ const sidecar = sidecars.get(specifier)
539
+ return sidecar ? `require(${quote}${sidecar}${quote})` : whole
540
+ })
541
+ }
542
+
543
+ /** The module a rewritable `require(...)` call resolves to, if any. */
544
+ function requireCallTarget(root: string, file: string, specifier: string): string | undefined {
545
+ if (specifier.startsWith('file://')) {
546
+ try {
547
+ return resolveImport(root, file, fileURLToPath(specifier))
548
+ } catch {
549
+ return undefined
550
+ }
551
+ }
552
+ return resolveImport(root, file, specifier)
553
+ }
554
+
555
+ // Compile an app module to a sibling `.pnext-require.cjs` (CommonJS), reusing a
556
+ // mtime/size-cached copy. Returns the sidecar path, or undefined on any failure
557
+ // (the original require is then left as-is). The module runs through the same
558
+ // server source pipeline as a normal load so the CJS copy behaves like the ESM
559
+ // one; nested module-scope requires inside it are NOT recursively inlined.
560
+ async function requireCjsSidecar(target: string): Promise<string | undefined> {
561
+ try {
562
+ const sidecar = requireCjsSidecarPath(target)
563
+ const fileStat = await stat(target)
564
+ const cached = requireSidecarCache.get(target)
565
+ if (cached?.mtimeMs === fileStat.mtimeMs && cached.size === fileStat.size) return sidecar
566
+ const runtime = runtimeConfigForFile(target)
567
+ const source = rewriteServerSource(await readFile(target, 'utf8'), target, {
568
+ root: runtime?.root,
569
+ })
570
+ const result = await transform(source, {
571
+ loader: esbuildLoader(target),
572
+ jsx: 'automatic',
573
+ jsxImportSource: 'preact',
574
+ sourcefile: target,
575
+ target: 'es2022',
576
+ format: 'cjs',
577
+ ...serverDefineOptions(),
578
+ })
579
+ await writeFile(sidecar, result.code)
580
+ requireSidecarCache.set(target, { mtimeMs: fileStat.mtimeMs, size: fileStat.size })
581
+ return sidecar
582
+ } catch {
583
+ return undefined
584
+ }
585
+ }
586
+
587
+ function requireCjsSidecarPath(target: string): string {
588
+ return `${target.replace(/\.[^./\\]+$/, '')}.pnext-require.cjs`
589
+ }
590
+
591
+ async function transformNodeModuleSource(file: string) {
592
+ const fileStat = await stat(file)
593
+ const cached = nodeModuleTransformCache.get(file)
594
+ if (cached?.mtimeMs === fileStat.mtimeMs && cached.size === fileStat.size) {
595
+ return cached.code
596
+ }
597
+ // The in-memory cache is empty on every restart, so a restarted server
598
+ // re-BUNDLES each of these packages on the request path.
599
+ const record = nodeModuleBundleRecordFile(file, fileStat)
600
+ const reused = record ? await readNodeModuleBundle(record) : undefined
601
+ if (reused !== undefined) {
602
+ nodeModuleTransformCache.set(file, {
603
+ mtimeMs: fileStat.mtimeMs,
604
+ size: fileStat.size,
605
+ code: reused,
606
+ })
607
+ return reused
608
+ }
609
+
610
+ const { code, inputs } = await bundleNodeModuleSource(file)
611
+ nodeModuleTransformCache.set(file, {
612
+ mtimeMs: fileStat.mtimeMs,
613
+ size: fileStat.size,
614
+ code,
615
+ })
616
+ if (record) void writeNodeModuleBundle(record, inputs, code)
617
+ return code
618
+ }
619
+
620
+ /**
621
+ * Where a bundle of `file` is remembered across restarts. The entry's own stat is in the name, but
622
+ * the build inlines the package's relative graph too, so the record carries every esbuild input and
623
+ * is only reused while all of them still stat the same. A record that cannot be validated is a miss.
624
+ */
625
+ function nodeModuleBundleRecordFile(file: string, fileStat: { mtimeMs: number; size: number }) {
626
+ if (transformDiskCacheDisabled) return undefined
627
+ const outPath = (runtimeConfigForFile(file) ?? firstRuntimeConfig())?.resolved.outPath
628
+ if (!outPath) return undefined
629
+ const key = `${file}\0${fileStat.mtimeMs}\0${fileStat.size}\0${currentLoadExtras().join(',')}\0${JSON.stringify(serverDefineOptions())}`
630
+ return path.join(cacheRoot(outPath), 'node-module-bundle', `${hashBundleSpecifier(key)}.json`)
631
+ }
632
+
633
+ async function bundleNodeModuleSource(file: string) {
634
+ const resolved = runtimeConfigForFile(file)?.resolved
635
+ const extensionPlugins = resolved ? getBundlerExtensions().serverEsbuildPlugins(resolved) : []
636
+ const result = await build({
637
+ // The marker entry only resolves when the extension chain is present.
638
+ entryPoints: [
639
+ (resolved
640
+ ? getBundlerExtensions().serverBundleEntry(file, path.dirname(file), file)
641
+ : undefined) ?? file,
642
+ ],
643
+ bundle: true,
644
+ write: false,
645
+ format: 'esm',
646
+ platform: 'neutral',
647
+ target: 'es2022',
648
+ loader: packageJsxLoaders,
649
+ jsx: 'automatic',
650
+ jsxImportSource: 'preact',
651
+ packages: 'external',
652
+ logLevel: 'silent',
653
+ metafile: true,
654
+ ...serverDefineOptions(),
655
+ plugins: [
656
+ serverAssetPlugin(),
657
+ ...extensionPlugins,
658
+ runtimeAliasBuildPlugin(undefined, 'server', { bundleRequireAliases: true }),
659
+ ],
660
+ })
661
+ const output = result.outputFiles[0]
662
+ if (!output) throw new Error(`Failed to bundle ${file}`)
663
+ // Packages can ship 'use cache' functions too (Next allows it); everything
664
+ // else in the source chain was already settled by the bundle above (imports
665
+ // resolved by the plugins, constants inlined by esbuild `define`).
666
+ return {
667
+ code: applyBundledSourceTransforms(output.text, file),
668
+ inputs: Object.keys(result.metafile.inputs).map(input => path.resolve(input)),
669
+ }
670
+ }
671
+
672
+ /**
673
+ * The one vendor-compile entry point. Every demand - a module compile's import scan, an esbuild
674
+ * resolve callback, a transitive dependency of another vendor bundle - arrives here and is scheduled
675
+ * by the pipeline in `./vendor`. `nested` marks demands raised from inside a running vendor build;
676
+ * see `withVendorSlot` for why they must not queue.
677
+ */
678
+
679
+ // ---------------------------------------------------------------------------
680
+ // Shared with vendor bundling (./vendor-build): alias resolution, asset
681
+ // stubbing, source-rewrite, and root/hash helpers used by both the loader's
682
+ // own plugins and the vendor esbuild passes.
683
+ // ---------------------------------------------------------------------------
684
+
685
+ /**
686
+ * Whether `rewriteServerSource` can possibly change `source`. One regex scan
687
+ * over the union of the core dynamic tokens and every registered transform's
688
+ * own sniff tokens (see `withSniff`); most modules trigger nothing and skip the
689
+ * whole chain.
690
+ */
691
+ export function needsServerSourceRewrite(source: string) {
692
+ return sourceHasDynamicImport(source) || sourceNeedsServerTransforms(source)
693
+ }
694
+
695
+ export function rewriteServerSource(
696
+ source: string,
697
+ file: string,
698
+ options: { nextFonts?: boolean; root?: string } = {},
699
+ ) {
700
+ const root = options.root ?? path.dirname(file)
701
+ const rewritten = sourceHasDynamicImport(source)
702
+ ? rewriteDynamicCallTargets(
703
+ rewriteLiteralDynamicCalls(source, file),
704
+ specifier => resolveImport(root, file, specifier),
705
+ file,
706
+ )
707
+ : source
708
+ // Compat pre-transforms (next/font/root-params) run before generic server
709
+ // transforms (use-cache/action tags). Pure-core apps register no transforms.
710
+ if (options.nextFonts === false) return rewritten
711
+ if (!sourceNeedsServerTransforms(rewritten)) return rewritten
712
+ return applyServerSourceTransforms(
713
+ applyServerSourcePreTransforms(rewritten, file, options.root),
714
+ file,
715
+ options.root,
716
+ )
717
+ }
718
+
719
+ export function serverRequireAlias(
720
+ specifier: string,
721
+ target: string,
722
+ kind: string | undefined,
723
+ ): string {
724
+ if (kind !== 'require-call') return target
725
+ if (specifier === 'next/navigation' && target.endsWith(`${path.sep}navigation.ts`)) {
726
+ return path.join(path.dirname(target), 'navigation.cjs')
727
+ }
728
+ if (specifier === 'next/router' && target.endsWith(`${path.sep}router.ts`)) {
729
+ return path.join(path.dirname(target), 'router.cjs')
730
+ }
731
+ return target
732
+ }
733
+
734
+ export function runtimeAliasBuildPlugin(
735
+ config?: ResolvedConfig,
736
+ target: CompatAliasTarget = 'server',
737
+ options: { bundleRequireAliases?: boolean; reactServerLayer?: boolean } = {},
738
+ ): Plugin {
739
+ const aliases = config ? coreAliases(config, target) : undefined
740
+ // A node_modules package bundled into the RSC (react-server) layer that requires 'react' must observe the
741
+ // react-server subset - no client-hook dispatcher - exactly like the framework's own react-server modules,
742
+ // so a package's `'useState' in require('react')` probe reads false on the server. ESM named imports stay
743
+ // external and resolve at runtime against the full-hooks server shim (kept for pages/api back-compat), so
744
+ // this narrow require-call override never breaks them.
745
+ const reactServerLayerAliases =
746
+ config && options.reactServerLayer
747
+ ? getImportAliasExtensions().reactServerLayerAliases(config)
748
+ : undefined
749
+ return {
750
+ name: 'pnext-runtime-build-alias',
751
+ setup(build) {
752
+ build.onResolve({ filter: /^\.\/preact$/ }, args => {
753
+ // `./preact` is the compat react shim's private import. It also appears in MIRRORED copies of the
754
+ // shim (build-cache outputs under node_modules paths) where no sibling preact file exists - those
755
+ // must resolve to the single compat instance too. Only a REAL sibling ./preact.* opts out.
756
+ const hasRealSibling = ['.ts', '.tsx', '.js', '.mjs', '.jsx'].some(ext =>
757
+ existsSync(path.join(args.resolveDir, `preact${ext}`)),
758
+ )
759
+ const compatPreact = path.resolve(import.meta.dirname, '..', 'compat', 'react', 'preact.ts')
760
+ if (hasRealSibling && path.resolve(args.resolveDir, 'preact.ts') !== compatPreact)
761
+ return undefined
762
+ return { path: compatPreact }
763
+ })
764
+ build.onResolve({ filter: /^\.\.\/client\/errors\/primitive-throw$/ }, args => {
765
+ const compatPreact = path.resolve(import.meta.dirname, '..', 'compat', 'react', 'preact.ts')
766
+ if (path.resolve(args.importer) !== compatPreact) return undefined
767
+ return {
768
+ path: path.resolve(
769
+ import.meta.dirname,
770
+ '..',
771
+ 'compat',
772
+ 'client',
773
+ 'errors',
774
+ 'primitive-throw.ts',
775
+ ),
776
+ }
777
+ })
778
+ build.onResolve({ filter: aliasSpecifierFilter }, args => {
779
+ const resolved = aliases?.[args.path] ?? firstAliasForSpecifier(args.path)
780
+ if (!resolved) return undefined
781
+ const requireTarget = serverRequireAlias(args.path, resolved, args.kind)
782
+ if (requireTarget !== resolved) return { path: requireTarget }
783
+ if (options.bundleRequireAliases && args.kind === 'require-call') {
784
+ const layerTarget = serverRequireAlias(
785
+ args.path,
786
+ reactServerLayerAliases?.[args.path] ?? resolved,
787
+ args.kind,
788
+ )
789
+ return { path: path.isAbsolute(layerTarget) ? layerTarget : require.resolve(layerTarget) }
790
+ }
791
+ return {
792
+ path: path.isAbsolute(resolved) ? pathToFileHref(resolved) : resolved,
793
+ external: true,
794
+ }
795
+ })
796
+ },
797
+ }
798
+ }
799
+
800
+ function isInside(root: string, file: string) {
801
+ const relative = path.relative(root, file)
802
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
803
+ }
804
+
805
+ function rootPaths(root: string) {
806
+ const key = path.resolve(root)
807
+ const cached = rootPathCache.get(key)
808
+ if (cached) return cached
809
+ const paths = new Set([path.resolve(root)])
810
+ try {
811
+ paths.add(realpathSync.native(root))
812
+ } catch {
813
+ // The dev cache root is registered before it exists.
814
+ }
815
+ const resolved = [...paths]
816
+ rootPathCache.set(key, resolved)
817
+ return resolved
818
+ }
819
+
820
+ function rootFilter(root: string) {
821
+ // Base source extensions plus any extra loadable extensions registered by
822
+ // compat (e.g. mdx/md via pageExtensions). Without these, `.mdx` modules skip
823
+ // the transform load hook and resolve as raw assets (default export = path).
824
+ const extras = currentLoadExtras().map(escapeRegex)
825
+ const exts = ['[jt]sx?', ...extras].join('|')
826
+ // Exclude `next.config.{js,cjs,mjs,ts}`: it is loaded for its exported value (often CommonJS
827
+ // `module.exports = ...`), not as part of the app's server module graph. Routing it through the
828
+ // ES-module source transform drops the CJS exports, silently disabling next.config
829
+ // rewrites/redirects.
830
+ // Exclude the vendor tree under the cache root: the `*.dist/` copies copyBrowserReadyEsmDist
831
+ // publishes are verbatim third-party ESM the copy predicate has already proved needs no server
832
+ // rewrite, but they are `.js`, so each was read and re-transformed on every boot. Bun loads them
833
+ // natively instead. Two clauses because the vendor tree is reachable from two registered roots.
834
+ const vendorGuard = vendorLoadsNatively()
835
+ ? `${root.endsWith(`${path.sep}cache${path.sep}server`) ? '(?!\\/vendor\\/)' : ''}(?!.*\\/cache\\/server\\/vendor\\/)`
836
+ : ''
837
+ return new RegExp(
838
+ `^${escapeRegex(root)}${vendorGuard}(?!.*\\/node_modules\\/)(?!\\/next\\.config\\.(?:js|cjs|mjs|ts)$)(?:/.*)?\\.(?:${exts})$`,
839
+ )
840
+ }
841
+
842
+ function esbuildLoader(file: string) {
843
+ if (file.endsWith('.tsx')) return 'tsx'
844
+ if (file.endsWith('.ts')) return 'ts'
845
+ // Workspace .js/.jsx may contain JSX (Next allows it); jsx is a js superset.
846
+ return 'jsx'
847
+ }
848
+
849
+ function hashRoot(value: string) {
850
+ let hash = 5381
851
+ for (const char of value) hash = ((hash << 5) + hash) ^ char.charCodeAt(0)
852
+ return (hash >>> 0).toString(36)
853
+ }
854
+
855
+ export function hashBundleSpecifier(value: string) {
856
+ return createHash('sha256').update(value).digest('hex').slice(0, 16)
857
+ }
858
+
859
+ /**
860
+ * Bisect switch for the vendor-tree load-plugin exclusion. Deliberately NOT `PNEXT_VENDOR_NATIVE` -
861
+ * that name already gates the plugin-free bundler, and sharing it would arm that opt-in path by
862
+ * accident whenever this one was bisected.
863
+ */
864
+ export function vendorLoadsNatively() {
865
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
866
+ return process.env.PNEXT_VENDOR_DIST_NATIVE !== '0'
867
+ }
868
+
869
+ // --------------------------------------------------------------------------
870
+ // pre-planned vendor policy (PNEXT_VENDOR_PREPLAN=1 opt-in, server layer only)
871
+ // --------------------------------------------------------------------------
872
+
873
+ export const serverIgnoredAssetFilter =
874
+ /\.(?:css|scss|sass|woff2?|ttf|otf|eot|png|jpe?g|gif|webp|avif|svg|ico|bmp)(?:$|[?#])/
875
+
876
+ function isCssFile(file: string) {
877
+ return file.endsWith('.css')
878
+ }
879
+
880
+ function isStaticImageFile(file: string) {
881
+ return /\.(?:png|jpe?g|gif|webp|avif|svg|ico|bmp)(?:$|[?#])/.test(file)
882
+ }
883
+
884
+ function resolveAssetPath(specifier: string, resolveDir: string) {
885
+ const [sourcePath = '', hash = ''] = specifier.split('#', 2)
886
+ const resolved = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(resolveDir, sourcePath)
887
+ return hash ? `${resolved}#${hash}` : resolved
888
+ }
889
+
890
+ async function staticImageModuleSource(config: ResolvedConfig | undefined, file: string) {
891
+ const [sourcePath = ''] = file.split('#', 1)
892
+ const bytes = new Uint8Array(await readFile(sourcePath))
893
+ const emitted: { relative: string; bytes: Uint8Array }[] = []
894
+ const emit = (relative: string, data: Uint8Array) => {
895
+ emitted.push({ relative, bytes: data })
896
+ return `/${relative}`
897
+ }
898
+ const compat = await getAssetExtensions().staticAssetModule({ sourcePath, bytes, emit })
899
+ const source = compat ?? coreStaticAssetModule(sourcePath, bytes, emit)
900
+ if (config) {
901
+ for (const asset of emitted) {
902
+ const target = path.join(config.outPath, 'public', ...asset.relative.split('/'))
903
+ await mkdir(path.dirname(target), { recursive: true })
904
+ if (!existsSync(target)) await Bun.write(target, asset.bytes)
905
+ }
906
+ }
907
+ return source
908
+ }
909
+
910
+ // Core's generic static-asset module: emit the file under a hashed media URL
911
+ // and export it as the default (a plain URL string) when no compat override is
912
+ // registered. next/image compat replaces this with a full StaticImageData shape.
913
+ function coreStaticAssetModule(
914
+ sourcePath: string,
915
+ bytes: Uint8Array,
916
+ emit: (relative: string, bytes: Uint8Array) => string,
917
+ ): string {
918
+ const ext = path.extname(sourcePath).toLowerCase() || '.bin'
919
+ const hash = createHash('sha256').update(bytes).digest('hex').slice(0, 8)
920
+ const base = path.basename(sourcePath, path.extname(sourcePath)).replace(/[^A-Za-z0-9_-]+/g, '-')
921
+ const relative = getAssetExtensions().staticAssetRelativePath({ sourcePath, hash, base, ext })
922
+ const src = emit(relative, bytes)
923
+ return `const src = ${JSON.stringify(src)};\nexport default src;\nexport { src };\n`
924
+ }
925
+
926
+ export function serverAssetPlugin(config?: ResolvedConfig): Plugin {
927
+ return {
928
+ name: 'pnext-empty-server-assets',
929
+ setup(build) {
930
+ build.onResolve({ filter: serverIgnoredAssetFilter }, args => {
931
+ const resolved = resolveAssetPath(args.path, args.resolveDir)
932
+ // A configured `turbopack.rules` loader chain for this extension (e.g.
933
+ // `*.svg`) preempts the generic asset pipeline: defer so the compat
934
+ // loader-rule plugin's onLoad runs the chain against the real file.
935
+ if (getAssetExtensions().hasLoaderRuleFor(resolved)) {
936
+ return undefined
937
+ }
938
+ return { path: resolved, namespace: 'pnext-empty-server-asset' }
939
+ })
940
+ build.onLoad({ filter: /.*/, namespace: 'pnext-empty-server-asset' }, async args => ({
941
+ contents:
942
+ getCssExtensions().loadCssModuleForClient(args.path) ??
943
+ (isCssFile(args.path)
944
+ ? ''
945
+ : isStaticImageFile(args.path)
946
+ ? await staticImageModuleSource(config, args.path)
947
+ : 'export default "";'),
948
+ loader: 'js',
949
+ }))
950
+ },
951
+ }
952
+ }