@wular/pnext 0.0.1

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 (371) hide show
  1. package/README.md +153 -0
  2. package/bin/pnext +67 -0
  3. package/config/lint/base.js +48 -0
  4. package/config/ts/base.json +26 -0
  5. package/config/ts/react.json +13 -0
  6. package/package.json +70 -0
  7. package/reference/compat.md +63 -0
  8. package/reference/config.md +120 -0
  9. package/reference/css.md +58 -0
  10. package/reference/dev.md +69 -0
  11. package/reference/env.md +40 -0
  12. package/reference/metadata.md +86 -0
  13. package/reference/navigation.md +149 -0
  14. package/reference/overview.md +35 -0
  15. package/reference/performance.md +97 -0
  16. package/reference/rendering.md +127 -0
  17. package/reference/routing.md +167 -0
  18. package/reference/typegen.md +64 -0
  19. package/src/api/cache.ts +80 -0
  20. package/src/api/client-cache.ts +9 -0
  21. package/src/api/client-navigation.ts +279 -0
  22. package/src/api/dynamic.tsx +102 -0
  23. package/src/api/link.tsx +119 -0
  24. package/src/api/navigation.ts +198 -0
  25. package/src/api/router/events.ts +53 -0
  26. package/src/api/router/history.ts +70 -0
  27. package/src/api/router/hub.ts +194 -0
  28. package/src/api/router/policies.ts +107 -0
  29. package/src/api/router/runtime.ts +5238 -0
  30. package/src/api/router/types.ts +299 -0
  31. package/src/api/router.ts +167 -0
  32. package/src/api/server.ts +323 -0
  33. package/src/api/suspense.ts +16 -0
  34. package/src/cache/context.ts +61 -0
  35. package/src/cli/adapters/vercel-warm.ts +375 -0
  36. package/src/cli/adapters/vercel.ts +1310 -0
  37. package/src/cli/analyze-print.ts +181 -0
  38. package/src/cli/analyze.ts +328 -0
  39. package/src/cli/boot-trace.ts +29 -0
  40. package/src/cli/build.ts +3114 -0
  41. package/src/cli/dev.ts +276 -0
  42. package/src/cli/index.ts +196 -0
  43. package/src/cli/named-bin.ts +119 -0
  44. package/src/cli/serve-ui.ts +160 -0
  45. package/src/cli/start.ts +1425 -0
  46. package/src/client/build.ts +2136 -0
  47. package/src/client/chunk-fold.ts +526 -0
  48. package/src/client/entry.ts +1525 -0
  49. package/src/client/paths.ts +22 -0
  50. package/src/client/prebuilt.ts +621 -0
  51. package/src/client/profile.ts +75 -0
  52. package/src/client/react-compiler.ts +94 -0
  53. package/src/client/reference-stub.ts +145 -0
  54. package/src/client/reference.ts +47 -0
  55. package/src/compat/actions/action-client.ts +531 -0
  56. package/src/compat/actions/action-dispatch.ts +676 -0
  57. package/src/compat/actions/action-router.ts +40 -0
  58. package/src/compat/actions/action-shared.ts +95 -0
  59. package/src/compat/actions/client-plugin.ts +135 -0
  60. package/src/compat/actions/client-stub.ts +65 -0
  61. package/src/compat/actions/config.ts +164 -0
  62. package/src/compat/actions/detect.ts +208 -0
  63. package/src/compat/actions/discovery.ts +244 -0
  64. package/src/compat/actions/early-submit.ts +40 -0
  65. package/src/compat/actions/endpoint.ts +602 -0
  66. package/src/compat/actions/flight.ts +52 -0
  67. package/src/compat/actions/form-state.ts +73 -0
  68. package/src/compat/actions/hoist.ts +485 -0
  69. package/src/compat/actions/ids.ts +39 -0
  70. package/src/compat/actions/index.ts +41 -0
  71. package/src/compat/actions/instances.ts +144 -0
  72. package/src/compat/actions/origin.ts +109 -0
  73. package/src/compat/actions/protocol.ts +125 -0
  74. package/src/compat/actions/registry.ts +74 -0
  75. package/src/compat/actions/rewrite.ts +282 -0
  76. package/src/compat/actions/serve.ts +414 -0
  77. package/src/compat/actions/server-tag.ts +21 -0
  78. package/src/compat/actions/unrecognized-error.ts +30 -0
  79. package/src/compat/adapter/build-complete.ts +257 -0
  80. package/src/compat/bundler/bun-externals.ts +53 -0
  81. package/src/compat/bundler/cjs-exports.ts +542 -0
  82. package/src/compat/bundler/config.ts +363 -0
  83. package/src/compat/bundler/externals.ts +34 -0
  84. package/src/compat/bundler/import-meta-url.ts +60 -0
  85. package/src/compat/bundler/modularize-imports.ts +119 -0
  86. package/src/compat/bundler/new-url-asset.ts +87 -0
  87. package/src/compat/bundler/optimize-package-imports.ts +273 -0
  88. package/src/compat/bundler/polyfill.ts +88 -0
  89. package/src/compat/bundler/react-compiler.ts +61 -0
  90. package/src/compat/bundler/react-profiler.tsx +25 -0
  91. package/src/compat/bundler/relay-transform.ts +116 -0
  92. package/src/compat/bundler/require-context.ts +281 -0
  93. package/src/compat/bundler/resolve-extensions.ts +75 -0
  94. package/src/compat/bundler/source-cache.ts +61 -0
  95. package/src/compat/bundler/static-imports.ts +25 -0
  96. package/src/compat/bundler/symlink-imports.ts +119 -0
  97. package/src/compat/bundler/tsconfig-paths.ts +50 -0
  98. package/src/compat/bundler/wasm.ts +153 -0
  99. package/src/compat/bundler/webpack-loaders.ts +685 -0
  100. package/src/compat/bundler/worker.ts +278 -0
  101. package/src/compat/cache/build-flags.ts +81 -0
  102. package/src/compat/cache/build-prerender-errors.ts +163 -0
  103. package/src/compat/cache/custom-handler.ts +159 -0
  104. package/src/compat/cache/fetch-patch.ts +745 -0
  105. package/src/compat/cache/handler.ts +100 -0
  106. package/src/compat/cache/modern-handler.ts +275 -0
  107. package/src/compat/cache/resume-data-cache.ts +143 -0
  108. package/src/compat/cache/revalidate.ts +759 -0
  109. package/src/compat/cache/runtime-error.ts +124 -0
  110. package/src/compat/cache/use-cache-transform.ts +961 -0
  111. package/src/compat/cache/use-cache.ts +1695 -0
  112. package/src/compat/cache-control.ts +269 -0
  113. package/src/compat/client/base-path.ts +64 -0
  114. package/src/compat/client/css-order.ts +36 -0
  115. package/src/compat/client/errors/control-flow.ts +92 -0
  116. package/src/compat/client/errors/error-boundary.ts +222 -0
  117. package/src/compat/client/errors/global-error.ts +238 -0
  118. package/src/compat/client/errors/install.ts +217 -0
  119. package/src/compat/client/errors/lazy.ts +53 -0
  120. package/src/compat/client/errors/primitive-throw.ts +126 -0
  121. package/src/compat/client/errors/soft-refresh.ts +14 -0
  122. package/src/compat/client/link-status.ts +86 -0
  123. package/src/compat/client/nav-compat-runtime.ts +57 -0
  124. package/src/compat/client/nav-compat.ts +42 -0
  125. package/src/compat/client/navigation-scroll.ts +154 -0
  126. package/src/compat/client/optimistic-routing.ts +206 -0
  127. package/src/compat/client/prefetch-cache.ts +111 -0
  128. package/src/compat/client/route-announcer.ts +72 -0
  129. package/src/compat/client/segment-cache-policy.ts +159 -0
  130. package/src/compat/client/segment-cache.ts +1077 -0
  131. package/src/compat/client/segment-prefetch.ts +375 -0
  132. package/src/compat/client/trailing-slash.ts +24 -0
  133. package/src/compat/css/chunking.ts +254 -0
  134. package/src/compat/css/inline-css.ts +73 -0
  135. package/src/compat/css/lightningcss.ts +90 -0
  136. package/src/compat/css/modules.ts +373 -0
  137. package/src/compat/css/nonce.ts +30 -0
  138. package/src/compat/css/sass-plugin.ts +65 -0
  139. package/src/compat/css/sass.ts +392 -0
  140. package/src/compat/css/styled-jsx-runtime.ts +80 -0
  141. package/src/compat/css/styled-jsx.ts +49 -0
  142. package/src/compat/edge-runtime.ts +71 -0
  143. package/src/compat/export/client.ts +112 -0
  144. package/src/compat/export/index.ts +272 -0
  145. package/src/compat/export/standalone.ts +207 -0
  146. package/src/compat/image-optimizer/cache.ts +119 -0
  147. package/src/compat/image-optimizer/detect.ts +143 -0
  148. package/src/compat/image-optimizer/index.ts +601 -0
  149. package/src/compat/image-optimizer/source.ts +243 -0
  150. package/src/compat/index.ts +458 -0
  151. package/src/compat/lifecycle/after-scope.ts +86 -0
  152. package/src/compat/lifecycle/after.ts +173 -0
  153. package/src/compat/lifecycle/error-funnel.ts +306 -0
  154. package/src/compat/lifecycle/error-serialize.ts +87 -0
  155. package/src/compat/lifecycle/error-ui.ts +167 -0
  156. package/src/compat/lifecycle/instrumentation-client.ts +138 -0
  157. package/src/compat/lifecycle/instrumentation.ts +277 -0
  158. package/src/compat/lifecycle/node-console.ts +19 -0
  159. package/src/compat/lifecycle/testmode.ts +263 -0
  160. package/src/compat/mdx/compile.ts +219 -0
  161. package/src/compat/mdx/next-mdx-stub.ts +46 -0
  162. package/src/compat/mdx/plugin.ts +37 -0
  163. package/src/compat/metadata-route-artifacts.ts +458 -0
  164. package/src/compat/metadata.ts +295 -0
  165. package/src/compat/middleware/manifest.ts +210 -0
  166. package/src/compat/misc/action-return.ts +173 -0
  167. package/src/compat/next/cache.ts +211 -0
  168. package/src/compat/next/canonical-url.ts +35 -0
  169. package/src/compat/next/client-cache.ts +57 -0
  170. package/src/compat/next/client-navigation.ts +313 -0
  171. package/src/compat/next/client-only.ts +3 -0
  172. package/src/compat/next/client-script.tsx +215 -0
  173. package/src/compat/next/client-server.ts +39 -0
  174. package/src/compat/next/config-loader.ts +569 -0
  175. package/src/compat/next/config.ts +29 -0
  176. package/src/compat/next/constants.cjs +6 -0
  177. package/src/compat/next/constants.ts +6 -0
  178. package/src/compat/next/custom-server.ts +236 -0
  179. package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
  180. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
  181. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
  182. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
  183. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
  184. package/src/compat/next/dynamic.tsx +46 -0
  185. package/src/compat/next/error.tsx +148 -0
  186. package/src/compat/next/font/cache.ts +171 -0
  187. package/src/compat/next/font/google.ts +2 -0
  188. package/src/compat/next/font/index.ts +8 -0
  189. package/src/compat/next/font/local.ts +5 -0
  190. package/src/compat/next/font/runtime-client.ts +71 -0
  191. package/src/compat/next/font/runtime.ts +974 -0
  192. package/src/compat/next/font/shared.ts +281 -0
  193. package/src/compat/next/form.tsx +156 -0
  194. package/src/compat/next/head.tsx +10 -0
  195. package/src/compat/next/headers.ts +247 -0
  196. package/src/compat/next/image/config.ts +196 -0
  197. package/src/compat/next/image/optimizer.ts +96 -0
  198. package/src/compat/next/image/patterns.ts +103 -0
  199. package/src/compat/next/image/shared.ts +141 -0
  200. package/src/compat/next/image/static-metadata.ts +283 -0
  201. package/src/compat/next/image/validate.ts +269 -0
  202. package/src/compat/next/image-client.tsx +215 -0
  203. package/src/compat/next/image-props.ts +575 -0
  204. package/src/compat/next/image-usage.ts +102 -0
  205. package/src/compat/next/image.tsx +56 -0
  206. package/src/compat/next/index.ts +1 -0
  207. package/src/compat/next/legacy-image.tsx +97 -0
  208. package/src/compat/next/link-usage.ts +29 -0
  209. package/src/compat/next/link-validation-transform.ts +200 -0
  210. package/src/compat/next/link.tsx +466 -0
  211. package/src/compat/next/navigation.cjs +21 -0
  212. package/src/compat/next/navigation.ts +188 -0
  213. package/src/compat/next/offline.ts +51 -0
  214. package/src/compat/next/og.ts +324 -0
  215. package/src/compat/next/optimistic-route-state.ts +188 -0
  216. package/src/compat/next/preferred-region.ts +39 -0
  217. package/src/compat/next/redirects.ts +131 -0
  218. package/src/compat/next/resource-hints.ts +136 -0
  219. package/src/compat/next/rewrites.ts +350 -0
  220. package/src/compat/next/root-params.ts +142 -0
  221. package/src/compat/next/router.cjs +49 -0
  222. package/src/compat/next/router.ts +143 -0
  223. package/src/compat/next/script.tsx +355 -0
  224. package/src/compat/next/server-only.ts +3 -0
  225. package/src/compat/next/server.ts +28 -0
  226. package/src/compat/next/svgr.ts +58 -0
  227. package/src/compat/next/telemetry.ts +77 -0
  228. package/src/compat/next/user-agent.ts +100 -0
  229. package/src/compat/next/web-vitals.ts +56 -0
  230. package/src/compat/otel/api.ts +95 -0
  231. package/src/compat/otel/client-trace-metadata.ts +71 -0
  232. package/src/compat/otel/fetch-span.ts +77 -0
  233. package/src/compat/otel/tracer.ts +944 -0
  234. package/src/compat/pages/client-plugin.ts +108 -0
  235. package/src/compat/pages/index.ts +527 -0
  236. package/src/compat/pages/router-state.ts +94 -0
  237. package/src/compat/ppr/io.ts +38 -0
  238. package/src/compat/ppr/missing-root-params.ts +105 -0
  239. package/src/compat/ppr/root-params-scan.ts +164 -0
  240. package/src/compat/ppr/root-params-transform.ts +75 -0
  241. package/src/compat/ppr/root-params.ts +129 -0
  242. package/src/compat/ppr/segment-config-incompat.ts +34 -0
  243. package/src/compat/protocol.ts +202 -0
  244. package/src/compat/react/client.ts +59 -0
  245. package/src/compat/react/compiler-runtime.ts +60 -0
  246. package/src/compat/react/dom-client.ts +115 -0
  247. package/src/compat/react/dom-react-server.ts +20 -0
  248. package/src/compat/react/dom-server.ts +40 -0
  249. package/src/compat/react/dom.ts +154 -0
  250. package/src/compat/react/preact.ts +522 -0
  251. package/src/compat/react/react-server.ts +84 -0
  252. package/src/compat/react/router-shim.ts +26 -0
  253. package/src/compat/react/server-component-use.ts +48 -0
  254. package/src/compat/react/server-inserted-html.ts +87 -0
  255. package/src/compat/react/server.ts +156 -0
  256. package/src/compat/react/view-transition.ts +60 -0
  257. package/src/compat/register/actions.ts +875 -0
  258. package/src/compat/register/boot.ts +141 -0
  259. package/src/compat/register/build-tier.ts +11 -0
  260. package/src/compat/register/build.ts +182 -0
  261. package/src/compat/register/bundler.ts +587 -0
  262. package/src/compat/register/cache.ts +85 -0
  263. package/src/compat/register/client-errors.ts +18 -0
  264. package/src/compat/register/config.ts +17 -0
  265. package/src/compat/register/css-extras.ts +120 -0
  266. package/src/compat/register/edge-runtime.ts +6 -0
  267. package/src/compat/register/errors.ts +46 -0
  268. package/src/compat/register/export.ts +23 -0
  269. package/src/compat/register/font.ts +36 -0
  270. package/src/compat/register/hooks.ts +34 -0
  271. package/src/compat/register/image.ts +133 -0
  272. package/src/compat/register/index.ts +111 -0
  273. package/src/compat/register/instrumentation-client.ts +35 -0
  274. package/src/compat/register/lifecycle.ts +86 -0
  275. package/src/compat/register/mdx.ts +48 -0
  276. package/src/compat/register/middleware.ts +36 -0
  277. package/src/compat/register/misc.ts +44 -0
  278. package/src/compat/register/otel.ts +288 -0
  279. package/src/compat/register/pages-api.ts +473 -0
  280. package/src/compat/register/ppr.ts +56 -0
  281. package/src/compat/register/protocol.ts +57 -0
  282. package/src/compat/register/proxy.ts +127 -0
  283. package/src/compat/register/render.ts +268 -0
  284. package/src/compat/register/routing.ts +410 -0
  285. package/src/compat/register/segment.ts +1903 -0
  286. package/src/compat/register/static-image.ts +21 -0
  287. package/src/compat/register/typed-routes.ts +35 -0
  288. package/src/compat/register/usecache.ts +131 -0
  289. package/src/compat/register/validation.ts +56 -0
  290. package/src/compat/segment/loading-boundary.ts +113 -0
  291. package/src/compat/segment/page-slot.ts +200 -0
  292. package/src/compat/segment/tree.ts +481 -0
  293. package/src/compat/segment/vary-key.ts +102 -0
  294. package/src/compat/segment/vary-params.ts +551 -0
  295. package/src/compat/static-params.ts +33 -0
  296. package/src/compat/tsconfig-defaults.ts +301 -0
  297. package/src/compat/typecheck/index.ts +1481 -0
  298. package/src/compat/typecheck/worker.ts +26 -0
  299. package/src/compat/typed-routes/index.ts +92 -0
  300. package/src/compat/typed-routes/manifest.ts +356 -0
  301. package/src/compat/typed-routes/typegen.ts +566 -0
  302. package/src/compat/validation/errors.ts +159 -0
  303. package/src/compat/validation/index.ts +1770 -0
  304. package/src/compat/validation/prerender-diagnostics.ts +1508 -0
  305. package/src/compat-bootstrap.ts +67 -0
  306. package/src/config.ts +218 -0
  307. package/src/css/build.ts +697 -0
  308. package/src/css/index.ts +2 -0
  309. package/src/css/postcss.ts +236 -0
  310. package/src/css/worker.ts +34 -0
  311. package/src/dev/client-actions.ts +35 -0
  312. package/src/dev/client-chunk-store.ts +92 -0
  313. package/src/dev/client-key-cache.ts +178 -0
  314. package/src/dev/global-css-cache.ts +212 -0
  315. package/src/dev/imports.ts +2430 -0
  316. package/src/dev/module-cache.ts +721 -0
  317. package/src/dev/module-generations.ts +38 -0
  318. package/src/dev/module-transform.ts +188 -0
  319. package/src/dev/node-module-bundle-cache.ts +63 -0
  320. package/src/dev/restart-cache.ts +10 -0
  321. package/src/dev/route-bundle-key-cache.ts +154 -0
  322. package/src/dev/route-facts-cache.ts +223 -0
  323. package/src/dev/server.ts +1710 -0
  324. package/src/dynamic/source.ts +307 -0
  325. package/src/dynamic/tree-shake.ts +262 -0
  326. package/src/env.ts +92 -0
  327. package/src/extensions.ts +1898 -0
  328. package/src/index.ts +34 -0
  329. package/src/internal.ts +43 -0
  330. package/src/islands/boundary-error.ts +8 -0
  331. package/src/islands/static-children.ts +37 -0
  332. package/src/islands/static-slots.ts +106 -0
  333. package/src/ppr-postpone.ts +24 -0
  334. package/src/ppr.ts +784 -0
  335. package/src/proxy.ts +752 -0
  336. package/src/render/hooks.ts +384 -0
  337. package/src/render/index.ts +1 -0
  338. package/src/render/island-context.ts +47 -0
  339. package/src/render/metadata.ts +857 -0
  340. package/src/render/renderer.ts +7391 -0
  341. package/src/render/resource-hints.ts +44 -0
  342. package/src/render/slots.tsx +679 -0
  343. package/src/request/context.ts +396 -0
  344. package/src/resolve/engine.ts +219 -0
  345. package/src/resolve/imports.ts +1104 -0
  346. package/src/resolve/scan-facts.ts +474 -0
  347. package/src/resolve/source-text.ts +86 -0
  348. package/src/routing/forwarded.ts +41 -0
  349. package/src/routing/handler.ts +271 -0
  350. package/src/routing/href.ts +203 -0
  351. package/src/routing/metadata.ts +1018 -0
  352. package/src/routing/request-runtime.ts +43 -0
  353. package/src/routing/routes.ts +2560 -0
  354. package/src/routing/slots.ts +432 -0
  355. package/src/runtime/server.ts +3453 -0
  356. package/src/runtime/vendor.ts +1160 -0
  357. package/src/style-modules.d.ts +9 -0
  358. package/src/typegen.ts +151 -0
  359. package/src/types.ts +725 -0
  360. package/src/utils/ansi.ts +9 -0
  361. package/src/utils/content-type.ts +31 -0
  362. package/src/utils/decode.ts +7 -0
  363. package/src/utils/dev-profile.ts +31 -0
  364. package/src/utils/error-log.ts +29 -0
  365. package/src/utils/fs-cache.ts +31 -0
  366. package/src/utils/fs.ts +119 -0
  367. package/src/utils/html.ts +46 -0
  368. package/src/utils/serialize.ts +378 -0
  369. package/src/utils/source.ts +35 -0
  370. package/src/utils/verbose.ts +39 -0
  371. package/tsconfig.json +10 -0
