@wular/pnext 0.0.4 → 0.0.7

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