@wular/pnext 0.1.5 → 0.1.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 (302) hide show
  1. package/bin/pnext +9 -2
  2. package/dist/server/_chunks/aliases-j47a10ce.js +44 -0
  3. package/dist/server/_chunks/analyze-arswqe6s.js +445 -0
  4. package/dist/server/_chunks/boot-af0mv3dy.js +36 -0
  5. package/dist/server/_chunks/build-spy3dxp4.js +84 -0
  6. package/dist/server/_chunks/build-t9h0hec3.js +3550 -0
  7. package/dist/server/_chunks/build-tier-m7yvqz61.js +2472 -0
  8. package/dist/server/_chunks/compile-53j02j27.js +22 -0
  9. package/dist/server/_chunks/config-1yzwexq6.js +27 -0
  10. package/dist/server/_chunks/config-n2z7yxps.js +22 -0
  11. package/dist/server/_chunks/create-meec9hs6.js +134 -0
  12. package/dist/server/_chunks/dev-fjmqg6en.js +220 -0
  13. package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
  14. package/dist/server/_chunks/generate-n9sh6hzt.js +21 -0
  15. package/dist/server/_chunks/index-0374j2b9.js +66 -0
  16. package/dist/server/_chunks/index-06nyqntx.js +213 -0
  17. package/dist/server/_chunks/index-1011cscr.js +5263 -0
  18. package/dist/server/_chunks/index-11sfk4hb.js +170 -0
  19. package/dist/server/_chunks/index-20ppawv7.js +297 -0
  20. package/dist/server/_chunks/index-2dv4y4wd.js +1065 -0
  21. package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
  22. package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
  23. package/dist/server/_chunks/index-357na4a8.js +109 -0
  24. package/dist/server/_chunks/index-3b3at80h.js +109 -0
  25. package/dist/server/_chunks/index-3tf1xjsp.js +6166 -0
  26. package/dist/server/_chunks/index-3xbr4eyv.js +105 -0
  27. package/dist/server/_chunks/index-4399bvd2.js +18 -0
  28. package/dist/server/_chunks/index-4hgjrqh7.js +851 -0
  29. package/dist/server/_chunks/index-4q2gbfwk.js +2530 -0
  30. package/dist/server/_chunks/index-4t92hdxd.js +172 -0
  31. package/dist/server/_chunks/index-4zzebszd.js +10 -0
  32. package/dist/server/_chunks/index-5gyr4emz.js +107 -0
  33. package/dist/server/_chunks/index-5hr4062s.js +70 -0
  34. package/dist/server/_chunks/index-68m3mwbd.js +84 -0
  35. package/dist/server/_chunks/index-6b009mt0.js +56 -0
  36. package/dist/server/_chunks/index-6e4fqv30.js +588 -0
  37. package/dist/server/_chunks/index-6gex3pfa.js +15 -0
  38. package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
  39. package/dist/server/_chunks/index-6q7zvrap.js +134 -0
  40. package/dist/server/_chunks/index-73z4esab.js +38 -0
  41. package/dist/server/_chunks/index-79ngvam8.js +60 -0
  42. package/dist/server/_chunks/index-7wc9n8be.js +25 -0
  43. package/dist/server/_chunks/index-8k7pfejn.js +1599 -0
  44. package/dist/server/_chunks/index-8kcxdfya.js +206 -0
  45. package/dist/server/_chunks/index-91x12ykq.js +274 -0
  46. package/dist/server/_chunks/index-9ch50vtq.js +18 -0
  47. package/dist/server/_chunks/index-9hx2641q.js +28 -0
  48. package/dist/server/_chunks/index-9n2914ww.js +535 -0
  49. package/dist/server/_chunks/index-9ych9ma8.js +207 -0
  50. package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
  51. package/dist/server/_chunks/index-bcws5eh2.js +35 -0
  52. package/dist/server/_chunks/index-c0g2wf3z.js +92 -0
  53. package/dist/server/_chunks/index-cf4rvxv6.js +95 -0
  54. package/dist/server/_chunks/index-cjgqs13g.js +65 -0
  55. package/dist/server/_chunks/index-ckkdpht5.js +41 -0
  56. package/dist/server/_chunks/index-cyfednwb.js +87 -0
  57. package/dist/server/_chunks/index-danncfhy.js +311 -0
  58. package/dist/server/_chunks/index-dg0f05zs.js +199 -0
  59. package/dist/server/_chunks/index-e3a6yx84.js +18 -0
  60. package/dist/server/_chunks/index-e88tyv35.js +45 -0
  61. package/dist/server/_chunks/index-eajaspjk.js +1253 -0
  62. package/dist/server/_chunks/index-eeaanp2e.js +483 -0
  63. package/dist/server/_chunks/index-egykcqg3.js +101 -0
  64. package/dist/server/_chunks/index-en7n9f7m.js +22 -0
  65. package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
  66. package/dist/server/_chunks/index-fkp000p1.js +590 -0
  67. package/dist/server/_chunks/index-fn1chkkd.js +214 -0
  68. package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
  69. package/dist/server/_chunks/index-ggk2j965.js +9432 -0
  70. package/dist/server/_chunks/index-grta8ap3.js +238 -0
  71. package/dist/server/_chunks/index-h2a70tg4.js +7 -0
  72. package/dist/server/_chunks/index-h4xy648y.js +51 -0
  73. package/dist/server/_chunks/index-hkdfj58q.js +92 -0
  74. package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
  75. package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
  76. package/dist/server/_chunks/index-jepjvcrf.js +198 -0
  77. package/dist/server/_chunks/index-jks0x0a1.js +14 -0
  78. package/dist/server/_chunks/index-jx7bqvw1.js +57 -0
  79. package/dist/server/_chunks/index-k1g3epw0.js +1299 -0
  80. package/dist/server/_chunks/index-knp0s912.js +7 -0
  81. package/dist/server/_chunks/index-kq8kpzye.js +472 -0
  82. package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
  83. package/dist/server/_chunks/index-kresp2n8.js +445 -0
  84. package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
  85. package/dist/server/_chunks/index-n4hxpng2.js +11 -0
  86. package/dist/server/_chunks/index-ncnes8c6.js +17 -0
  87. package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
  88. package/dist/server/_chunks/index-nyrba2kr.js +4130 -0
  89. package/dist/server/_chunks/index-p77b4kcx.js +296 -0
  90. package/dist/server/_chunks/index-pym1cezq.js +39 -0
  91. package/dist/server/_chunks/index-q738kkhj.js +100 -0
  92. package/dist/server/_chunks/index-qjj6gddn.js +54 -0
  93. package/dist/server/_chunks/index-qm6kmhqs.js +110 -0
  94. package/dist/server/_chunks/index-qn4z5s3c.js +819 -0
  95. package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
  96. package/dist/server/_chunks/index-r97ptz1q.js +97 -0
  97. package/dist/server/_chunks/index-ras0sdab.js +26 -0
  98. package/dist/server/_chunks/index-rcs322t1.js +19 -0
  99. package/dist/server/_chunks/index-rn8dyr1f.js +126 -0
  100. package/dist/server/_chunks/index-rt9qq1va.js +4 -0
  101. package/dist/server/_chunks/index-rthrsed5.js +356 -0
  102. package/dist/server/_chunks/index-sctcgyvv.js +185 -0
  103. package/dist/server/_chunks/index-sjpckxqn.js +213 -0
  104. package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
  105. package/dist/server/_chunks/index-stbk3jhn.js +31 -0
  106. package/dist/server/_chunks/index-sv8m6789.js +266 -0
  107. package/dist/server/_chunks/index-tgcakdxc.js +125 -0
  108. package/dist/server/_chunks/index-tgsfjmep.js +74 -0
  109. package/dist/server/_chunks/index-tq0pc7eg.js +154 -0
  110. package/dist/server/_chunks/index-tq1f96v7.js +51 -0
  111. package/dist/server/_chunks/index-tqn2qnnn.js +241 -0
  112. package/dist/server/_chunks/index-tvqkq6e6.js +128 -0
  113. package/dist/server/_chunks/index-v1ags1na.js +132 -0
  114. package/dist/server/_chunks/index-vvmmknm1.js +1431 -0
  115. package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
  116. package/dist/server/_chunks/index-vz0km5qk.js +33 -0
  117. package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
  118. package/dist/server/_chunks/index-web361b8.js +138 -0
  119. package/dist/server/_chunks/index-wpfhfbs4.js +194 -0
  120. package/dist/server/_chunks/index-x0y005nh.js +283 -0
  121. package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
  122. package/dist/server/_chunks/index-x93hv0sc.js +271 -0
  123. package/dist/server/_chunks/index-xvj80c3a.js +30 -0
  124. package/dist/server/_chunks/index-xywjg2vc.js +100 -0
  125. package/dist/server/_chunks/index-y2jr2n72.js +152 -0
  126. package/dist/server/_chunks/index-y36a0ybw.js +57 -0
  127. package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
  128. package/dist/server/_chunks/index-yhxkxghe.js +56 -0
  129. package/dist/server/_chunks/index-ym67zqxp.js +130 -0
  130. package/dist/server/_chunks/index-ytjvpbm2.js +736 -0
  131. package/dist/server/_chunks/index-yz54pxrh.js +960 -0
  132. package/dist/server/_chunks/index-z4z9zv3b.js +733 -0
  133. package/dist/server/_chunks/index-z84ab1w0.js +1270 -0
  134. package/dist/server/_chunks/index-z88qv16t.js +11 -0
  135. package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
  136. package/dist/server/_chunks/loader-7yw0j98z.js +78 -0
  137. package/dist/server/_chunks/modules-jn8bmbn8.js +74 -0
  138. package/dist/server/_chunks/pipeline-yy9jhydf.js +832 -0
  139. package/dist/server/_chunks/production-jar9ztm3.js +44 -0
  140. package/dist/server/_chunks/proxy-config-j84dgksn.js +21 -0
  141. package/dist/server/_chunks/proxy-w1d0wmsn.js +33 -0
  142. package/dist/server/_chunks/router-k1reahfn.js +498 -0
  143. package/dist/server/_chunks/routes-2s277fc6.js +64 -0
  144. package/dist/server/_chunks/run-pvd8bs1t.js +696 -0
  145. package/dist/server/_chunks/server-mt4a994c.js +1835 -0
  146. package/dist/server/_chunks/tsconfig-defaults-1nb3308g.js +20 -0
  147. package/dist/server/_chunks/typegen-0qr0459b.js +35 -0
  148. package/dist/server/api/client-cache.js +14 -0
  149. package/dist/server/cli/index.js +378 -0
  150. package/dist/server/cli/start.js +137 -0
  151. package/dist/server/client/reference.js +16 -0
  152. package/dist/server/compat/next/cache.js +56 -0
  153. package/dist/server/compat/next/canonical-url.js +13 -0
  154. package/dist/server/compat/next/client-cache.js +57 -0
  155. package/dist/server/compat/next/client-navigation.js +232 -0
  156. package/dist/server/compat/next/client-only.js +1 -0
  157. package/dist/server/compat/next/client-script.js +178 -0
  158. package/dist/server/compat/next/client-server.js +34 -0
  159. package/dist/server/compat/next/config-headers.js +32 -0
  160. package/dist/server/compat/next/config-loader.js +25 -0
  161. package/dist/server/compat/next/config.js +10 -0
  162. package/dist/server/compat/next/constants.js +18 -0
  163. package/dist/server/compat/next/custom-server.js +10 -0
  164. package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
  165. package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
  166. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
  167. package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
  168. package/dist/server/compat/next/dynamic.js +32 -0
  169. package/dist/server/compat/next/error.js +112 -0
  170. package/dist/server/compat/next/font/cache.js +14 -0
  171. package/dist/server/compat/next/font/google.js +3 -0
  172. package/dist/server/compat/next/font/index.js +1 -0
  173. package/dist/server/compat/next/font/local.js +22 -0
  174. package/dist/server/compat/next/font/runtime-client.js +33 -0
  175. package/dist/server/compat/next/font/runtime.js +41 -0
  176. package/dist/server/compat/next/font/shared.js +22 -0
  177. package/dist/server/compat/next/form.js +129 -0
  178. package/dist/server/compat/next/head.js +10 -0
  179. package/dist/server/compat/next/headers.js +30 -0
  180. package/dist/server/compat/next/image/client.js +11 -0
  181. package/dist/server/compat/next/image/config.js +18 -0
  182. package/dist/server/compat/next/image/optimizer.js +25 -0
  183. package/dist/server/compat/next/image/patterns.js +12 -0
  184. package/dist/server/compat/next/image/props.js +16 -0
  185. package/dist/server/compat/next/image/shared.js +86 -0
  186. package/dist/server/compat/next/image/static-metadata.js +32 -0
  187. package/dist/server/compat/next/image/validate.js +8 -0
  188. package/dist/server/compat/next/image.js +59 -0
  189. package/dist/server/compat/next/index.js +1 -0
  190. package/dist/server/compat/next/legacy-image.js +78 -0
  191. package/dist/server/compat/next/legacy-request-apis.js +24 -0
  192. package/dist/server/compat/next/link-transform.js +14 -0
  193. package/dist/server/compat/next/link.js +14 -0
  194. package/dist/server/compat/next/navigation.js +190 -0
  195. package/dist/server/compat/next/offline.js +45 -0
  196. package/dist/server/compat/next/og.js +8 -0
  197. package/dist/server/compat/next/preferred-region.js +8 -0
  198. package/dist/server/compat/next/redirects.js +30 -0
  199. package/dist/server/compat/next/resource-hints.js +30 -0
  200. package/dist/server/compat/next/rewrites.js +41 -0
  201. package/dist/server/compat/next/root-params.js +121 -0
  202. package/dist/server/compat/next/route-state.js +23 -0
  203. package/dist/server/compat/next/router.js +103 -0
  204. package/dist/server/compat/next/script.js +37 -0
  205. package/dist/server/compat/next/server-only.js +1 -0
  206. package/dist/server/compat/next/server.js +131 -0
  207. package/dist/server/compat/next/svgr.js +14 -0
  208. package/dist/server/compat/next/telemetry.js +10 -0
  209. package/dist/server/compat/next/usage.js +13 -0
  210. package/dist/server/compat/next/user-agent.js +12 -0
  211. package/dist/server/compat/next/web-vitals.js +35 -0
  212. package/dist/server/compat/react/action-state.js +11 -0
  213. package/dist/server/compat/react/client-lite.js +83 -0
  214. package/dist/server/compat/react/client.js +131 -0
  215. package/dist/server/compat/react/compiler-runtime.js +42 -0
  216. package/dist/server/compat/react/dom-client.js +106 -0
  217. package/dist/server/compat/react/dom-react-server.js +37 -0
  218. package/dist/server/compat/react/dom-server.js +40 -0
  219. package/dist/server/compat/react/dom.js +52 -0
  220. package/dist/server/compat/react/hooks-extra.js +12 -0
  221. package/dist/server/compat/react/internals.js +14 -0
  222. package/dist/server/compat/react/parity.js +11 -0
  223. package/dist/server/compat/react/preact.js +113 -0
  224. package/dist/server/compat/react/react-server.js +133 -0
  225. package/dist/server/compat/react/router-shim.js +8 -0
  226. package/dist/server/compat/react/server-component-use.js +14 -0
  227. package/dist/server/compat/react/server-inserted-html.js +14 -0
  228. package/dist/server/compat/react/server.js +194 -0
  229. package/dist/server/compat/react/style-values.js +10 -0
  230. package/dist/server/compat/react/use.js +10 -0
  231. package/dist/server/compat/react/view-transition.js +12 -0
  232. package/dist/server/generation.json +1 -0
  233. package/package.json +4 -1
  234. package/src/api/dynamic.tsx +2 -0
  235. package/src/api/server.ts +24 -6
  236. package/src/cli/adapters/vercel-warm.ts +315 -61
  237. package/src/cli/adapters/vercel.ts +348 -71
  238. package/src/cli/build.ts +58 -33
  239. package/src/cli/index.ts +23 -10
  240. package/src/cli/serve/entry.ts +21 -159
  241. package/src/cli/serve/immutable.ts +31 -0
  242. package/src/cli/serve/pipeline.ts +82 -84
  243. package/src/cli/start.ts +3 -1
  244. package/src/client/chunk-fold.ts +19 -6
  245. package/src/client/react-tier.ts +3 -2
  246. package/src/client/reference-stub.ts +21 -2
  247. package/src/compat/actions/client-plugin.ts +4 -2
  248. package/src/compat/actions/config.ts +6 -5
  249. package/src/compat/actions/extensions.ts +2 -3
  250. package/src/compat/aliases.ts +8 -1
  251. package/src/compat/bundler/config.ts +88 -0
  252. package/src/compat/bundler/optimize-package-imports.ts +86 -26
  253. package/src/compat/bundler/relay-transform.ts +15 -3
  254. package/src/compat/cache-control.ts +16 -8
  255. package/src/compat/css/modules.ts +18 -5
  256. package/src/compat/lifecycle/error-funnel.ts +1 -1
  257. package/src/compat/lifecycle/instrumentation.ts +117 -24
  258. package/src/compat/lifecycle/testmode.ts +3 -2
  259. package/src/compat/next/config-loader.ts +137 -13
  260. package/src/compat/next/font/runtime.ts +22 -2
  261. package/src/compat/next/og.ts +3 -3
  262. package/src/compat/next/usage.ts +3 -2
  263. package/src/compat/pages/api.ts +83 -14
  264. package/src/compat/pages/router.ts +30 -14
  265. package/src/compat/register/bundler.ts +3 -1
  266. package/src/compat/register/middleware.ts +1 -1
  267. package/src/compat/register/otel.ts +5 -9
  268. package/src/compat/register/render.ts +3 -1
  269. package/src/compat/register/use-cache.ts +3 -1
  270. package/src/compat/release.ts +46 -0
  271. package/src/compat/segment/serve.ts +1 -1
  272. package/src/compat/validation/validate.ts +10 -7
  273. package/src/config.ts +51 -7
  274. package/src/css/assets.ts +213 -0
  275. package/src/css/build.ts +174 -238
  276. package/src/dev/server.ts +27 -8
  277. package/src/extensions.ts +4 -0
  278. package/src/render/hooks.ts +13 -0
  279. package/src/render/renderer.ts +52 -32
  280. package/src/request/context.ts +9 -0
  281. package/src/resolve/dynamic.ts +3 -1
  282. package/src/resolve/imports.ts +12 -52
  283. package/src/resolve/package-json.ts +56 -0
  284. package/src/resolve/scan-facts.ts +65 -0
  285. package/src/routing/href.ts +10 -3
  286. package/src/routing/match.ts +287 -0
  287. package/src/routing/metadata-files.ts +19 -5
  288. package/src/routing/proxy-config.ts +137 -0
  289. package/src/routing/proxy.ts +35 -134
  290. package/src/routing/routes.ts +22 -281
  291. package/src/runtime/fingerprint.ts +23 -8
  292. package/src/runtime/load.ts +170 -0
  293. package/src/runtime/loader.ts +215 -43
  294. package/src/runtime/module-cache.ts +13 -0
  295. package/src/runtime/modules.ts +370 -81
  296. package/src/runtime/prebundle.ts +81 -0
  297. package/src/runtime/production.ts +391 -0
  298. package/src/runtime/release-graph.ts +334 -0
  299. package/src/runtime/vendor-build.ts +724 -13
  300. package/src/runtime/vendor.ts +16 -3
  301. package/src/types.ts +2 -0
  302. package/src/utils/fs.ts +89 -3