@@ -0,0 +1,363 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Bundler config accessors (COMPAT).
3
+ //
4
+ // Small typed readers over the loaded next.config (getNextConfig()) for the
5
+ // bundler-feature plugins. Kept in one place so every plugin reads the same
6
+ // normalized shapes and a pure-core / non-next app (empty config) degrades to
7
+ // safe defaults.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ import { getNextConfig } from '../next/config-loader';
11
+ import type { ModularizeRule } from './modularize-imports';
12
+
13
+ /** A predefined built-in set kept external server-side (Next ships this list). */
14
+ const PREDEFINED_SERVER_EXTERNAL_PACKAGES = [
15
+ 'sharp',
16
+ 'sqlite3',
17
+ 'better-sqlite3',
18
+ 'canvas',
19
+ '@node-rs/argon2',
20
+ '@node-rs/bcrypt',
21
+ ];
22
+
23
+ function stringArray(value: unknown): string[] {
24
+ return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [];
25
+ }
26
+
27
+ /**
28
+ * `serverExternalPackages` + the predefined built-in list: packages kept external
29
+ * (resolved from node_modules, never bundled) in the server graph.
30
+ */
31
+ export function serverExternalPackages(): Set<string> {
32
+ const config = getNextConfig();
33
+ return new Set([
34
+ ...PREDEFINED_SERVER_EXTERNAL_PACKAGES,
35
+ ...stringArray(config.serverExternalPackages),
36
+ ]);
37
+ }
38
+
39
+ /**
40
+ * The build's deployment id: next.config `deploymentId`, else the
41
+ * `NEXT_DEPLOYMENT_ID` env var (Next accepts either). Inlined into every graph
42
+ * and written to `required-server-files.json` so tooling can read it back.
43
+ */
44
+ export function deploymentId(): string | undefined {
45
+ const configured = getNextConfig().deploymentId;
46
+ if (typeof configured === 'string' && configured.length > 0) return configured;
47
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
48
+ const fromEnv = process.env.NEXT_DEPLOYMENT_ID;
49
+ return fromEnv && fromEnv.length > 0 ? fromEnv : undefined;
50
+ }
51
+
52
+ /** `publicRuntimeConfig`: the subset of runtime config safe to inline into client bundles. */
53
+ export function publicRuntimeConfig(): Record<string, unknown> {
54
+ const config = getNextConfig().publicRuntimeConfig;
55
+ return config && typeof config === 'object' ? (config as Record<string, unknown>) : {};
56
+ }
57
+
58
+ /** `transpilePackages`: node_modules packages force-bundled + transpiled. */
59
+ export function transpilePackages(): string[] {
60
+ return stringArray(getNextConfig().transpilePackages);
61
+ }
62
+
63
+ /**
64
+ * `modularizeImports`: specifier -> `{ transform, skipDefaultConversion }`
65
+ * rules that split barrel imports into per-member imports. Only the string
66
+ * `transform` template form is honored (the shape Next's compat fixtures use);
67
+ * malformed/object-template entries are dropped so a build still proceeds.
68
+ */
69
+ export function modularizeImports(): Record<string, ModularizeRule> {
70
+ const raw = getNextConfig().modularizeImports;
71
+ if (!raw || typeof raw !== 'object') return {};
72
+ const out: Record<string, ModularizeRule> = {};
73
+ for (const [specifier, value] of Object.entries(raw as Record<string, unknown>)) {
74
+ if (value && typeof value === 'object' && typeof (value as ModularizeRule).transform === 'string') {
75
+ const rule = value as ModularizeRule;
76
+ out[specifier] = {
77
+ transform: rule.transform,
78
+ skipDefaultConversion: Boolean(rule.skipDefaultConversion),
79
+ };
80
+ }
81
+ }
82
+ return out;
83
+ }
84
+
85
+ /**
86
+ * `experimental.optimizePackageImports`: barrel packages whose named imports
87
+ * are rewritten to their leaf modules (see optimize-package-imports.ts). The
88
+ * configured list EXTENDS the built-in default set, as Next's does.
89
+ */
90
+ export function optimizePackageImports(): string[] {
91
+ const experimental = getNextConfig().experimental as
92
+ | { optimizePackageImports?: unknown }
93
+ | undefined;
94
+ return stringArray(experimental?.optimizePackageImports);
95
+ }
96
+
97
+ /** A normalized `compiler.relay` entry (see relay-transform.ts). */
98
+ export interface RelayCompilerConfig {
99
+ /** Source root the transform applies to, relative to `process.cwd()`. */
100
+ src: string;
101
+ /** Where relay-compiler wrote its artifacts, relative to `process.cwd()`. */
102
+ artifactDirectory?: string;
103
+ /** The artifact language: decides the generated file's extension. */
104
+ language: 'javascript' | 'typescript' | 'flow';
105
+ }
106
+
107
+ /**
108
+ * `compiler.relay`: the Relay SWC transform's config. `src` is required by
109
+ * Next's schema; `language` defaults to `'javascript'`. Returns undefined when
110
+ * unconfigured so the transform stays a no-op.
111
+ */
112
+ export function relayCompilerConfig(): RelayCompilerConfig | undefined {
113
+ const compiler = getNextConfig().compiler as
114
+ | { relay?: { src?: unknown; artifactDirectory?: unknown; language?: unknown } }
115
+ | undefined;
116
+ const relay = compiler?.relay;
117
+ if (!relay || typeof relay !== 'object' || typeof relay.src !== 'string') return undefined;
118
+ const language = relay.language;
119
+ return {
120
+ src: relay.src,
121
+ artifactDirectory:
122
+ typeof relay.artifactDirectory === 'string' ? relay.artifactDirectory : undefined,
123
+ language:
124
+ language === 'typescript' || language === 'flow' || language === 'javascript'
125
+ ? language
126
+ : 'javascript',
127
+ };
128
+ }
129
+
130
+ /**
131
+ * `experimental.esmExternals`: `true` (default) | `false` | `'loose'`.
132
+ * Controls whether ESM externals stay external or are bundled.
133
+ */
134
+ export function esmExternals(): boolean | 'loose' {
135
+ const experimental = getNextConfig().experimental as
136
+ | { esmExternals?: boolean | 'loose' }
137
+ | undefined;
138
+ return experimental?.esmExternals ?? true;
139
+ }
140
+
141
+ /**
142
+ * `resolveExtensions`: user-supplied resolver extension order, if any. Next accepts the top-level key,
143
+ * `turbopack.resolveExtensions`, and the legacy `experimental.turbo.resolveExtensions` spelling.
144
+ */
145
+ export function resolveExtensions(): string[] | undefined {
146
+ const config = getNextConfig();
147
+ const turbopack = config.turbopack as { resolveExtensions?: unknown } | undefined;
148
+ const experimental = config.experimental as
149
+ | { turbo?: { resolveExtensions?: unknown } }
150
+ | undefined;
151
+ for (const value of [
152
+ config.resolveExtensions,
153
+ turbopack?.resolveExtensions,
154
+ experimental?.turbo?.resolveExtensions,
155
+ ]) {
156
+ const list = stringArray(value);
157
+ if (list.length > 0) return list;
158
+ }
159
+ return undefined;
160
+ }
161
+
162
+ /** `typescript.tsconfigPath`: a non-default tsconfig location. */
163
+ export function tsconfigPath(): string | undefined {
164
+ const ts = getNextConfig().typescript as { tsconfigPath?: string } | undefined;
165
+ return typeof ts?.tsconfigPath === 'string' ? ts.tsconfigPath : undefined;
166
+ }
167
+
168
+ export interface CompilerDefines {
169
+ /** Inlined into BOTH server and client bundles. */
170
+ define: Record<string, string>;
171
+ /** Inlined into the SERVER bundle only (client sees the fallback). */
172
+ defineServer: Record<string, string>;
173
+ }
174
+
175
+ function normalizeDefineMap(value: unknown): Record<string, string> {
176
+ if (!value || typeof value !== 'object') return {};
177
+ const out: Record<string, string> = {};
178
+ for (const [key, raw] of Object.entries(value as Record<string, unknown>)) {
179
+ // esbuild `define` values must be JS source text: strings need to be
180
+ // JSON-encoded, primitives stringified.
181
+ if (typeof raw === 'string') out[key] = JSON.stringify(raw);
182
+ else if (typeof raw === 'number' || typeof raw === 'boolean') out[key] = String(raw);
183
+ }
184
+ return out;
185
+ }
186
+
187
+ /** `compiler.define` / `compiler.defineServer` inlined-constant maps. */
188
+ export function compilerDefines(): CompilerDefines {
189
+ const compiler = getNextConfig().compiler as
190
+ | { define?: Record<string, unknown>; defineServer?: Record<string, unknown> }
191
+ | undefined;
192
+ return {
193
+ define: normalizeDefineMap(compiler?.define),
194
+ defineServer: normalizeDefineMap(compiler?.defineServer),
195
+ };
196
+ }
197
+
198
+ /** The console methods Next's SWC `removeConsole` transform can target. */
199
+ const CONSOLE_METHODS = [
200
+ 'assert',
201
+ 'clear',
202
+ 'count',
203
+ 'countReset',
204
+ 'debug',
205
+ 'dir',
206
+ 'dirxml',
207
+ 'error',
208
+ 'group',
209
+ 'groupCollapsed',
210
+ 'groupEnd',
211
+ 'info',
212
+ 'log',
213
+ 'table',
214
+ 'time',
215
+ 'timeEnd',
216
+ 'timeLog',
217
+ 'trace',
218
+ 'warn',
219
+ ];
220
+
221
+ /**
222
+ * `compiler.removeConsole`: `true` strips every `console.*` call; `{ exclude }`
223
+ * strips all methods except the listed ones. Returns the `console.<method>`
224
+ * esbuild `pure` targets to strip, or `undefined` when unconfigured.
225
+ */
226
+ export function removeConsoleTargets(): string[] | undefined {
227
+ const compiler = getNextConfig().compiler as
228
+ | { removeConsole?: boolean | { exclude?: unknown } }
229
+ | undefined;
230
+ const removeConsole = compiler?.removeConsole;
231
+ if (!removeConsole) return undefined;
232
+ const exclude = new Set(
233
+ typeof removeConsole === 'object' ? stringArray(removeConsole.exclude) : [],
234
+ );
235
+ return CONSOLE_METHODS.filter(method => !exclude.has(method)).map(method => `console.${method}`);
236
+ }
237
+
238
+ /** `cacheComponents` (PPR): gates the `next-js` export condition. */
239
+ export function cacheComponentsEnabled(): boolean {
240
+ const config = getNextConfig();
241
+ const experimental = config.experimental as { cacheComponents?: boolean } | undefined;
242
+ return Boolean(config.cacheComponents ?? experimental?.cacheComponents);
243
+ }
244
+
245
+ /**
246
+ * `experimental.swcEnvOptions`: when `mode: 'usage'`, SWC injects core-js
247
+ * polyfills for JS features the build targets (per browserslist) that the user
248
+ * code actually uses. pnext mirrors the user-visible outcome for the features
249
+ * apps rely on: usage-based injection of the matching core-js module into the
250
+ * client graph. Returns the configured mode (or undefined when unset).
251
+ */
252
+ export function swcEnvUsageMode(): 'usage' | 'entry' | undefined {
253
+ const experimental = getNextConfig().experimental as
254
+ | { swcEnvOptions?: { mode?: unknown } }
255
+ | undefined;
256
+ const mode = experimental?.swcEnvOptions?.mode;
257
+ return mode === 'usage' || mode === 'entry' ? mode : undefined;
258
+ }
259
+
260
+ /** Next's `reactCompiler` / legacy experimental flag. */
261
+ export function reactCompilerEnabled(): boolean {
262
+ const config = getNextConfig();
263
+ const experimental = config.experimental as { reactCompiler?: boolean } | undefined;
264
+ return Boolean(config.reactCompiler ?? experimental?.reactCompiler);
265
+ }
266
+
267
+ /** A single `turbopack.rules` entry, normalized to the shapes pnext supports. */
268
+ export interface WebpackLoaderRule {
269
+ /** The rule's glob key, e.g. `'*.txt'` or `'*.test-file.ts'`. Only a leading `*` wildcard is honored. */
270
+ glob: string;
271
+ /** Loader module specifiers (relative path or bare package name), applied in array order. */
272
+ loaders: string[];
273
+ /** The virtual extension of the loader chain's final output, e.g. `'*.js'`. */
274
+ as?: string;
275
+ /**
276
+ * A conditional rule guard: the rule only applies when the import's
277
+ * `resourceQuery` matches (string equality or a regex `.test`). Comes from the
278
+ * conditional-array rule form `'*.ext': [{ condition: { query }, loaders }]`.
279
+ */
280
+ condition?: { query: string | RegExp };
281
+ /**
282
+ * A no-loader `type` asset rule: how the raw file is represented as a module.
283
+ * `'resource'` emits the file under `/_next/static/media` and exports its URL
284
+ * string; `'bytes'` exports a `Uint8Array`; `'source'` exports the file text.
285
+ */
286
+ assetType?: 'resource' | 'bytes' | 'source';
287
+ }
288
+
289
+ /**
290
+ * `turbopack.rules`: Next's webpack-loader-rule config, read directly (rather
291
+ * than executing the `webpack(config)` mutator) since fixtures configure both
292
+ * spellings with equivalent semantics. Handles the loader shorthand/object
293
+ * form, the conditional-array form (`[{ condition, loaders, as }]`), and no-
294
+ * loader `type` asset rules (`{ type: 'asset' | 'bytes' | 'asset/source' }`).
295
+ */
296
+ export function turbopackLoaderRules(): WebpackLoaderRule[] {
297
+ const config = getNextConfig();
298
+ const turbopack = config.turbopack as { rules?: Record<string, unknown> } | undefined;
299
+ const rules = turbopack?.rules;
300
+ if (!rules || typeof rules !== 'object') return [];
301
+ const out: WebpackLoaderRule[] = [];
302
+ for (const [glob, raw] of Object.entries(rules)) collectLoaderRuleEntries(glob, raw, out);
303
+ return out;
304
+ }
305
+
306
+ function collectLoaderRuleEntries(glob: string, raw: unknown, out: WebpackLoaderRule[]): void {
307
+ if (Array.isArray(raw)) {
308
+ // A plain array of loader specifiers, or the conditional-array form whose
309
+ // entries are `{ condition, loaders, as }` objects.
310
+ if (raw.every(item => typeof item === 'string')) {
311
+ const loaders = stringArray(raw);
312
+ if (loaders.length > 0) out.push({ glob, loaders });
313
+ return;
314
+ }
315
+ for (const item of raw) {
316
+ if (item && typeof item === 'object') pushLoaderRuleObject(glob, item as Record<string, unknown>, out);
317
+ }
318
+ return;
319
+ }
320
+ if (raw && typeof raw === 'object') pushLoaderRuleObject(glob, raw as Record<string, unknown>, out);
321
+ }
322
+
323
+ function pushLoaderRuleObject(glob: string, entry: Record<string, unknown>, out: WebpackLoaderRule[]): void {
324
+ const loaders = stringArray(entry.loaders);
325
+ const as = typeof entry.as === 'string' ? entry.as : undefined;
326
+ const condition = parseRuleCondition(entry.condition);
327
+ if (loaders.length > 0) {
328
+ out.push({ glob, loaders, as, ...(condition ? { condition } : {}) });
329
+ return;
330
+ }
331
+ const assetType = parseAssetRuleType(entry.type);
332
+ if (assetType) out.push({ glob, loaders: [], as, assetType });
333
+ }
334
+
335
+ function parseRuleCondition(value: unknown): { query: string | RegExp } | undefined {
336
+ if (!value || typeof value !== 'object') return undefined;
337
+ const query = (value as { query?: unknown }).query;
338
+ if (typeof query === 'string' || query instanceof RegExp) return { query };
339
+ return undefined;
340
+ }
341
+
342
+ function parseAssetRuleType(value: unknown): 'resource' | 'bytes' | 'source' | undefined {
343
+ if (value === 'asset' || value === 'asset/resource') return 'resource';
344
+ if (value === 'bytes') return 'bytes';
345
+ if (value === 'asset/source') return 'source';
346
+ return undefined;
347
+ }
348
+
349
+ /**
350
+ * `turbopack.resolveAlias`: specifier-to-replacement-path mappings. Exact keys and trailing-glob keys
351
+ * are both honored. Values are returned verbatim - relative paths are resolved against the project root
352
+ * by the consumer.
353
+ */
354
+ export function turbopackResolveAlias(): Record<string, string> {
355
+ const turbopack = getNextConfig().turbopack as { resolveAlias?: unknown } | undefined;
356
+ const alias = turbopack?.resolveAlias;
357
+ if (!alias || typeof alias !== 'object') return {};
358
+ const out: Record<string, string> = {};
359
+ for (const [key, value] of Object.entries(alias as Record<string, unknown>)) {
360
+ if (typeof value === 'string') out[key] = value;
361
+ }
362
+ return out;
363
+ }
@@ -0,0 +1,34 @@
1
+ import type { Plugin } from 'esbuild';
2
+ import type { ResolvedConfig } from '../../config';
3
+ import { packageNameOfSpecifier, resolvePackageSpecifier } from '../../resolve/imports';
4
+ import { escapeRegex } from '../../utils/source';
5
+
6
+ /**
7
+ * Bundle configured server externals into client output with browser exports.
8
+ * The configured package names ARE the filter (plus their subpaths), so an app
9
+ * with no `serverExternalPackages` registers no plugin at all instead of paying
10
+ * a hook fire per bare import in the graph.
11
+ */
12
+ export function clientExternalPackageResolvePlugin(
13
+ config: ResolvedConfig,
14
+ externals: ReadonlySet<string>,
15
+ ): Plugin | undefined {
16
+ if (externals.size === 0) return undefined;
17
+ const filter = new RegExp(`^(?:${[...externals].map(escapeRegex).join('|')})(?:/|$)`);
18
+ return {
19
+ name: 'pnext-client-external-package-resolve',
20
+ setup(build) {
21
+ build.onResolve({ filter }, args => {
22
+ const packageName = packageNameOfSpecifier(args.path);
23
+ if (!packageName || !externals.has(packageName)) return undefined;
24
+ const resolved = resolvePackageSpecifier(
25
+ config.root,
26
+ `${args.importer || config.root}/pnext-resolve.ts`,
27
+ args.path,
28
+ ['import', 'browser', 'require', 'default'],
29
+ );
30
+ return resolved ? { path: resolved } : undefined;
31
+ });
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,60 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { rewriteFacts } from '../../resolve/scan-facts';
5
+ import { spliceSource } from '../../dev/module-transform';
6
+
7
+ export function sourceHasImportMetaUrl(source: string) {
8
+ return source.includes('import.meta.url');
9
+ }
10
+
11
+ /**
12
+ * Inline `import.meta.url` as the module's own file URL. Folded onto the module
13
+ * record's `importMetas` spans: exact by construction, where
14
+ * the regex also fired inside strings and comments.
15
+ */
16
+ export function rewriteImportMetaUrlSource(source: string, file: string) {
17
+ if (!sourceHasImportMetaUrl(source)) return source;
18
+ const facts = rewriteFacts(file, source);
19
+ if (facts.unreliable) return legacyRewriteImportMetaUrl(source, file);
20
+ const edits = facts.importMetas
21
+ .filter(meta => /^\.url\b/.test(source.slice(meta.end, meta.end + 5)))
22
+ .map(meta => ({
23
+ start: meta.start,
24
+ end: meta.end + 4,
25
+ value: JSON.stringify(pathToFileURL(virtualFixturePath(realSourcePath(file))).href),
26
+ }));
27
+ return edits.length > 0 ? spliceSource(source, edits) : source;
28
+ }
29
+
30
+ // A source oxc could only partially recover keeps the textual pass: an
31
+ // incomplete record would silently under-rewrite.
32
+ function legacyRewriteImportMetaUrl(source: string, file: string) {
33
+ return source.replace(
34
+ /\bimport\.meta\.url\b/g,
35
+ JSON.stringify(pathToFileURL(virtualFixturePath(realSourcePath(file))).href),
36
+ );
37
+ }
38
+
39
+ // Modules can reach the bundler through the pages-compat mirror's source-app/
40
+ // source-pages symlinks; inlining that symlinked path breaks code that walks
41
+ // the filesystem relative to import.meta.url (Next inlines the real path).
42
+ function realSourcePath(file: string) {
43
+ try {
44
+ return realpathSync(file);
45
+ } catch {
46
+ return file;
47
+ }
48
+ }
49
+
50
+ function virtualFixturePath(file: string) {
51
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
52
+ const root = process.env.PNEXT_IMPORT_META_URL_FIXTURE_ROOT;
53
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
54
+ const virtualRoot = process.env.PNEXT_IMPORT_META_URL_VIRTUAL_ROOT;
55
+ if (!root || !virtualRoot) return file;
56
+ const relative = path.relative(root, file);
57
+ return relative && !relative.startsWith(`..${path.sep}`) && relative !== '..'
58
+ ? path.join(virtualRoot, relative)
59
+ : file;
60
+ }
@@ -0,0 +1,119 @@
1
+ // next.config `modularizeImports` (COMPAT).
2
+ //
3
+ // Next rewrites barrel `import { A, B } from '<specifier>'` into per-member imports of individual
4
+ // modules, driven by a `transform` template. For fixtures whose barrel file does not exist at all (only
5
+ // the per-member modules do), the rewrite is the ONLY way the import resolves.
6
+ //
7
+ // This is a plain source transform: for each configured specifier it splits a matching named-import
8
+ // statement into one import per member, applying the template with the kebabCase/camelCase/lowerCase/
9
+ // upperCase helpers. `skipDefaultConversion: true` emits a NAMED import of the original member name
10
+ // from the target module; otherwise a DEFAULT import. Aliasing is preserved.
11
+ //
12
+ // It runs BEFORE path-alias resolution, so the emitted specifiers still flow through tsconfig `paths`
13
+ // resolution. Namespace, default and mixed-default imports of the specifier are left untouched - Next
14
+ // bails on those too.
15
+
16
+ import { rewriteFacts, type ImportBinding } from '../../resolve/scan-facts';
17
+ import { spliceSource } from '../../dev/module-transform';
18
+ import { withSniff, type ServerSourceTransform } from '../../extensions';
19
+ import { specifierSniffTokens } from '../../utils/source';
20
+
21
+ /** A normalized `modularizeImports[specifier]` entry (string-template form). */
22
+ export interface ModularizeRule {
23
+ /** The output-path template, e.g. `'#/design-system/icons/{{ kebabCase member }}'`. */
24
+ transform: string;
25
+ /** `true` => named import of the member from the target; otherwise a default import. */
26
+ skipDefaultConversion?: boolean;
27
+ }
28
+
29
+ /** Split an identifier into words on camelCase / digit / `_` / `-` boundaries. */
30
+ function splitWords(value: string): string[] {
31
+ return value
32
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
33
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
34
+ .replace(/[_-]+/g, ' ')
35
+ .trim()
36
+ .split(/\s+/)
37
+ .filter(Boolean);
38
+ }
39
+
40
+ /** Apply a template helper (`kebabCase`/`camelCase`/`lowerCase`/`upperCase`) to a member name. */
41
+ function applyHelper(helper: string, member: string): string {
42
+ switch (helper) {
43
+ case 'kebabCase':
44
+ return splitWords(member)
45
+ .map(word => word.toLowerCase())
46
+ .join('-');
47
+ case 'camelCase':
48
+ return splitWords(member)
49
+ .map((word, index) =>
50
+ index === 0 ? word.toLowerCase() : word[0]!.toUpperCase() + word.slice(1).toLowerCase(),
51
+ )
52
+ .join('');
53
+ case 'lowerCase':
54
+ return member.toLowerCase();
55
+ case 'upperCase':
56
+ return member.toUpperCase();
57
+ default:
58
+ return member;
59
+ }
60
+ }
61
+
62
+ /** Expand `{{ member }}` / `{{ helper member }}` placeholders in a transform template. */
63
+ function applyTemplate(template: string, member: string): string {
64
+ return template.replace(/\{\{\s*(?:(\w+)\s+)?member\s*\}\}/g, (_full, helper?: string) =>
65
+ helper ? applyHelper(helper, member) : member,
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Rewrite the members of one matched named import into per-member import
71
+ * statements. Returns `undefined` (leaving the original import untouched) for a
72
+ * clause the rewrite does not own: no members, or a `type` import.
73
+ */
74
+ function expandMembers(bindings: readonly ImportBinding[], rule: ModularizeRule): string | undefined {
75
+ if (bindings.length === 0) return undefined;
76
+
77
+ const statements: string[] = [];
78
+ for (const binding of bindings) {
79
+ if (binding.type || binding.imported === 'default' || binding.imported === '*') return undefined;
80
+ const original = binding.imported;
81
+ const local = binding.local;
82
+ const target = JSON.stringify(applyTemplate(rule.transform, original));
83
+ if (rule.skipDefaultConversion) {
84
+ const named = original === local ? original : `${original} as ${local}`;
85
+ statements.push(`import { ${named} } from ${target};`);
86
+ } else {
87
+ statements.push(`import ${local} from ${target};`);
88
+ }
89
+ }
90
+ return statements.join(' ');
91
+ }
92
+
93
+ /**
94
+ * Build a source transform applying the configured `modularizeImports` rules.
95
+ * Returns a no-op transform when nothing is configured so pure-core apps pay
96
+ * nothing.
97
+ */
98
+ export function createModularizeImportsTransform(
99
+ rules: Record<string, ModularizeRule>,
100
+ ): ServerSourceTransform {
101
+ if (Object.keys(rules).length === 0) return withSniff([], source => source);
102
+
103
+ // Folded onto the module record: one memoized parse instead
104
+ // of a per-rule import regex, and a configured specifier quoted in a string or
105
+ // a comment no longer expands.
106
+ return withSniff(specifierSniffTokens(Object.keys(rules)), (source, file) => {
107
+ if (!source.includes('import')) return source;
108
+ const edits: { start: number; end: number; value: string }[] = [];
109
+ for (const statement of rewriteFacts(file, source).imports) {
110
+ const rule = rules[statement.specifier];
111
+ if (!rule) continue;
112
+ const expanded = expandMembers(statement.bindings, rule);
113
+ if (expanded !== undefined) {
114
+ edits.push({ start: statement.start, end: statement.end, value: expanded });
115
+ }
116
+ }
117
+ return edits.length > 0 ? spliceSource(source, edits) : source;
118
+ });
119
+ }
@@ -0,0 +1,87 @@
1
+ // `new URL('./asset.png', import.meta.url)` asset references (COMPAT).
2
+ //
3
+ // Next/webpack rewrites this so it evaluates to the emitted client asset URL - the same URL an
4
+ // `import img from './asset.png'` produces - rather than a runtime file:// URL relative to the compiled
5
+ // bundle. Left intact, the literal resolves against the built bundle location, a path that never gets
6
+ // served.
7
+ //
8
+ // This reuses the static-image import pipeline: rewrite each matched call to `(<binding>.src)` and
9
+ // inject a top-level `import <binding> from '<spec>'`. That import flows through core's
10
+ // staticAssetModule seam, which emits the asset and yields the client URL. The `.src` string is what
11
+ // `.toString()` and `fileURLToPath()` (which then throws, as in Next's webpack path) observe.
12
+ //
13
+ // Applied to both graphs as a registered source transform.
14
+
15
+ import { rewriteReactProfilerServerSource } from './react-compiler';
16
+
17
+ // A `new URL('<image>', import.meta.url)` call whose first argument is a string
18
+ // literal ending in a static-image extension (optional ?query/#hash) and whose
19
+ // second argument is exactly `import.meta.url`. Non-asset `new URL(...)` calls
20
+ // (e.g. `new URL(request.url)`) never match.
21
+ const IMAGE_EXT = 'png|jpe?g|gif|webp|avif|svg|ico|bmp';
22
+ const newUrlAssetPattern = () =>
23
+ new RegExp(
24
+ `new\\s+URL\\(\\s*(['"])([^'"]+?\\.(?:${IMAGE_EXT})(?:[?#][^'"]*)?)\\1\\s*,\\s*import\\.meta\\.url\\s*\\)`,
25
+ 'g',
26
+ );
27
+
28
+ /** Cheap gate: does the source contain any candidate `new URL(...import.meta.url)`? */
29
+ export function sourceHasNewUrlAsset(source: string): boolean {
30
+ return source.includes('import.meta.url') && newUrlAssetPattern().test(source);
31
+ }
32
+
33
+ /**
34
+ * Rewrite `new URL('<image>', import.meta.url)` occurrences to the emitted
35
+ * static-image URL by threading them through the static-asset import pipeline.
36
+ * Returns the source unchanged when there is nothing to rewrite.
37
+ */
38
+ export function rewriteNewUrlAssetSource(source: string, filePath?: string): string {
39
+ const rewritten = rewriteReactProfilerServerSource(source, filePath);
40
+ return rewriteNewUrlAssets(
41
+ rewritten,
42
+ typeof filePath === 'string' && filePath.includes('middleware'),
43
+ );
44
+ }
45
+
46
+ /**
47
+ * Client-graph variant: no middleware form (a browser module never runs on the edge, and a client file
48
+ * merely living under an `app/middleware/...` path must not get the blob: rewrite) and no Profiler pass
49
+ * - that one is registered as its own client transform.
50
+ */
51
+ export function rewriteNewUrlAssetClientSource(source: string): string {
52
+ return rewriteNewUrlAssets(source, false);
53
+ }
54
+
55
+ function rewriteNewUrlAssets(source: string, isMiddleware: boolean): string {
56
+ if (!source.includes('import.meta.url')) return source;
57
+ const bindings = new Map<string, string>();
58
+ const replaced = source.replace(newUrlAssetPattern(), (_match, _quote, spec: string) => {
59
+ let binding = bindings.get(spec);
60
+ if (!binding) {
61
+ binding = `__pnext_new_url_${bindings.size}`;
62
+ bindings.set(spec, binding);
63
+ }
64
+ if (isMiddleware) {
65
+ return `('blob:' + ${binding}.src.split('/').pop())`;
66
+ }
67
+ return `(${binding}.src)`;
68
+ });
69
+ if (bindings.size === 0) return source;
70
+ const imports = [...bindings]
71
+ .map(([spec, binding]) => `import ${binding} from ${JSON.stringify(spec)};`)
72
+ .join('\n');
73
+ return injectAfterDirectives(replaced, imports);
74
+ }
75
+
76
+ // Insert injected imports after any leading directive prologue ('use client' /
77
+ // 'use server' / 'use strict') and optional shebang, so a client module's
78
+ // `'use client'` stays the first statement (otherwise the directive is demoted
79
+ // to a plain expression and the module is treated as server-only).
80
+ function injectAfterDirectives(source: string, injection: string): string {
81
+ const prologue = /^(\uFEFF?(?:#![^\n]*\n)?(?:[ \t]*(['"])use [\w-]+\2[ \t]*;?[ \t]*(?:\r?\n|$))*)/.exec(
82
+ source,
83
+ );
84
+ const index = prologue ? prologue[0].length : 0;
85
+ return `${source.slice(0, index)}${injection}\n${source.slice(index)}`;
86
+ }
87
+