@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.
- package/bin/pnext +9 -2
- package/dist/server/_chunks/aliases-j47a10ce.js +44 -0
- package/dist/server/_chunks/analyze-arswqe6s.js +445 -0
- package/dist/server/_chunks/boot-af0mv3dy.js +36 -0
- package/dist/server/_chunks/build-spy3dxp4.js +84 -0
- package/dist/server/_chunks/build-t9h0hec3.js +3550 -0
- package/dist/server/_chunks/build-tier-m7yvqz61.js +2472 -0
- package/dist/server/_chunks/compile-53j02j27.js +22 -0
- package/dist/server/_chunks/config-1yzwexq6.js +27 -0
- package/dist/server/_chunks/config-n2z7yxps.js +22 -0
- package/dist/server/_chunks/create-meec9hs6.js +134 -0
- package/dist/server/_chunks/dev-fjmqg6en.js +220 -0
- package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
- package/dist/server/_chunks/generate-n9sh6hzt.js +21 -0
- package/dist/server/_chunks/index-0374j2b9.js +66 -0
- package/dist/server/_chunks/index-06nyqntx.js +213 -0
- package/dist/server/_chunks/index-1011cscr.js +5263 -0
- package/dist/server/_chunks/index-11sfk4hb.js +170 -0
- package/dist/server/_chunks/index-20ppawv7.js +297 -0
- package/dist/server/_chunks/index-2dv4y4wd.js +1065 -0
- package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
- package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
- package/dist/server/_chunks/index-357na4a8.js +109 -0
- package/dist/server/_chunks/index-3b3at80h.js +109 -0
- package/dist/server/_chunks/index-3tf1xjsp.js +6166 -0
- package/dist/server/_chunks/index-3xbr4eyv.js +105 -0
- package/dist/server/_chunks/index-4399bvd2.js +18 -0
- package/dist/server/_chunks/index-4hgjrqh7.js +851 -0
- package/dist/server/_chunks/index-4q2gbfwk.js +2530 -0
- package/dist/server/_chunks/index-4t92hdxd.js +172 -0
- package/dist/server/_chunks/index-4zzebszd.js +10 -0
- package/dist/server/_chunks/index-5gyr4emz.js +107 -0
- package/dist/server/_chunks/index-5hr4062s.js +70 -0
- package/dist/server/_chunks/index-68m3mwbd.js +84 -0
- package/dist/server/_chunks/index-6b009mt0.js +56 -0
- package/dist/server/_chunks/index-6e4fqv30.js +588 -0
- package/dist/server/_chunks/index-6gex3pfa.js +15 -0
- package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
- package/dist/server/_chunks/index-6q7zvrap.js +134 -0
- package/dist/server/_chunks/index-73z4esab.js +38 -0
- package/dist/server/_chunks/index-79ngvam8.js +60 -0
- package/dist/server/_chunks/index-7wc9n8be.js +25 -0
- package/dist/server/_chunks/index-8k7pfejn.js +1599 -0
- package/dist/server/_chunks/index-8kcxdfya.js +206 -0
- package/dist/server/_chunks/index-91x12ykq.js +274 -0
- package/dist/server/_chunks/index-9ch50vtq.js +18 -0
- package/dist/server/_chunks/index-9hx2641q.js +28 -0
- package/dist/server/_chunks/index-9n2914ww.js +535 -0
- package/dist/server/_chunks/index-9ych9ma8.js +207 -0
- package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
- package/dist/server/_chunks/index-bcws5eh2.js +35 -0
- package/dist/server/_chunks/index-c0g2wf3z.js +92 -0
- package/dist/server/_chunks/index-cf4rvxv6.js +95 -0
- package/dist/server/_chunks/index-cjgqs13g.js +65 -0
- package/dist/server/_chunks/index-ckkdpht5.js +41 -0
- package/dist/server/_chunks/index-cyfednwb.js +87 -0
- package/dist/server/_chunks/index-danncfhy.js +311 -0
- package/dist/server/_chunks/index-dg0f05zs.js +199 -0
- package/dist/server/_chunks/index-e3a6yx84.js +18 -0
- package/dist/server/_chunks/index-e88tyv35.js +45 -0
- package/dist/server/_chunks/index-eajaspjk.js +1253 -0
- package/dist/server/_chunks/index-eeaanp2e.js +483 -0
- package/dist/server/_chunks/index-egykcqg3.js +101 -0
- package/dist/server/_chunks/index-en7n9f7m.js +22 -0
- package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
- package/dist/server/_chunks/index-fkp000p1.js +590 -0
- package/dist/server/_chunks/index-fn1chkkd.js +214 -0
- package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
- package/dist/server/_chunks/index-ggk2j965.js +9432 -0
- package/dist/server/_chunks/index-grta8ap3.js +238 -0
- package/dist/server/_chunks/index-h2a70tg4.js +7 -0
- package/dist/server/_chunks/index-h4xy648y.js +51 -0
- package/dist/server/_chunks/index-hkdfj58q.js +92 -0
- package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
- package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
- package/dist/server/_chunks/index-jepjvcrf.js +198 -0
- package/dist/server/_chunks/index-jks0x0a1.js +14 -0
- package/dist/server/_chunks/index-jx7bqvw1.js +57 -0
- package/dist/server/_chunks/index-k1g3epw0.js +1299 -0
- package/dist/server/_chunks/index-knp0s912.js +7 -0
- package/dist/server/_chunks/index-kq8kpzye.js +472 -0
- package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
- package/dist/server/_chunks/index-kresp2n8.js +445 -0
- package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
- package/dist/server/_chunks/index-n4hxpng2.js +11 -0
- package/dist/server/_chunks/index-ncnes8c6.js +17 -0
- package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
- package/dist/server/_chunks/index-nyrba2kr.js +4130 -0
- package/dist/server/_chunks/index-p77b4kcx.js +296 -0
- package/dist/server/_chunks/index-pym1cezq.js +39 -0
- package/dist/server/_chunks/index-q738kkhj.js +100 -0
- package/dist/server/_chunks/index-qjj6gddn.js +54 -0
- package/dist/server/_chunks/index-qm6kmhqs.js +110 -0
- package/dist/server/_chunks/index-qn4z5s3c.js +819 -0
- package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
- package/dist/server/_chunks/index-r97ptz1q.js +97 -0
- package/dist/server/_chunks/index-ras0sdab.js +26 -0
- package/dist/server/_chunks/index-rcs322t1.js +19 -0
- package/dist/server/_chunks/index-rn8dyr1f.js +126 -0
- package/dist/server/_chunks/index-rt9qq1va.js +4 -0
- package/dist/server/_chunks/index-rthrsed5.js +356 -0
- package/dist/server/_chunks/index-sctcgyvv.js +185 -0
- package/dist/server/_chunks/index-sjpckxqn.js +213 -0
- package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
- package/dist/server/_chunks/index-stbk3jhn.js +31 -0
- package/dist/server/_chunks/index-sv8m6789.js +266 -0
- package/dist/server/_chunks/index-tgcakdxc.js +125 -0
- package/dist/server/_chunks/index-tgsfjmep.js +74 -0
- package/dist/server/_chunks/index-tq0pc7eg.js +154 -0
- package/dist/server/_chunks/index-tq1f96v7.js +51 -0
- package/dist/server/_chunks/index-tqn2qnnn.js +241 -0
- package/dist/server/_chunks/index-tvqkq6e6.js +128 -0
- package/dist/server/_chunks/index-v1ags1na.js +132 -0
- package/dist/server/_chunks/index-vvmmknm1.js +1431 -0
- package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
- package/dist/server/_chunks/index-vz0km5qk.js +33 -0
- package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
- package/dist/server/_chunks/index-web361b8.js +138 -0
- package/dist/server/_chunks/index-wpfhfbs4.js +194 -0
- package/dist/server/_chunks/index-x0y005nh.js +283 -0
- package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
- package/dist/server/_chunks/index-x93hv0sc.js +271 -0
- package/dist/server/_chunks/index-xvj80c3a.js +30 -0
- package/dist/server/_chunks/index-xywjg2vc.js +100 -0
- package/dist/server/_chunks/index-y2jr2n72.js +152 -0
- package/dist/server/_chunks/index-y36a0ybw.js +57 -0
- package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
- package/dist/server/_chunks/index-yhxkxghe.js +56 -0
- package/dist/server/_chunks/index-ym67zqxp.js +130 -0
- package/dist/server/_chunks/index-ytjvpbm2.js +736 -0
- package/dist/server/_chunks/index-yz54pxrh.js +960 -0
- package/dist/server/_chunks/index-z4z9zv3b.js +733 -0
- package/dist/server/_chunks/index-z84ab1w0.js +1270 -0
- package/dist/server/_chunks/index-z88qv16t.js +11 -0
- package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
- package/dist/server/_chunks/loader-7yw0j98z.js +78 -0
- package/dist/server/_chunks/modules-jn8bmbn8.js +74 -0
- package/dist/server/_chunks/pipeline-yy9jhydf.js +832 -0
- package/dist/server/_chunks/production-jar9ztm3.js +44 -0
- package/dist/server/_chunks/proxy-config-j84dgksn.js +21 -0
- package/dist/server/_chunks/proxy-w1d0wmsn.js +33 -0
- package/dist/server/_chunks/router-k1reahfn.js +498 -0
- package/dist/server/_chunks/routes-2s277fc6.js +64 -0
- package/dist/server/_chunks/run-pvd8bs1t.js +696 -0
- package/dist/server/_chunks/server-mt4a994c.js +1835 -0
- package/dist/server/_chunks/tsconfig-defaults-1nb3308g.js +20 -0
- package/dist/server/_chunks/typegen-0qr0459b.js +35 -0
- package/dist/server/api/client-cache.js +14 -0
- package/dist/server/cli/index.js +378 -0
- package/dist/server/cli/start.js +137 -0
- package/dist/server/client/reference.js +16 -0
- package/dist/server/compat/next/cache.js +56 -0
- package/dist/server/compat/next/canonical-url.js +13 -0
- package/dist/server/compat/next/client-cache.js +57 -0
- package/dist/server/compat/next/client-navigation.js +232 -0
- package/dist/server/compat/next/client-only.js +1 -0
- package/dist/server/compat/next/client-script.js +178 -0
- package/dist/server/compat/next/client-server.js +34 -0
- package/dist/server/compat/next/config-headers.js +32 -0
- package/dist/server/compat/next/config-loader.js +25 -0
- package/dist/server/compat/next/config.js +10 -0
- package/dist/server/compat/next/constants.js +18 -0
- package/dist/server/compat/next/custom-server.js +10 -0
- package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
- package/dist/server/compat/next/dynamic.js +32 -0
- package/dist/server/compat/next/error.js +112 -0
- package/dist/server/compat/next/font/cache.js +14 -0
- package/dist/server/compat/next/font/google.js +3 -0
- package/dist/server/compat/next/font/index.js +1 -0
- package/dist/server/compat/next/font/local.js +22 -0
- package/dist/server/compat/next/font/runtime-client.js +33 -0
- package/dist/server/compat/next/font/runtime.js +41 -0
- package/dist/server/compat/next/font/shared.js +22 -0
- package/dist/server/compat/next/form.js +129 -0
- package/dist/server/compat/next/head.js +10 -0
- package/dist/server/compat/next/headers.js +30 -0
- package/dist/server/compat/next/image/client.js +11 -0
- package/dist/server/compat/next/image/config.js +18 -0
- package/dist/server/compat/next/image/optimizer.js +25 -0
- package/dist/server/compat/next/image/patterns.js +12 -0
- package/dist/server/compat/next/image/props.js +16 -0
- package/dist/server/compat/next/image/shared.js +86 -0
- package/dist/server/compat/next/image/static-metadata.js +32 -0
- package/dist/server/compat/next/image/validate.js +8 -0
- package/dist/server/compat/next/image.js +59 -0
- package/dist/server/compat/next/index.js +1 -0
- package/dist/server/compat/next/legacy-image.js +78 -0
- package/dist/server/compat/next/legacy-request-apis.js +24 -0
- package/dist/server/compat/next/link-transform.js +14 -0
- package/dist/server/compat/next/link.js +14 -0
- package/dist/server/compat/next/navigation.js +190 -0
- package/dist/server/compat/next/offline.js +45 -0
- package/dist/server/compat/next/og.js +8 -0
- package/dist/server/compat/next/preferred-region.js +8 -0
- package/dist/server/compat/next/redirects.js +30 -0
- package/dist/server/compat/next/resource-hints.js +30 -0
- package/dist/server/compat/next/rewrites.js +41 -0
- package/dist/server/compat/next/root-params.js +121 -0
- package/dist/server/compat/next/route-state.js +23 -0
- package/dist/server/compat/next/router.js +103 -0
- package/dist/server/compat/next/script.js +37 -0
- package/dist/server/compat/next/server-only.js +1 -0
- package/dist/server/compat/next/server.js +131 -0
- package/dist/server/compat/next/svgr.js +14 -0
- package/dist/server/compat/next/telemetry.js +10 -0
- package/dist/server/compat/next/usage.js +13 -0
- package/dist/server/compat/next/user-agent.js +12 -0
- package/dist/server/compat/next/web-vitals.js +35 -0
- package/dist/server/compat/react/action-state.js +11 -0
- package/dist/server/compat/react/client-lite.js +83 -0
- package/dist/server/compat/react/client.js +131 -0
- package/dist/server/compat/react/compiler-runtime.js +42 -0
- package/dist/server/compat/react/dom-client.js +106 -0
- package/dist/server/compat/react/dom-react-server.js +37 -0
- package/dist/server/compat/react/dom-server.js +40 -0
- package/dist/server/compat/react/dom.js +52 -0
- package/dist/server/compat/react/hooks-extra.js +12 -0
- package/dist/server/compat/react/internals.js +14 -0
- package/dist/server/compat/react/parity.js +11 -0
- package/dist/server/compat/react/preact.js +113 -0
- package/dist/server/compat/react/react-server.js +133 -0
- package/dist/server/compat/react/router-shim.js +8 -0
- package/dist/server/compat/react/server-component-use.js +14 -0
- package/dist/server/compat/react/server-inserted-html.js +14 -0
- package/dist/server/compat/react/server.js +194 -0
- package/dist/server/compat/react/style-values.js +10 -0
- package/dist/server/compat/react/use.js +10 -0
- package/dist/server/compat/react/view-transition.js +12 -0
- package/dist/server/generation.json +1 -0
- package/package.json +4 -1
- package/src/api/dynamic.tsx +2 -0
- package/src/api/server.ts +24 -6
- package/src/cli/adapters/vercel-warm.ts +315 -61
- package/src/cli/adapters/vercel.ts +348 -71
- package/src/cli/build.ts +58 -33
- package/src/cli/index.ts +23 -10
- package/src/cli/serve/entry.ts +21 -159
- package/src/cli/serve/immutable.ts +31 -0
- package/src/cli/serve/pipeline.ts +82 -84
- package/src/cli/start.ts +3 -1
- package/src/client/chunk-fold.ts +19 -6
- package/src/client/react-tier.ts +3 -2
- package/src/client/reference-stub.ts +21 -2
- package/src/compat/actions/client-plugin.ts +4 -2
- package/src/compat/actions/config.ts +6 -5
- package/src/compat/actions/extensions.ts +2 -3
- package/src/compat/aliases.ts +8 -1
- package/src/compat/bundler/config.ts +88 -0
- package/src/compat/bundler/optimize-package-imports.ts +86 -26
- package/src/compat/bundler/relay-transform.ts +15 -3
- package/src/compat/cache-control.ts +16 -8
- package/src/compat/css/modules.ts +18 -5
- package/src/compat/lifecycle/error-funnel.ts +1 -1
- package/src/compat/lifecycle/instrumentation.ts +117 -24
- package/src/compat/lifecycle/testmode.ts +3 -2
- package/src/compat/next/config-loader.ts +137 -13
- package/src/compat/next/font/runtime.ts +22 -2
- package/src/compat/next/og.ts +3 -3
- package/src/compat/next/usage.ts +3 -2
- package/src/compat/pages/api.ts +83 -14
- package/src/compat/pages/router.ts +30 -14
- package/src/compat/register/bundler.ts +3 -1
- package/src/compat/register/middleware.ts +1 -1
- package/src/compat/register/otel.ts +5 -9
- package/src/compat/register/render.ts +3 -1
- package/src/compat/register/use-cache.ts +3 -1
- package/src/compat/release.ts +46 -0
- package/src/compat/segment/serve.ts +1 -1
- package/src/compat/validation/validate.ts +10 -7
- package/src/config.ts +51 -7
- package/src/css/assets.ts +213 -0
- package/src/css/build.ts +174 -238
- package/src/dev/server.ts +27 -8
- package/src/extensions.ts +4 -0
- package/src/render/hooks.ts +13 -0
- package/src/render/renderer.ts +52 -32
- package/src/request/context.ts +9 -0
- package/src/resolve/dynamic.ts +3 -1
- package/src/resolve/imports.ts +12 -52
- package/src/resolve/package-json.ts +56 -0
- package/src/resolve/scan-facts.ts +65 -0
- package/src/routing/href.ts +10 -3
- package/src/routing/match.ts +287 -0
- package/src/routing/metadata-files.ts +19 -5
- package/src/routing/proxy-config.ts +137 -0
- package/src/routing/proxy.ts +35 -134
- package/src/routing/routes.ts +22 -281
- package/src/runtime/fingerprint.ts +23 -8
- package/src/runtime/load.ts +170 -0
- package/src/runtime/loader.ts +215 -43
- package/src/runtime/module-cache.ts +13 -0
- package/src/runtime/modules.ts +370 -81
- package/src/runtime/prebundle.ts +81 -0
- package/src/runtime/production.ts +391 -0
- package/src/runtime/release-graph.ts +334 -0
- package/src/runtime/vendor-build.ts +724 -13
- package/src/runtime/vendor.ts +16 -3
- package/src/types.ts +2 -0
- 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
|
+
}
|