@@ -0,0 +1,81 @@
1
+ // The published package runs production from dist/server (scripts/prebundle.ts). There, app imports
2
+ // of framework source resolve to the same prebundled modules, so the process holds one instance of
3
+ // each registry. A source checkout has no prebundle and resolves source as before.
4
+ import { readFileSync } from 'node:fs'
5
+ import path from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ /** Source modules production can import: the start entry and everything app code reaches at runtime. */
9
+ export const runtimeEntryFiles = ['cli/start.ts', 'index.ts', 'internal.ts', 'client/reference.ts']
10
+ export const runtimeEntryDirs = ['api', 'compat/next', 'compat/react']
11
+
12
+ /** Written last by the prebundle: dist is complete, and built from this version and source. */
13
+ export const PREBUNDLE_STAMP = path.join('dist', 'server', 'generation.json')
14
+
15
+ export interface PrebundleStamp {
16
+ version: string
17
+ fingerprint: string
18
+ /** Package-relative sources dist imports rather than inlines: the public API closure. */
19
+ source: string[]
20
+ }
21
+
22
+ declare const PNEXT_PREBUNDLE:
23
+ { version: string; fingerprint: string; entries: string[] } | undefined
24
+
25
+ const prebundle = typeof PNEXT_PREBUNDLE === 'object' ? PNEXT_PREBUNDLE : undefined
26
+ const packageRoot = path.resolve(import.meta.dirname, '..', '..')
27
+ const srcRoot = path.join(packageRoot, 'src') + path.sep
28
+ const distRoot = path.join(packageRoot, 'dist', 'server')
29
+ const entries = new Set(prebundle?.entries)
30
+
31
+ function packageVersion(root: string) {
32
+ return (JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8')) as { version?: string })
33
+ .version
34
+ }
35
+
36
+ /** The framework's prebundle stamp when its dist is complete and built from `fingerprint`'s source. */
37
+ export function readPrebundleStamp(frameworkRoot: string, fingerprint: string) {
38
+ let stamp: PrebundleStamp
39
+ try {
40
+ stamp = JSON.parse(
41
+ readFileSync(path.join(frameworkRoot, PREBUNDLE_STAMP), 'utf8'),
42
+ ) as PrebundleStamp
43
+ } catch {
44
+ return undefined
45
+ }
46
+ return stamp.fingerprint === fingerprint && stamp.version === packageVersion(frameworkRoot)
47
+ ? stamp
48
+ : undefined
49
+ }
50
+
51
+ /** The prebundled counterpart of a framework source module, else `file` unchanged. */
52
+ export function prebundledFile(file: string): string {
53
+ if (!prebundle || !file.startsWith(srcRoot)) return file
54
+ const entry = file.slice(srcRoot.length).replace(/\.tsx?$/, '')
55
+ return entries.has(entry) ? path.join(distRoot, `${entry}.js`) : file
56
+ }
57
+
58
+ let registered = false
59
+
60
+ /** Route imports of framework source, by path, to the prebundle. */
61
+ export function registerPrebundleResolve(): void {
62
+ if (!prebundle || registered) return
63
+ registered = true
64
+ const escaped = srcRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
65
+ Bun.plugin({
66
+ name: 'pnext-prebundle',
67
+ setup(build) {
68
+ build.onResolve({ filter: new RegExp(`^(?:file://)?${escaped}.*\\.tsx?$`) }, args => {
69
+ const file = args.path.startsWith('file:') ? fileURLToPath(args.path) : args.path
70
+ const target = prebundledFile(file)
71
+ return target === file ? undefined : { path: target }
72
+ })
73
+ // Compiled artifacts name framework modules by relative path.
74
+ build.onResolve({ filter: /^\.\.?\/.*\/src\/.*\.tsx?$/ }, args => {
75
+ const file = path.resolve(path.dirname(args.importer), args.path)
76
+ const target = prebundledFile(file)
77
+ return target === file ? undefined : { path: target }
78
+ })
79
+ },
80
+ })
81
+ }
@@ -0,0 +1,391 @@
1
+ /**
2
+ * The release a production server runs from: compiled server artifacts plus the source facts the
3
+ * build froze. A served request never reads, stats or hashes app source or config, and never
4
+ * compiles; everything it imports is named here. Dev and the build itself keep their own loaders.
5
+ */
6
+ import { type Dirent, existsSync, readFileSync, readdirSync } from 'node:fs'
7
+ import { mkdir, rename, rm, writeFile } from 'node:fs/promises'
8
+ import path from 'node:path'
9
+ import { pathToFileURL } from 'node:url'
10
+ import type { ResolvedConfig } from '../config'
11
+ import type { ReleasedFont } from '../render/hooks'
12
+ import type { StaticMetadataFile } from '../routing/metadata-files'
13
+
14
+ export const BUILD_INDEX_VERSION = 1
15
+ const LOCATOR_FILE = 'release-locator.json'
16
+
17
+ /** `server` is the RSC/server layer, `client` the SSR copy of client components. */
18
+ export type ReleaseLayer = 'server' | 'client'
19
+
20
+ /** What the build writes. Paths are relative (to the root, or to the out dir for artifacts). */
21
+ export interface BuildIndex {
22
+ version: number
23
+ /** The framework fingerprint the build compiled with. */
24
+ framework?: string
25
+ config: Record<string, unknown>
26
+ /** The compiled next.config, out-relative. */
27
+ nextConfig?: string
28
+ /** `<layer>:<target>:<releaseSourceKey>` -> artifact. */
29
+ modules: Record<string, string>
30
+ /** App directory -> the convention files and `@slot`/group directories it holds. */
31
+ conventions: Record<string, string[]>
32
+ /** Convention files carrying `'use client'`. */
33
+ clientConventions: string[]
34
+ /** Root layouts that export a default component. */
35
+ documentLayouts: string[]
36
+ /** The root layout's global stylesheet closure, in order. */
37
+ globalCss: string[]
38
+ /** The proxy source and its literal `config` export, when the app has one. */
39
+ proxy?: { file: string; config?: unknown }
40
+ /** Font resolutions by declaration key, files out-relative. */
41
+ fonts?: Record<string, ReleasedFont>
42
+ /** Prebuilt instrumentation instances, out-relative. */
43
+ instrumentation?: { file: string; edge?: string }
44
+ /** App facts compat reads at boot: root param names, pages revalidate windows. */
45
+ compat?: CompatReleaseFacts
46
+ /** The App Router layers' linked server dependency graphs, out-relative. */
47
+ dependencies?: string[]
48
+ }
49
+
50
+ /** What compat contributes to a release. */
51
+ export type CompatRelease = Pick<BuildIndex, 'nextConfig' | 'instrumentation' | 'compat'>
52
+
53
+ export interface CompatReleaseFacts {
54
+ rootParams: string[]
55
+ pagesRevalidate: [string, number][]
56
+ /** Pages API sources (root-relative) and their runtime. */
57
+ pagesApi: Record<string, string>
58
+ /** Compiled cache handlers by role, out-relative. */
59
+ cacheHandlers: Record<string, string>
60
+ /** Materialized pages-router route wrappers, root-relative. */
61
+ pagesRoutes: string[]
62
+ }
63
+
64
+ /** The loaded release, resolved against where it is served from. */
65
+ export interface Release {
66
+ /** `<layer>:<target>:<absolute source>` -> file href. */
67
+ modules: Map<string, string>
68
+ conventions: ConventionFacts
69
+ globalCss: string[]
70
+ proxy: { file?: string; config?: unknown }
71
+ instrumentation?: { file: string; edge?: string }
72
+ compat?: CompatReleaseFacts
73
+ /** Font resolutions by declaration key, files absolute. */
74
+ fonts?: Record<string, ReleasedFont>
75
+ /** The build's static metadata files; the serving pipeline publishes them from its manifest. */
76
+ staticMetadataFiles?: StaticMetadataFile[]
77
+ }
78
+
79
+ export interface ConventionFacts {
80
+ appPath: string
81
+ /** Absolute app directory -> its convention files and child directories. */
82
+ dirs: Map<string, { files: Set<string>; dirs: string[] }>
83
+ client: ReadonlySet<string>
84
+ documentLayouts: ReadonlySet<string>
85
+ }
86
+
87
+ const releases = new WeakMap<object, Release>()
88
+ const WORK_UNIT_STORAGE = Symbol.for('pnext.workUnitStorage')
89
+
90
+ export function buildIndexFile(outPath: string) {
91
+ return path.join(outPath, 'server', 'build-index.json')
92
+ }
93
+
94
+ export function releaseModuleKey(layer: ReleaseLayer, target: string, file: string) {
95
+ return `${layer}:${target}:${file}`
96
+ }
97
+
98
+ /** The release `config` serves from; undefined for dev and for the build itself. */
99
+ export function productionRelease(config: object): Release | undefined {
100
+ return releases.get(config)
101
+ }
102
+
103
+ /** The release the current request's work unit serves, if any (request/context owns the store). */
104
+ export function servedRelease(): Release | undefined {
105
+ const units = (globalThis as Record<PropertyKey, unknown>)[WORK_UNIT_STORAGE] as
106
+ { getStore(): { release?: Release } | undefined } | undefined
107
+ return units?.getStore()?.release
108
+ }
109
+
110
+ /** The frozen app-directory facts of the release this work serves, if any. */
111
+ export function servedConventions(): ConventionFacts | undefined {
112
+ return servedRelease()?.conventions
113
+ }
114
+
115
+ /** A frozen listing for `dir` when it lies in the served app; undefined defers to the disk. */
116
+ export function frozenDirListing(dir: string) {
117
+ const facts = servedConventions()
118
+ if (!facts || !isInsideDir(facts.appPath, dir)) return undefined
119
+ return facts.dirs.get(dir) ?? { files: new Set<string>(), dirs: [] }
120
+ }
121
+
122
+ /** Whether a convention file exists: the frozen fact in production, the disk otherwise. */
123
+ export function conventionFileExists(file: string) {
124
+ return frozenDirListing(path.dirname(file))?.files.has(path.basename(file)) ?? existsSync(file)
125
+ }
126
+
127
+ /** The compiled artifact for `file`; a module the build did not compile is a build bug, never a compile. */
128
+ export function releaseModuleHref(
129
+ release: Release,
130
+ layer: ReleaseLayer,
131
+ target: string,
132
+ file: string,
133
+ ) {
134
+ const href = release.modules.get(releaseModuleKey(layer, target, path.resolve(file)))
135
+ if (!href) {
136
+ throw new Error(
137
+ `pnext: ${file} (${layer}, ${target}) is not in this build's release. Run 'pnext build' again.`,
138
+ )
139
+ }
140
+ return href
141
+ }
142
+
143
+ /** Read `<outPath>/server/build-index.json` and attach it to `config`. */
144
+ export function attachRelease(config: ResolvedConfig, index = readBuildIndex(config.outPath)) {
145
+ const existing = releases.get(config)
146
+ if (existing) return existing
147
+ const fromRoot = (file: string) => path.resolve(config.root, file)
148
+ const modules = new Map<string, string>()
149
+ for (const [key, artifact] of Object.entries(index.modules)) {
150
+ const second = key.indexOf(':', key.indexOf(':') + 1)
151
+ modules.set(
152
+ `${key.slice(0, second + 1)}${releaseSourceFile(key.slice(second + 1), config.root, config.workspaceRoot)}`,
153
+ pathToFileURL(path.resolve(config.outPath, artifact)).href,
154
+ )
155
+ }
156
+ const dirs = new Map<string, { files: Set<string>; dirs: string[] }>()
157
+ for (const [dir, names] of Object.entries(index.conventions)) {
158
+ dirs.set(fromRoot(dir), {
159
+ files: new Set(names.filter(name => !name.endsWith('/'))),
160
+ dirs: names.filter(name => name.endsWith('/')).map(name => name.slice(0, -1)),
161
+ })
162
+ }
163
+ const release: Release = {
164
+ modules,
165
+ conventions: {
166
+ appPath: config.appPath,
167
+ dirs,
168
+ client: new Set(index.clientConventions.map(fromRoot)),
169
+ documentLayouts: new Set(index.documentLayouts.map(fromRoot)),
170
+ },
171
+ globalCss: index.globalCss.map(fromRoot),
172
+ proxy: index.proxy ? { ...index.proxy, file: fromRoot(index.proxy.file) } : {},
173
+ ...(index.compat ? { compat: index.compat } : {}),
174
+ ...(index.instrumentation
175
+ ? {
176
+ instrumentation: {
177
+ file: path.resolve(config.outPath, index.instrumentation.file),
178
+ ...(index.instrumentation.edge
179
+ ? { edge: path.resolve(config.outPath, index.instrumentation.edge) }
180
+ : {}),
181
+ },
182
+ }
183
+ : {}),
184
+ ...(index.fonts
185
+ ? {
186
+ fonts: Object.fromEntries(
187
+ Object.entries(index.fonts).map(([key, font]) => [
188
+ key,
189
+ { ...font, files: font.files.map(file => path.resolve(config.outPath, file)) },
190
+ ]),
191
+ ),
192
+ }
193
+ : {}),
194
+ }
195
+ releases.set(config, release)
196
+ return release
197
+ }
198
+
199
+ const conventionBases = new Set([
200
+ 'page',
201
+ 'route',
202
+ 'layout',
203
+ 'template',
204
+ 'loading',
205
+ 'error',
206
+ 'not-found',
207
+ 'default',
208
+ 'forbidden',
209
+ 'unauthorized',
210
+ 'global-error',
211
+ 'global-not-found',
212
+ ])
213
+
214
+ const metadataBase =
215
+ /^(?:robots|sitemap|manifest|favicon|(?:apple-)?icon\d*|opengraph-image\d*|twitter-image\d*)$/
216
+ const codeFile = /\.(?:[cm]?[jt]sx?|mdx?)$/
217
+
218
+ function capturedFile(name: string) {
219
+ const base = /^[^.]+/.exec(name)?.[0] ?? name
220
+ return conventionBases.has(base) || metadataBase.test(base)
221
+ }
222
+
223
+ /** Every file of the served app's frozen tree: its convention and metadata files. */
224
+ export function servedAppFiles(facts: ConventionFacts) {
225
+ return [...facts.dirs].flatMap(([dir, listing]) =>
226
+ [...listing.files].map(name => path.join(dir, name)),
227
+ )
228
+ }
229
+
230
+ /** Every app directory with its convention/metadata files and child directories; `files` are the code ones. */
231
+ export function captureConventions(root: string, appPath: string) {
232
+ const conventions: Record<string, string[]> = {}
233
+ const files: string[] = []
234
+ const visit = (dir: string) => {
235
+ let entries: Dirent[]
236
+ try {
237
+ entries = readdirSync(dir, { withFileTypes: true })
238
+ } catch {
239
+ return
240
+ }
241
+ const names: string[] = []
242
+ for (const entry of entries) {
243
+ if (entry.isDirectory()) {
244
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue
245
+ names.push(`${entry.name}/`)
246
+ visit(path.join(dir, entry.name))
247
+ } else if (capturedFile(entry.name)) {
248
+ names.push(entry.name)
249
+ if (codeFile.test(entry.name)) files.push(path.join(dir, entry.name))
250
+ }
251
+ }
252
+ conventions[toPosix(path.relative(root, dir)) || '.'] = names.sort()
253
+ }
254
+ visit(appPath)
255
+ return { conventions, files }
256
+ }
257
+
258
+ // The framework's own package root: compat runtime modules compile like app sources but live here.
259
+ const frameworkRoot = path.resolve(import.meta.dirname, '..', '..')
260
+
261
+ /** A source's identity in the release: root-, workspace- or framework-relative, so a moved build still finds it. */
262
+ export function releaseSourceKey(file: string, root: string, workspaceRoot: string) {
263
+ const inRoot = path.relative(root, file)
264
+ if (!inRoot.startsWith('..') && !path.isAbsolute(inRoot)) return `r:${toPosix(inRoot)}`
265
+ const inWorkspace = path.relative(workspaceRoot, file)
266
+ if (!inWorkspace.startsWith('..') && !path.isAbsolute(inWorkspace))
267
+ return `w:${toPosix(inWorkspace)}`
268
+ const inFramework = path.relative(frameworkRoot, file)
269
+ if (!inFramework.startsWith('..') && !path.isAbsolute(inFramework))
270
+ return `f:${toPosix(inFramework)}`
271
+ // Outside every root (a pages app materialized in tmpdir): root-relative, resolved like the manifest.
272
+ return `r:${toPosix(inRoot)}`
273
+ }
274
+
275
+ export function releaseSourceFile(key: string, root: string, workspaceRoot: string) {
276
+ const value = key.slice(2)
277
+ if (key.startsWith('r:')) return path.join(root, value)
278
+ if (key.startsWith('w:')) return path.resolve(workspaceRoot, value)
279
+ if (key.startsWith('f:')) return path.resolve(frameworkRoot, value)
280
+ return path.join(root, value)
281
+ }
282
+
283
+ function toPosix(file: string) {
284
+ return file.split(path.sep).join('/')
285
+ }
286
+
287
+ function isInsideDir(root: string, file: string) {
288
+ return file === root || file.startsWith(`${root}${path.sep}`)
289
+ }
290
+
291
+ export function readBuildIndex(outPath: string): BuildIndex {
292
+ const file = buildIndexFile(outPath)
293
+ let index: BuildIndex
294
+ try {
295
+ index = JSON.parse(readFileSync(file, 'utf8')) as BuildIndex
296
+ } catch (error) {
297
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
298
+ throw new Error("No production build found. Run 'pnext build' first.")
299
+ }
300
+ if (index.version !== BUILD_INDEX_VERSION) {
301
+ throw new Error(`pnext: ${file} is from another pnext version. Run 'pnext build' again.`)
302
+ }
303
+ return index
304
+ }
305
+
306
+ /**
307
+ * Where a built root keeps its release: the dir its locator names when the latest build wrote outside
308
+ * the default out dir (a build into the default empties it, locator included), else the default.
309
+ * Undefined when the root holds no build.
310
+ */
311
+ export function locateRelease(root: string, defaultOutDir: string): string | undefined {
312
+ const outPath = path.join(root, defaultOutDir)
313
+ try {
314
+ const { outDir } = JSON.parse(readFileSync(path.join(outPath, LOCATOR_FILE), 'utf8')) as {
315
+ outDir: string
316
+ }
317
+ return path.resolve(root, outDir)
318
+ } catch {
319
+ return existsSync(buildIndexFile(outPath)) ? outPath : undefined
320
+ }
321
+ }
322
+
323
+ /** The resolved config as the build saw it, with paths made relative to the root. */
324
+ export function serializeReleaseConfig(config: ResolvedConfig): Record<string, unknown> {
325
+ const relative = (file: string) => path.relative(config.root, file) || '.'
326
+ return JSON.parse(
327
+ JSON.stringify(
328
+ {
329
+ ...config,
330
+ root: '.',
331
+ workspaceRoot: relative(config.workspaceRoot),
332
+ appPath: relative(config.appPath),
333
+ publicPath: relative(config.publicPath),
334
+ outPath: relative(config.outPath),
335
+ outRootPath: relative(config.outRootPath),
336
+ typesPath: relative(config.typesPath),
337
+ checksPath: relative(config.checksPath),
338
+ },
339
+ (_key, value: unknown) =>
340
+ value instanceof RegExp ? { $regexp: [value.source, value.flags] } : value,
341
+ ),
342
+ ) as Record<string, unknown>
343
+ }
344
+
345
+ /** The inverse of `serializeReleaseConfig`, for a release served from `root` out of `outPath`. */
346
+ export function releaseConfig(
347
+ serialized: Record<string, unknown>,
348
+ root: string,
349
+ outPath: string,
350
+ ): ResolvedConfig {
351
+ const config = JSON.parse(JSON.stringify(serialized), (_key, value: unknown) => {
352
+ const pattern = (value as { $regexp?: [string, string] } | null)?.$regexp
353
+ return pattern ? new RegExp(pattern[0], pattern[1]) : value
354
+ }) as ResolvedConfig
355
+ const fromRoot = (file: string) => path.resolve(root, file)
356
+ const fromOut = (file: string) => path.resolve(outPath, path.relative(config.outPath, file))
357
+ return {
358
+ ...config,
359
+ root,
360
+ workspaceRoot: fromRoot(config.workspaceRoot),
361
+ appPath: fromRoot(config.appPath),
362
+ publicPath: fromRoot(config.publicPath),
363
+ outPath,
364
+ outRootPath: fromOut(config.outRootPath),
365
+ typesPath: fromOut(config.typesPath),
366
+ checksPath: fromOut(config.checksPath),
367
+ }
368
+ }
369
+
370
+ /** Publish the build index last, atomically, plus a locator when the out dir is not the default. */
371
+ export async function writeBuildIndex(
372
+ config: ResolvedConfig,
373
+ index: BuildIndex,
374
+ defaultOutDir: string,
375
+ ) {
376
+ const file = buildIndexFile(config.outPath)
377
+ const temporary = `${file}.${process.pid}.tmp`
378
+ await writeFile(temporary, JSON.stringify(index))
379
+ await rename(temporary, file)
380
+ const defaultOut = path.join(config.root, defaultOutDir)
381
+ if (path.resolve(config.outPath) === path.resolve(defaultOut)) return
382
+ await mkdir(defaultOut, { recursive: true })
383
+ const locator = path.join(defaultOut, LOCATOR_FILE)
384
+ await writeFile(
385
+ `${locator}.${process.pid}.tmp`,
386
+ JSON.stringify({ outDir: path.relative(config.root, config.outPath) }),
387
+ )
388
+ await rename(`${locator}.${process.pid}.tmp`, locator)
389
+ // A default-out release left by an earlier build is now stale: the locator already outranks it.
390
+ await rm(buildIndexFile(defaultOut), { force: true })
391
+ }