@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
@@ -14,6 +14,7 @@
14
14
  // lazy-static MISS responses. Emitting it for pure static HITs needs the route's cacheLife persisted in
15
15
  // the build manifest and read by the static-serve path in src/cli/start.ts.
16
16
 
17
+ import { productionRelease } from '../../runtime/production'
17
18
  import type { ResolvedConfig } from '../../config'
18
19
  import { nextCompatEnabled } from '../../compat/aliases'
19
20
  import {
@@ -84,7 +85,8 @@ export function registerUseCacheExtensions(config: ResolvedConfig): void {
84
85
  // Seed the root-param NAME set for cache-key participation (Stage B-3): a
85
86
  // `use cache` entry's conservative first-call key may only discriminate by
86
87
  // root params, so the runtime needs the scanned names at build AND serve.
87
- setUseCacheRootParamNames(scanRootParams(config.appPath))
88
+ const released = productionRelease(config)?.compat?.rootParams
89
+ setUseCacheRootParamNames(released ? new Set(released) : scanRootParams(config.appPath))
88
90
 
89
91
  // Arm `use cache` build-time validation for this build's prerender pass.
90
92
  // Registered as a build STEP so it runs before any page is prerendered; the
@@ -0,0 +1,46 @@
1
+ // Compat facts a production release carries (COMPAT): compiled next.config, cache handlers and
2
+ // instrumentation, plus the app facts compat would otherwise rescan from source at boot.
3
+ import path from 'node:path'
4
+ import type { ResolvedConfig } from '../config'
5
+ import type { CompatRelease } from '../runtime/production'
6
+ import { pagesRevalidateFacts } from './cache-control'
7
+ import { emitReleaseInstrumentation } from './lifecycle/instrumentation'
8
+ import { emitNextConfigBundle } from './next/config-loader'
9
+ import { pagesApiFacts, pagesRouteFacts } from './pages/api'
10
+ import { scanRootParams } from './ppr/root-params-scan'
11
+
12
+ export async function compatReleaseFacts(
13
+ config: ResolvedConfig,
14
+ outDir: string,
15
+ ): Promise<CompatRelease> {
16
+ const [nextConfig, instrumentation] = await Promise.all([
17
+ emitNextConfigBundle(config.root, outDir),
18
+ emitReleaseInstrumentation(config, outDir),
19
+ ])
20
+ const toPosix = (file: string) => file.split(path.sep).join('/')
21
+ return {
22
+ ...(nextConfig ? { nextConfig: toPosix(path.relative(config.outPath, nextConfig.file)) } : {}),
23
+ ...(instrumentation
24
+ ? {
25
+ instrumentation: {
26
+ file: toPosix(instrumentation.file),
27
+ ...(instrumentation.edge ? { edge: toPosix(instrumentation.edge) } : {}),
28
+ },
29
+ }
30
+ : {}),
31
+ compat: {
32
+ rootParams: [...scanRootParams(config.appPath)],
33
+ pagesRevalidate: pagesRevalidateFacts(config.root).map(
34
+ ([file, seconds]): [string, number] => [toPosix(file), seconds],
35
+ ),
36
+ pagesApi: pagesApiFacts(config.root),
37
+ pagesRoutes: pagesRouteFacts(config),
38
+ cacheHandlers: Object.fromEntries(
39
+ Object.entries(nextConfig?.handlers ?? {}).map(([name, file]) => [
40
+ name,
41
+ toPosix(path.relative(config.outPath, file)),
42
+ ]),
43
+ ),
44
+ },
45
+ }
46
+ }
@@ -30,7 +30,7 @@ import {
30
30
  } from '../../extensions'
31
31
  import { getRequestRuntime } from '../../routing/request-environment'
32
32
  import { takeCacheLifeStash } from '../cache/use-cache'
33
- import { matchInterception, parseNavState, selectRouteForRequest } from '../../routing/routes'
33
+ import { matchInterception, parseNavState, selectRouteForRequest } from '../../routing/match'
34
34
  import {
35
35
  currentPprShellHtml,
36
36
  pprShellPath,
@@ -10,8 +10,9 @@
10
10
  // undefined/non-component default export; and the output:'export' extras (exportPathMap + app, a
11
11
  // dynamic route without generateStaticParams, route handlers without static opt-ins, force-dynamic).
12
12
 
13
- import { existsSync, readdirSync, readFileSync } from 'node:fs'
13
+ import { existsSync, readdirSync } from 'node:fs'
14
14
  import path from 'node:path'
15
+ import { readSourceSync } from '../../resolve/source-text'
15
16
  import type { ResolvedConfig } from '../../config'
16
17
  import { extraPageExtensions } from '../../extensions'
17
18
  import type { RouteManifestEntry } from '../../types'
@@ -366,7 +367,7 @@ function readSource(file: string): string | undefined {
366
367
  if (sourceCache.has(file)) return sourceCache.get(file)
367
368
  let source: string | undefined
368
369
  try {
369
- source = readFileSync(file, 'utf8')
370
+ source = readSourceSync(file)
370
371
  } catch {
371
372
  source = undefined
372
373
  }
@@ -379,7 +380,12 @@ function routeFiles(route: RouteManifestEntry): string[] {
379
380
  }
380
381
 
381
382
  function isAppSourceFile(config: ResolvedConfig, file: string): boolean {
382
- if (isInside(config.outPath, file)) return false
383
+ const materialized =
384
+ file.includes(`${path.sep}source-app${path.sep}`) ||
385
+ file.includes(`${path.sep}source-pages${path.sep}`)
386
+ // A build materializes pages sources into its output (`<out>/pnext-pages-compat`).
387
+ if (isInside(config.outPath, file))
388
+ return materialized && file.includes(`${path.sep}pnext-pages-compat${path.sep}`)
383
389
  const relative = path.relative(config.root, file)
384
390
  if (relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative)) {
385
391
  // A standalone npm layout keeps node_modules INSIDE the root; framework-supplied route
@@ -387,10 +393,7 @@ function isAppSourceFile(config: ResolvedConfig, file: string): boolean {
387
393
  // (a JSDoc example in pnext's extensions.ts failed a real app's build as './pic.png').
388
394
  return !relative.split(path.sep).includes('node_modules')
389
395
  }
390
- return (
391
- file.includes(`${path.sep}source-app${path.sep}`) ||
392
- file.includes(`${path.sep}source-pages${path.sep}`)
393
- )
396
+ return materialized
394
397
  }
395
398
 
396
399
  function isInside(parent: string, file: string): boolean {
package/src/config.ts CHANGED
@@ -2,10 +2,11 @@ import { existsSync, realpathSync } from 'node:fs'
2
2
  import { fileURLToPath, pathToFileURL } from 'node:url'
3
3
  import path from 'node:path'
4
4
  import { loadEnv } from './env'
5
- import { findWorkspaceRoot } from './resolve/imports'
5
+ import { findWorkspaceRoot } from './resolve/package-json'
6
6
  import { PREFETCH_MODES, type PNextConfig } from './types'
7
7
  import { setCacheComponents } from './render/ppr'
8
8
  import { setLegacyRequestAPIs } from './request/context'
9
+ import { attachRelease, locateRelease, readBuildIndex, releaseConfig } from './runtime/production'
9
10
 
10
11
  export type ResolvedConfig = Required<Pick<PNextConfig, 'outDir' | 'basePath'>> &
11
12
  Omit<PNextConfig, 'outDir' | 'basePath'> & {
@@ -61,7 +62,13 @@ export interface ConfigSourceOverrides {
61
62
  }
62
63
  export type ConfigSource = (
63
64
  root: string,
64
- options: { dev?: boolean; serve?: boolean; warnings?: boolean },
65
+ options: {
66
+ dev?: boolean
67
+ serve?: boolean
68
+ warnings?: boolean
69
+ bundle?: string | null
70
+ handlers?: Record<string, string>
71
+ },
65
72
  ) => Promise<ConfigSourceOverrides>
66
73
 
67
74
  let configSource: ConfigSource | undefined
@@ -73,7 +80,7 @@ export function registerConfigSource(source: ConfigSource): void {
73
80
  async function resolveConfigSource(
74
81
  config: PNextConfig,
75
82
  root: string,
76
- options: { dev?: boolean; serve?: boolean; warnings?: boolean },
83
+ options: Parameters<ConfigSource>[1],
77
84
  ): Promise<ConfigSourceOverrides> {
78
85
  if (!config.compat?.next) return {}
79
86
  if (!configSource) {
@@ -90,6 +97,8 @@ export async function loadConfig(
90
97
  options: { dev?: boolean; serve?: boolean; warnings?: boolean } = {},
91
98
  ): Promise<ResolvedConfig> {
92
99
  const root = canonicalRoot(path.resolve(rootInput))
100
+ const released = options.serve ? locateRelease(root, DEFAULT_OUT_DIR) : undefined
101
+ if (released) return loadReleasedConfig(root, released, options)
93
102
  await loadEnv(root, options)
94
103
  const configPath = path.join(root, 'pnext.config.ts')
95
104
  const loadedConfig = existsSync(configPath)
@@ -119,8 +128,13 @@ export async function loadConfig(
119
128
  setCacheComponents(false)
120
129
  const sourceOverrides = stripUndefined(await resolveConfigSource(config, root, options))
121
130
  const merged = { ...defaultConfig, ...config, ...sourceOverrides }
122
- const appPath = await resolveAppPath(root, config)
123
131
  const outRootPath = path.resolve(root, merged.outDir)
132
+ // A build materializes pages into its output, so the release names them portably.
133
+ const appPath = await resolveAppPath(
134
+ root,
135
+ config,
136
+ options.dev ? undefined : path.join(outRootPath, 'pnext-pages-compat'),
137
+ )
124
138
  const workspaceRoot = canonicalRoot(
125
139
  config.workspaceRoot
126
140
  ? path.resolve(root, config.workspaceRoot)
@@ -156,6 +170,36 @@ export async function loadConfig(
156
170
  }
157
171
  }
158
172
 
173
+ /**
174
+ * A production server's config: what the build resolved, read from its release instead of re-importing
175
+ * `pnext.config.ts`/`next.config.*`. Per-app process state is re-derived exactly as a source load does.
176
+ */
177
+ async function loadReleasedConfig(
178
+ root: string,
179
+ outPath: string,
180
+ options: { dev?: boolean; serve?: boolean; warnings?: boolean },
181
+ ): Promise<ResolvedConfig> {
182
+ const index = readBuildIndex(outPath)
183
+ const config = releaseConfig(index.config, root, outPath)
184
+ await loadEnv(root, options)
185
+ setLegacyRequestAPIs(
186
+ typeof config.compat?.next === 'object' && config.compat.next.legacyRequestAPIs === true,
187
+ )
188
+ setCacheComponents(false)
189
+ await resolveConfigSource(config, root, {
190
+ ...options,
191
+ bundle: index.nextConfig ? path.resolve(outPath, index.nextConfig) : null,
192
+ handlers: Object.fromEntries(
193
+ Object.entries(index.compat?.cacheHandlers ?? {}).map(([name, file]) => [
194
+ name,
195
+ path.resolve(outPath, file),
196
+ ]),
197
+ ),
198
+ })
199
+ attachRelease(config, index)
200
+ return config
201
+ }
202
+
159
203
  // One row per enum-valued config field; validateConfig checks them all.
160
204
  const enumFields: readonly [keyof PNextConfig, readonly unknown[]][] = [
161
205
  ['prefetch', PREFETCH_MODES],
@@ -264,7 +308,7 @@ export function pnextAliases(target: CompatAliasTarget): Record<string, string>
264
308
  }
265
309
  }
266
310
 
267
- async function resolveAppPath(root: string, config: PNextConfig) {
311
+ async function resolveAppPath(root: string, config: PNextConfig, pagesBase?: string) {
268
312
  const rootApp = path.join(root, 'app')
269
313
  if (config.compat?.next) {
270
314
  const pagesPath = path.join(root, 'pages')
@@ -272,13 +316,13 @@ async function resolveAppPath(root: string, config: PNextConfig) {
272
316
  if (existsSync(rootApp)) {
273
317
  if (hasPages) {
274
318
  const { materializePagesApp } = await import('./compat/pages/router')
275
- const hybrid = await materializePagesApp(root)
319
+ const hybrid = await materializePagesApp(root, pagesBase)
276
320
  if (hybrid) return hybrid
277
321
  }
278
322
  return rootApp
279
323
  }
280
324
  const { materializePagesApp } = await import('./compat/pages/router')
281
- const pagesApp = await materializePagesApp(root)
325
+ const pagesApp = await materializePagesApp(root, pagesBase)
282
326
  if (pagesApp) return pagesApp
283
327
  } else if (existsSync(rootApp)) return rootApp
284
328
  return path.join(root, 'src', 'app')
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Built-asset naming and the CSS-module runtime: what a render needs to link stylesheets. The CSS
3
+ * compiler lives in `./build`; a production server never loads it.
4
+ */
5
+ import { existsSync } from 'node:fs'
6
+ import { readFile, writeFile } from 'node:fs/promises'
7
+ import path from 'node:path'
8
+ import { getCssExtensions } from '../extensions'
9
+ import { nextCompatEnabled } from '../render/hooks'
10
+ import { productionRelease } from '../runtime/production'
11
+ import { hashedAssetName } from '../utils/asset-hash'
12
+ import { cssModuleScopePath, ensureDir, readText } from '../utils/fs'
13
+ import type { ResolvedConfig } from '../config'
14
+ import type { RouteManifestEntry } from '../types'
15
+
16
+ let build: Promise<typeof import('./build')> | undefined
17
+
18
+ export async function globalCssHref(config: ResolvedConfig) {
19
+ const sources =
20
+ productionRelease(config)?.globalCss ??
21
+ (await (build ??= import('./build'))).globalCssSources(config)
22
+ return sources.length > 0 ? assetHref(config, 'global.css') : undefined
23
+ }
24
+
25
+ export type AssetHrefConfig = Pick<ResolvedConfig, 'assetPrefix' | 'compat' | 'outPath'>
26
+
27
+ /**
28
+ * Logical build-asset name -> the content-hashed name the build actually emitted
29
+ * (`global.css` -> `global-1f4a9c2b3d5e6f70.css`). A production asset name must
30
+ * carry its content, or the URL cannot honestly be served `immutable`: the same
31
+ * name would answer different bytes after a deploy.
32
+ *
33
+ * Keyed by outPath, never process-global: one process builds several apps (the
34
+ * test suite does it constantly) and their names must not cross. Empty in dev,
35
+ * where names stay flat and every asset is served `no-cache` anyway.
36
+ */
37
+ const emittedAssets = new Map<string, Map<string, string>>()
38
+
39
+ export function recordEmittedAsset(outPath: string, logical: string, emitted: string): void {
40
+ const names = emittedAssets.get(outPath) ?? new Map<string, string>()
41
+ names.set(logical, emitted)
42
+ emittedAssets.set(outPath, names)
43
+ }
44
+
45
+ /** Re-publish the build's name map at server boot (see BuildManifest.assetNames). */
46
+ export function publishEmittedAssets(
47
+ outPath: string,
48
+ names: Record<string, string> | undefined,
49
+ ): void {
50
+ if (!names) return
51
+ for (const [logical, emitted] of Object.entries(names))
52
+ recordEmittedAsset(outPath, logical, emitted)
53
+ }
54
+
55
+ export function emittedAssetNames(outPath: string): Record<string, string> {
56
+ return Object.fromEntries(emittedAssets.get(outPath) ?? [])
57
+ }
58
+
59
+ export function clearEmittedAssets(outPath: string): void {
60
+ emittedAssets.delete(outPath)
61
+ }
62
+
63
+ /** The file name a logical asset name resolves to. Identity until a build records one. */
64
+ export function emittedAssetName(
65
+ config: Pick<ResolvedConfig, 'outPath'> | undefined,
66
+ name: string,
67
+ ): string {
68
+ if (!config?.outPath) return name
69
+ return emittedAssets.get(config.outPath)?.get(name) ?? name
70
+ }
71
+
72
+ // Where a built asset lives in the URL space. next-compat serves the build output under Next's
73
+ // static path, so a compat app's document references its CSS/JS exactly as Next does; core keeps
74
+ // `/assets/`. Every document-emitted build-asset URL goes through here (and the dev/prod servers
75
+ // accept both spellings), so an emitted href can never name a path the server will not serve —
76
+ // including the content hash the production name carries.
77
+ export function assetPathname(
78
+ config: Pick<ResolvedConfig, 'compat' | 'outPath'> | undefined,
79
+ name: string,
80
+ ) {
81
+ const emitted = emittedAssetName(config, name)
82
+ return nextCompatEnabled(config ?? {}) ? `/_next/static/${emitted}` : `/assets/${emitted}`
83
+ }
84
+
85
+ export function assetHref(config: AssetHrefConfig | undefined, name: string) {
86
+ return withAssetPrefix(config, assetPathname(config, name))
87
+ }
88
+
89
+ // A route's built CSS filenames - the one rule behind the document's links, the
90
+ // inline-CSS path and analyze, so no consumer can disagree about whether a
91
+ // route has CSS. compat cssChunking records split names in cssAssets.
92
+ export function routeCssAssetNames(
93
+ route: Pick<RouteManifestEntry, 'id' | 'cssImports' | 'cssAssets'>,
94
+ ): string[] {
95
+ if (route.cssImports.length === 0) return []
96
+ return route.cssAssets?.length ? route.cssAssets : [`${route.id}.css`]
97
+ }
98
+
99
+ export function routeCssHref(
100
+ route: RouteManifestEntry,
101
+ config?: AssetHrefConfig,
102
+ ): string | string[] | undefined {
103
+ const assets = routeCssAssetNames(route)
104
+ if (assets.length === 0) return undefined
105
+ return assets.map(asset => assetHref(config, asset))
106
+ }
107
+
108
+ /**
109
+ * Put a render's next/font rules in the first stylesheet chunk, matching Next's
110
+ * linked CSS delivery without changing the rest of the route's chunk order.
111
+ */
112
+ export async function emitFontCssStylesheet(
113
+ config: ResolvedConfig,
114
+ routeId: string,
115
+ fontCss: string,
116
+ baseAsset: string | undefined,
117
+ options: { dev: boolean },
118
+ ) {
119
+ const outDir = path.join(config.outPath, options.dev ? 'cache' : 'public', 'assets')
120
+ await ensureDir(outDir)
121
+ const baseFile = baseAsset ? path.join(outDir, baseAsset) : undefined
122
+ const baseCss = baseFile && existsSync(baseFile) ? await readFile(baseFile, 'utf8') : ''
123
+ const contents = [fontCss, baseCss].filter(Boolean).join('\n')
124
+ const logicalName = baseAsset
125
+ ? baseAsset.replace(/-[0-9a-f]{16}(?=\.css$)/, '')
126
+ : `${routeId}.css`
127
+ const name = hashedAssetName(logicalName, contents)
128
+ const file = path.join(outDir, name)
129
+ if (!existsSync(file) || (await readFile(file, 'utf8')) !== contents)
130
+ await writeFile(file, contents)
131
+ return name
132
+ }
133
+
134
+ // Prepend the configured assetPrefix (a CDN origin or path) to an app-absolute
135
+ // asset URL. Link hrefs use basePath instead and must NOT go through here.
136
+ export function withAssetPrefix(
137
+ config: Pick<ResolvedConfig, 'assetPrefix'> | undefined,
138
+ href: string,
139
+ ) {
140
+ const prefix = config?.assetPrefix
141
+ if (!prefix) return href
142
+ return `${prefix.replace(/\/$/, '')}${href}`
143
+ }
144
+
145
+ let cssRuntimeRegistered = false
146
+
147
+ export function registerCssRuntime() {
148
+ if (cssRuntimeRegistered) return
149
+ cssRuntimeRegistered = true
150
+
151
+ Bun.plugin({
152
+ name: 'pnext-css-runtime',
153
+ setup(plugin) {
154
+ plugin.onLoad({ filter: /\.(?:css|scss|sass)$/ }, async ({ path: file }) =>
155
+ isCssModuleFile(file)
156
+ ? {
157
+ exports: { default: await cssModuleMapping(file) },
158
+ loader: 'object',
159
+ }
160
+ : {
161
+ contents: 'export default undefined;',
162
+ loader: 'js',
163
+ },
164
+ )
165
+ },
166
+ })
167
+ }
168
+
169
+ // Sass is unsupported (no compiler); its imports still must not break the
170
+ // bundle, so .scss/.sass load as empty modules with module class-name maps.
171
+ export function isCssModuleFile(file: string) {
172
+ return /\.module\.(?:css|scss|sass)$/.test(file)
173
+ }
174
+
175
+ export async function cssModuleMapping(file: string) {
176
+ // Compat handles *.module.{scss,sass} (sass compiles + scopes); core keeps
177
+ // plain .module.css. Lazy read: the registry populates at compat bootstrap.
178
+ const compatMapping = getCssExtensions().resolveCssModule(file)
179
+ if (compatMapping) return compatMapping
180
+ const source = await readText(file)
181
+ const classNames = cssClassNames(source)
182
+
183
+ return Object.fromEntries(
184
+ [...classNames].map(className => [className, cssModuleClassName(file, className)]),
185
+ )
186
+ }
187
+
188
+ export function cssClassNames(source: string) {
189
+ const classNames = new Set<string>()
190
+ const classPattern = /(^|[^\\])\.(-?[_a-zA-Z][\w-]*)/g
191
+ let match: RegExpExecArray | null
192
+
193
+ while ((match = classPattern.exec(source))) {
194
+ if (match[2]) classNames.add(match[2])
195
+ }
196
+
197
+ return classNames
198
+ }
199
+
200
+ export function cssModuleClassName(file: string, className: string) {
201
+ const base = path
202
+ .basename(file)
203
+ .replace(/\.module\.css$/, '')
204
+ .replace(/[^_a-zA-Z0-9]/g, '_')
205
+ const hash = pathHash(cssModuleScopePath(file))
206
+ return `${base}_${className}_${hash}`
207
+ }
208
+
209
+ function pathHash(file: string) {
210
+ let hash = 5381
211
+ for (const char of file) hash = ((hash << 5) + hash) ^ char.charCodeAt(0)
212
+ return (hash >>> 0).toString(36).slice(0, 5)
213
+ }