@wular/pnext 0.1.6 → 0.1.8
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-pycbtjt1.js +46 -0
- package/dist/server/_chunks/analyze-4d9e00g9.js +449 -0
- package/dist/server/_chunks/boot-bhemypxz.js +38 -0
- package/dist/server/_chunks/build-c991dv65.js +86 -0
- package/dist/server/_chunks/build-kh5e3x48.js +3341 -0
- package/dist/server/_chunks/build-tier-0a96kmx3.js +2456 -0
- package/dist/server/_chunks/compile-040r79gj.js +22 -0
- package/dist/server/_chunks/config-0tvz03a6.js +24 -0
- package/dist/server/_chunks/config-27rj7830.js +36 -0
- package/dist/server/_chunks/create-9rvwshsp.js +135 -0
- package/dist/server/_chunks/dev-ex9exynt.js +220 -0
- package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
- package/dist/server/_chunks/generate-myw9hef7.js +22 -0
- package/dist/server/_chunks/index-0r5eqfc7.js +279 -0
- package/dist/server/_chunks/index-0yjv5v47.js +105 -0
- package/dist/server/_chunks/index-11xpbfej.js +17 -0
- package/dist/server/_chunks/index-141vcwk6.js +109 -0
- package/dist/server/_chunks/index-1pzm1hdy.js +4130 -0
- package/dist/server/_chunks/index-29pq0kax.js +590 -0
- package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
- package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
- package/dist/server/_chunks/index-38xpdxwd.js +194 -0
- package/dist/server/_chunks/index-3e075kny.js +128 -0
- package/dist/server/_chunks/index-3ycf5ckv.js +472 -0
- package/dist/server/_chunks/index-4399bvd2.js +18 -0
- package/dist/server/_chunks/index-4da76t62.js +297 -0
- package/dist/server/_chunks/index-4t92hdxd.js +172 -0
- package/dist/server/_chunks/index-4zzebszd.js +10 -0
- package/dist/server/_chunks/index-52k54ykj.js +95 -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-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-71885zaq.js +284 -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-8ct7rqy3.js +198 -0
- package/dist/server/_chunks/index-8kcxdfya.js +206 -0
- package/dist/server/_chunks/index-9ch50vtq.js +18 -0
- package/dist/server/_chunks/index-9f49w76j.js +213 -0
- package/dist/server/_chunks/index-9hz3s0m8.js +851 -0
- package/dist/server/_chunks/index-akkrvjn6.js +535 -0
- package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
- package/dist/server/_chunks/index-b7j671dj.js +207 -0
- package/dist/server/_chunks/index-bcws5eh2.js +35 -0
- package/dist/server/_chunks/index-bzd2ef7t.js +10 -0
- package/dist/server/_chunks/index-cjgqs13g.js +65 -0
- package/dist/server/_chunks/index-ckkdpht5.js +41 -0
- package/dist/server/_chunks/index-cn86z041.js +296 -0
- package/dist/server/_chunks/index-cvr4z22m.js +92 -0
- package/dist/server/_chunks/index-cyfednwb.js +87 -0
- package/dist/server/_chunks/index-d158y67j.js +152 -0
- package/dist/server/_chunks/index-d1jsmhhk.js +955 -0
- package/dist/server/_chunks/index-dg0f05zs.js +199 -0
- package/dist/server/_chunks/index-dgr390q7.js +9438 -0
- package/dist/server/_chunks/index-drwv61cc.js +185 -0
- package/dist/server/_chunks/index-e3a6yx84.js +18 -0
- package/dist/server/_chunks/index-e88tyv35.js +45 -0
- package/dist/server/_chunks/index-en7n9f7m.js +22 -0
- package/dist/server/_chunks/index-entm8bmz.js +28 -0
- package/dist/server/_chunks/index-evhd413j.js +57 -0
- package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
- package/dist/server/_chunks/index-fjv96re1.js +5295 -0
- package/dist/server/_chunks/index-fn1chkkd.js +214 -0
- package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
- package/dist/server/_chunks/index-gcmj16xy.js +92 -0
- package/dist/server/_chunks/index-gkndxkxf.js +736 -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-hdbwtdv2.js +352 -0
- package/dist/server/_chunks/index-he6n2bvp.js +1270 -0
- package/dist/server/_chunks/index-j0m1jxqa.js +1253 -0
- package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
- package/dist/server/_chunks/index-j681c48a.js +2530 -0
- package/dist/server/_chunks/index-jbj7ehef.js +50 -0
- package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
- package/dist/server/_chunks/index-jks0x0a1.js +14 -0
- package/dist/server/_chunks/index-jn9rbhrx.js +1599 -0
- package/dist/server/_chunks/index-jt8e1pje.js +12 -0
- package/dist/server/_chunks/index-kdhxpwyq.js +483 -0
- package/dist/server/_chunks/index-knp0s912.js +7 -0
- package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
- package/dist/server/_chunks/index-kresp2n8.js +445 -0
- package/dist/server/_chunks/index-m63czgq5.js +590 -0
- package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
- package/dist/server/_chunks/index-n4hxpng2.js +11 -0
- package/dist/server/_chunks/index-n629dy38.js +1071 -0
- package/dist/server/_chunks/index-nf3df4jy.js +266 -0
- package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
- package/dist/server/_chunks/index-pym1cezq.js +39 -0
- package/dist/server/_chunks/index-q3r9z8mq.js +213 -0
- package/dist/server/_chunks/index-q738kkhj.js +100 -0
- package/dist/server/_chunks/index-qcrvt6er.js +112 -0
- package/dist/server/_chunks/index-qjj6gddn.js +54 -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-rgj5mx84.js +101 -0
- package/dist/server/_chunks/index-rjegyfx4.js +1435 -0
- package/dist/server/_chunks/index-rt9qq1va.js +4 -0
- package/dist/server/_chunks/index-rthrsed5.js +356 -0
- package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
- package/dist/server/_chunks/index-stbk3jhn.js +31 -0
- package/dist/server/_chunks/index-tf4j19ge.js +130 -0
- package/dist/server/_chunks/index-tgcakdxc.js +125 -0
- package/dist/server/_chunks/index-tgsfjmep.js +74 -0
- package/dist/server/_chunks/index-tq1f96v7.js +51 -0
- package/dist/server/_chunks/index-tq3b39a5.js +107 -0
- package/dist/server/_chunks/index-typcbcsv.js +819 -0
- package/dist/server/_chunks/index-v1ags1na.js +132 -0
- package/dist/server/_chunks/index-vmr35jjw.js +170 -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-wm36rj4v.js +311 -0
- package/dist/server/_chunks/index-x0y005nh.js +283 -0
- package/dist/server/_chunks/index-x2m17v9c.js +6166 -0
- package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
- package/dist/server/_chunks/index-x9c55pzy.js +871 -0
- package/dist/server/_chunks/index-xh1nbk46.js +1299 -0
- package/dist/server/_chunks/index-xvj80c3a.js +30 -0
- package/dist/server/_chunks/index-xywjg2vc.js +100 -0
- package/dist/server/_chunks/index-y4d02znn.js +66 -0
- package/dist/server/_chunks/index-y7mzvq2q.js +110 -0
- package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
- package/dist/server/_chunks/index-yhxkxghe.js +56 -0
- package/dist/server/_chunks/index-yrjkqtfj.js +86 -0
- package/dist/server/_chunks/index-z88qv16t.js +11 -0
- package/dist/server/_chunks/index-zfrwq472.js +154 -0
- package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
- package/dist/server/_chunks/loader-5en7wpt5.js +80 -0
- package/dist/server/_chunks/modules-t92favpj.js +76 -0
- package/dist/server/_chunks/pipeline-4t9q43ht.js +836 -0
- package/dist/server/_chunks/production-385bw8df.js +55 -0
- package/dist/server/_chunks/proxy-config-60gprphe.js +23 -0
- package/dist/server/_chunks/proxy-gfhmktbk.js +35 -0
- package/dist/server/_chunks/router-xnrva921.js +501 -0
- package/dist/server/_chunks/routes-ht868pdc.js +66 -0
- package/dist/server/_chunks/run-d40d63ag.js +697 -0
- package/dist/server/_chunks/server-2p8fgqq2.js +1839 -0
- package/dist/server/_chunks/tsconfig-defaults-bcn34eqb.js +21 -0
- package/dist/server/_chunks/typegen-dvtcjtaw.js +37 -0
- package/dist/server/api/client-cache.js +14 -0
- package/dist/server/cli/index.js +375 -0
- package/dist/server/cli/start.js +158 -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 +34 -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 +21 -0
- package/dist/server/compat/next/error.js +112 -0
- package/dist/server/compat/next/font/cache.js +16 -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 +24 -0
- package/dist/server/compat/next/font/runtime-client.js +33 -0
- package/dist/server/compat/next/font/runtime.js +43 -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 +15 -0
- package/dist/server/compat/next/link.js +14 -0
- package/dist/server/compat/next/navigation.js +191 -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 +32 -0
- package/dist/server/compat/next/resource-hints.js +30 -0
- package/dist/server/compat/next/rewrites.js +43 -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/reference/compat.md +1 -1
- package/reference/config.md +2 -2
- package/reference/dev.md +1 -1
- package/reference/getting-started.md +1 -1
- package/reference/rendering.md +4 -4
- package/src/api/dynamic.tsx +86 -4
- package/src/api/server.ts +24 -6
- package/src/cli/adapters/vercel-warm.ts +327 -62
- package/src/cli/adapters/vercel.ts +164 -1054
- package/src/cli/analyze.ts +3 -2
- package/src/cli/build/cache.ts +6 -6
- package/src/cli/build.ts +78 -45
- package/src/cli/index.ts +21 -3
- package/src/cli/serve/immutable.ts +31 -0
- package/src/cli/serve/pipeline.ts +97 -93
- package/src/cli/serve/standalone-worker.ts +8 -0
- package/src/cli/serve/standalone.ts +703 -0
- package/src/cli/start.ts +31 -8
- package/src/client/build.ts +1 -1
- package/src/client/chunk-fold.ts +19 -6
- package/src/client/react-tier.ts +3 -2
- package/src/client/reference-stub.ts +23 -36
- package/src/compat/actions/client-plugin.ts +4 -2
- package/src/compat/actions/config.ts +6 -5
- package/src/compat/actions/extensions.ts +5 -5
- 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/bundler/require-context.ts +2 -1
- package/src/compat/bundler/webpack-loaders.ts +3 -2
- package/src/compat/bundler/worker.ts +2 -2
- package/src/compat/cache-control.ts +16 -8
- package/src/compat/css/inline-css.ts +1 -1
- package/src/compat/css/modules.ts +18 -5
- package/src/compat/export/build-complete.ts +1 -1
- package/src/compat/export/emit.ts +4 -4
- package/src/compat/export/standalone.ts +30 -65
- package/src/compat/image-optimizer/optimize.ts +1 -1
- package/src/compat/lifecycle/error-funnel.ts +1 -1
- package/src/compat/lifecycle/instrumentation-client.ts +4 -3
- package/src/compat/lifecycle/instrumentation.ts +117 -24
- package/src/compat/lifecycle/testmode.ts +3 -2
- package/src/compat/metadata-artifacts.ts +1 -1
- package/src/compat/next/config-loader.ts +140 -13
- package/src/compat/next/dynamic.tsx +10 -23
- package/src/compat/next/font/cache.ts +2 -1
- package/src/compat/next/font/runtime.ts +23 -3
- 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/image.ts +1 -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/typecheck/check.ts +6 -4
- package/src/compat/validation/validate.ts +10 -7
- package/src/config.ts +76 -9
- package/src/css/assets.ts +213 -0
- package/src/css/build.ts +190 -247
- package/src/dev/client-chunk-store.ts +2 -1
- package/src/dev/restart/client-key.ts +2 -1
- package/src/dev/restart/global-css.ts +2 -1
- package/src/dev/restart/route-bundle-key.ts +2 -1
- package/src/dev/restart/route-facts.ts +2 -1
- package/src/dev/server.ts +34 -14
- package/src/extensions.ts +4 -0
- package/src/out-paths.ts +10 -0
- package/src/render/hooks.ts +13 -0
- package/src/render/renderer.ts +53 -33
- package/src/request/context.ts +9 -0
- package/src/resolve/dynamic.ts +7 -1
- package/src/resolve/engine.ts +2 -12
- package/src/resolve/imports.ts +12 -52
- package/src/resolve/package-json.ts +56 -0
- package/src/resolve/scan-facts.ts +250 -1
- package/src/routing/href.ts +10 -3
- package/src/routing/match.ts +287 -0
- package/src/routing/metadata-files.ts +20 -6
- 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 +218 -44
- package/src/runtime/module-cache.ts +15 -1
- package/src/runtime/modules.ts +405 -82
- package/src/runtime/prebundle.ts +101 -0
- package/src/runtime/production.ts +456 -0
- package/src/runtime/release-graph.ts +342 -0
- package/src/runtime/vendor-build.ts +750 -17
- package/src/runtime/vendor.ts +16 -3
- package/src/types.ts +4 -3
- package/src/utils/directive.ts +40 -0
- package/src/utils/fs.ts +95 -4
- package/src/utils/resource-query.ts +12 -0
- package/src/cli/serve/entry.ts +0 -45
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// Everything is resolved relative to `process.cwd()`, matching the SWC transform's root. That is what
|
|
15
15
|
// makes the multi-project fixture work: each sub-project is built with its own cwd.
|
|
16
16
|
|
|
17
|
-
import { existsSync } from 'node:fs'
|
|
17
|
+
import { existsSync, realpathSync } from 'node:fs'
|
|
18
18
|
import path from 'node:path'
|
|
19
19
|
import { withSniff, type ServerSourceTransform } from '../../extensions'
|
|
20
20
|
import type { RelayCompilerConfig } from './config'
|
|
@@ -35,6 +35,14 @@ function relayTagPattern(): RegExp {
|
|
|
35
35
|
|
|
36
36
|
const OPERATION_NAME = /\b(?:query|mutation|subscription|fragment)\s+([A-Za-z_][\w]*)/
|
|
37
37
|
|
|
38
|
+
function realFile(file: string): string {
|
|
39
|
+
try {
|
|
40
|
+
return realpathSync(file)
|
|
41
|
+
} catch {
|
|
42
|
+
return file
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
function isUnder(dir: string, file: string): boolean {
|
|
39
47
|
const relative = path.relative(dir, file)
|
|
40
48
|
return relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative)
|
|
@@ -61,6 +69,7 @@ export function createRelayTransform(
|
|
|
61
69
|
|
|
62
70
|
const cwd = path.resolve(process.cwd())
|
|
63
71
|
const srcDir = path.resolve(cwd, relay.src)
|
|
72
|
+
const realSrcDir = realFile(srcDir)
|
|
64
73
|
const artifactDir = relay.artifactDirectory
|
|
65
74
|
? path.resolve(cwd, relay.artifactDirectory)
|
|
66
75
|
: undefined
|
|
@@ -88,11 +97,14 @@ export function createRelayTransform(
|
|
|
88
97
|
|
|
89
98
|
return withSniff(['graphql'], (source, file) => {
|
|
90
99
|
if (!source.includes('graphql`') && !/graphql\s*`/.test(source)) return source
|
|
91
|
-
const
|
|
100
|
+
const resolved = path.resolve(file)
|
|
101
|
+
// A build materializes pages under its out dir; its links lead back to the source file.
|
|
102
|
+
const absolute = isUnder(cwd, resolved) ? realFile(resolved) : resolved
|
|
92
103
|
// Next scopes the transform to `src`. Files outside the build cwd entirely
|
|
93
104
|
// (materialized copies) are not covered by that check, so only skip a file
|
|
94
105
|
// that lives under the cwd but outside the configured source root.
|
|
95
|
-
|
|
106
|
+
const inSrc = isUnder(srcDir, resolved) || isUnder(realSrcDir, absolute)
|
|
107
|
+
if (isUnder(cwd, absolute) && !inSrc) return source
|
|
96
108
|
|
|
97
109
|
const bindings = new Map<string, string>()
|
|
98
110
|
const replaced = source.replace(relayTagPattern(), (match, body: string) => {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
14
14
|
import path from 'node:path'
|
|
15
|
+
import { outCachePath } from '../../out-paths'
|
|
15
16
|
|
|
16
17
|
/** Extensions whose files also get an extension-less request key (webpack resolves both). */
|
|
17
18
|
const RESOLVABLE_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.json']
|
|
@@ -210,7 +211,7 @@ function resolveContextDir(
|
|
|
210
211
|
const direct = path.resolve(path.dirname(file), specifier)
|
|
211
212
|
if (existsSync(direct)) return direct
|
|
212
213
|
if (paths?.outPath && paths.workspaceRoot) {
|
|
213
|
-
const cacheRoot = path.join(paths.outPath, '
|
|
214
|
+
const cacheRoot = path.join(outCachePath(paths.outPath), 'server')
|
|
214
215
|
const relative = path.relative(cacheRoot, file)
|
|
215
216
|
if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
|
|
216
217
|
const segments = relative.split(path.sep)
|
|
@@ -25,6 +25,7 @@ import type { Plugin } from 'esbuild'
|
|
|
25
25
|
import type { ResolvedConfig } from '../../config'
|
|
26
26
|
import { rewriteSpecifierLiterals } from '../../resolve/scan-facts'
|
|
27
27
|
import { turbopackLoaderRules, turbopackResolveAlias, type WebpackLoaderRule } from './config'
|
|
28
|
+
import { outCachePath } from '../../out-paths'
|
|
28
29
|
|
|
29
30
|
interface LoaderFn {
|
|
30
31
|
(this: LoaderContext, content: string | Buffer): unknown
|
|
@@ -293,7 +294,7 @@ function resolveLoaderRequest(root: string, context: string, request: string): P
|
|
|
293
294
|
*/
|
|
294
295
|
function originalResourcePath(resourcePath: string, config: ResolvedConfig | undefined): string {
|
|
295
296
|
if (config) {
|
|
296
|
-
const cacheRoot = path.join(config.outPath, '
|
|
297
|
+
const cacheRoot = path.join(outCachePath(config.outPath), 'server')
|
|
297
298
|
const rel = path.relative(cacheRoot, resourcePath)
|
|
298
299
|
if (rel && !rel.startsWith('..') && !path.isAbsolute(rel)) {
|
|
299
300
|
const segments = rel.split(path.sep)
|
|
@@ -451,7 +452,7 @@ async function emitAssetResourceModule(
|
|
|
451
452
|
.basename(resourcePath, path.extname(resourcePath))
|
|
452
453
|
.replace(/[^A-Za-z0-9_-]+/g, '-')
|
|
453
454
|
const relative = path.posix.join('_next', 'static', 'media', `${base}.${hash}${ext}`)
|
|
454
|
-
const target = path.join(config.outPath, '
|
|
455
|
+
const target = path.join(config.outPath, 'static', ...relative.split('/'))
|
|
455
456
|
await mkdir(path.dirname(target), { recursive: true })
|
|
456
457
|
if (!existsSync(target)) await writeFile(target, bytes)
|
|
457
458
|
const src = `/${relative}`
|
|
@@ -128,7 +128,7 @@ async function workerAssetModuleSource(config: ResolvedConfig, file: string): Pr
|
|
|
128
128
|
source = `const src = ${JSON.stringify(src)};\nexport default { src };\nexport { src };\n`
|
|
129
129
|
}
|
|
130
130
|
for (const relative of emitted) {
|
|
131
|
-
const target = path.join(config.outPath, '
|
|
131
|
+
const target = path.join(config.outPath, 'static', ...relative.split('/'))
|
|
132
132
|
await mkdir(path.dirname(target), { recursive: true })
|
|
133
133
|
if (!existsSync(target)) await copyFile(sourcePath, target)
|
|
134
134
|
}
|
|
@@ -208,7 +208,7 @@ async function bundleWorkerEntry(config: ResolvedConfig, entry: string): Promise
|
|
|
208
208
|
const hash = createHash('sha256').update(output.contents).digest('hex').slice(0, 8)
|
|
209
209
|
const base = path.basename(entry, path.extname(entry)).replace(/[^A-Za-z0-9_-]+/g, '-')
|
|
210
210
|
const relative = path.posix.join('assets', 'workers', `${base}.${hash}.js`)
|
|
211
|
-
const target = path.join(config.outPath, '
|
|
211
|
+
const target = path.join(config.outPath, 'static', ...relative.split('/'))
|
|
212
212
|
await mkdir(path.dirname(target), { recursive: true })
|
|
213
213
|
await writeFile(target, output.contents)
|
|
214
214
|
return `/${relative}`
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { nextCompatEnabled } from '../compat/aliases'
|
|
4
|
+
import { productionRelease } from '../runtime/production'
|
|
4
5
|
import type { ResolvedConfig } from '../config'
|
|
5
6
|
import type { ResponseFinalizer, ResponseFinalizerContext } from '../extensions'
|
|
6
7
|
import { getNextConfig } from './next/config-loader'
|
|
@@ -31,7 +32,7 @@ export function cacheControlFinalizers(config: ResolvedConfig): ResponseFinalize
|
|
|
31
32
|
rules ??= loadCompatHeaders(config.root)
|
|
32
33
|
applyConfigHeaders(ctx, await rules, config.basePath)
|
|
33
34
|
applyPoweredByHeader(ctx)
|
|
34
|
-
pagesRevalidateRules ??= loadPagesRevalidateRules(config
|
|
35
|
+
pagesRevalidateRules ??= loadPagesRevalidateRules(config)
|
|
35
36
|
applyDefaultIsrHeader(ctx, pagesRevalidateRules)
|
|
36
37
|
}
|
|
37
38
|
return [finalizer]
|
|
@@ -139,20 +140,27 @@ function isBrowserCacheable(value: string): boolean {
|
|
|
139
140
|
return !/\bno-store\b|\bno-cache\b/i.test(value)
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
function loadPagesRevalidateRules(
|
|
143
|
+
function loadPagesRevalidateRules(config: ResolvedConfig): RevalidateRule[] {
|
|
144
|
+
const facts =
|
|
145
|
+
productionRelease(config)?.compat?.pagesRevalidate ?? pagesRevalidateFacts(config.root)
|
|
146
|
+
return facts.flatMap(([relative, revalidateSeconds]) => {
|
|
147
|
+
const regex = pagesRouteRegex(relative)
|
|
148
|
+
return regex ? [{ regex, revalidateSeconds }] : []
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Pages with a `getStaticProps` revalidate window: `[pages-relative file, seconds]`. */
|
|
153
|
+
export function pagesRevalidateFacts(root: string): [string, number][] {
|
|
143
154
|
const pagesDir = path.join(root, 'pages')
|
|
144
155
|
if (!existsSync(pagesDir)) return []
|
|
145
|
-
const
|
|
156
|
+
const facts: [string, number][] = []
|
|
146
157
|
for (const file of walkFiles(pagesDir)) {
|
|
147
158
|
const source = readFileSync(file, 'utf8')
|
|
148
159
|
if (!/\bgetStaticProps\b/.test(source)) continue
|
|
149
160
|
const match = /\brevalidate\s*:\s*(\d+)/.exec(source)
|
|
150
|
-
if (
|
|
151
|
-
const regex = pagesRouteRegex(path.relative(pagesDir, file))
|
|
152
|
-
if (!regex) continue
|
|
153
|
-
rules.push({ regex, revalidateSeconds: Number(match[1]) })
|
|
161
|
+
if (match?.[1]) facts.push([path.relative(pagesDir, file), Number(match[1])])
|
|
154
162
|
}
|
|
155
|
-
return
|
|
163
|
+
return facts
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
function walkFiles(dir: string): string[] {
|
|
@@ -65,7 +65,7 @@ export function inlineCssStylesheets(
|
|
|
65
65
|
): string[] | undefined {
|
|
66
66
|
if (options.dev || suppressed.getStore() === true || !inlineCssEnabled(config)) return undefined
|
|
67
67
|
const assets = options.assetNames.map(asset =>
|
|
68
|
-
readCss(`${config.outPath}/
|
|
68
|
+
readCss(`${config.outPath}/static/assets/${asset}`),
|
|
69
69
|
)
|
|
70
70
|
if (assets.some(css => css === undefined)) return undefined
|
|
71
71
|
const css = [options.prependCss, ...assets].filter(Boolean).join('\n')
|
|
@@ -4,10 +4,10 @@ import path from 'node:path'
|
|
|
4
4
|
import type { Plugin } from 'esbuild'
|
|
5
5
|
import type { ResolvedConfig } from '../../config'
|
|
6
6
|
import { resolveImport } from '../../resolve/imports'
|
|
7
|
-
import { hoistCssImports } from '../../css/build'
|
|
8
7
|
import { maybeLightningcssTransform } from './lightningcss'
|
|
9
8
|
import { escapeRegex } from '../../utils/code'
|
|
10
9
|
import { cssModuleScopePath } from '../../utils/fs'
|
|
10
|
+
import { productionRelease } from '../../runtime/production'
|
|
11
11
|
|
|
12
12
|
interface ComposeRef {
|
|
13
13
|
names: string[]
|
|
@@ -23,31 +23,44 @@ interface CssModuleInfo {
|
|
|
23
23
|
const pagesCompatIgnoredSourceEntries = new Set(['.next', '.pnext', 'app', 'node_modules', 'pages'])
|
|
24
24
|
|
|
25
25
|
export function materializeNextCssSources(config: ResolvedConfig) {
|
|
26
|
+
// A production release already compiled everything these links would let resolve.
|
|
27
|
+
if (productionRelease(config)) return
|
|
26
28
|
const generatedRoot = path.dirname(config.appPath)
|
|
27
29
|
if (path.basename(path.dirname(generatedRoot)) !== 'pnext-pages-compat') return
|
|
28
30
|
|
|
31
|
+
const outTop = path.relative(config.root, config.outRootPath).split(path.sep)[0]
|
|
32
|
+
// Inside the app (a build's output) links stay relative, naming no build-machine path.
|
|
33
|
+
const inApp = !path.relative(config.root, generatedRoot).startsWith('..')
|
|
29
34
|
for (const entry of readdirSync(config.root)) {
|
|
30
|
-
if (pagesCompatIgnoredSourceEntries.has(entry)) continue
|
|
35
|
+
if (pagesCompatIgnoredSourceEntries.has(entry) || entry === outTop) continue
|
|
31
36
|
const source = path.join(config.root, entry)
|
|
32
37
|
const target = path.join(generatedRoot, entry)
|
|
33
38
|
if (existsSync(target)) continue
|
|
34
39
|
try {
|
|
35
|
-
symlinkSync(
|
|
40
|
+
symlinkSync(
|
|
41
|
+
inApp ? path.relative(generatedRoot, source) : source,
|
|
42
|
+
target,
|
|
43
|
+
lstatSync(source).isDirectory() ? 'dir' : 'file',
|
|
44
|
+
)
|
|
36
45
|
} catch {
|
|
37
46
|
// A concurrent materialization may have linked the same source already.
|
|
38
47
|
}
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
50
|
|
|
51
|
+
let cssBuild: Promise<typeof import('../../css/build')> | undefined
|
|
52
|
+
|
|
42
53
|
export function nextCssModuleChunkPlugin(config: ResolvedConfig): Plugin {
|
|
43
54
|
return {
|
|
44
55
|
name: 'pnext-compat-css-modules',
|
|
45
56
|
setup(build) {
|
|
46
|
-
build.onLoad({ filter: /\.css$/ }, ({ path: file }) => {
|
|
57
|
+
build.onLoad({ filter: /\.css$/ }, async ({ path: file }) => {
|
|
47
58
|
const source = nextCssSource(file, config.root)
|
|
48
59
|
// This onLoad claims every `.css`, so core's directive-order plugin
|
|
49
60
|
// (registered after it) never sees a compat app's stylesheet — hoist here.
|
|
50
|
-
const raw =
|
|
61
|
+
const raw = (await (cssBuild ??= import('../../css/build'))).hoistCssImports(
|
|
62
|
+
readFileSync(source, 'utf8'),
|
|
63
|
+
)
|
|
51
64
|
const contents = file.endsWith('.module.css')
|
|
52
65
|
? transformCssModule(raw, source, config.root)
|
|
53
66
|
: rewriteTransparentBodyChildren(raw)
|
|
@@ -130,7 +130,7 @@ function collectOutputs(config: ResolvedConfig, manifest: BuildManifest): Adapte
|
|
|
130
130
|
const prerenderedRoutes = new Set<string>()
|
|
131
131
|
|
|
132
132
|
for (const [relative, metadata] of Object.entries(manifest.staticFiles ?? {})) {
|
|
133
|
-
const filePath = path.join(config.outPath, '
|
|
133
|
+
const filePath = path.join(config.outPath, 'static', relative)
|
|
134
134
|
// The manifest also records prerenders that produced no body on disk
|
|
135
135
|
// (an empty response, `_not-found` / `_global-error`). Those are not
|
|
136
136
|
// deployable artifacts: leave them out, and leave the owning route as a
|
|
@@ -42,7 +42,7 @@ export async function emitStaticExport({ config, manifest, log }: EmitStaticExpo
|
|
|
42
42
|
// the running server - client runtime code fetches it unconditionally, and Next's own asset-404 tests
|
|
43
43
|
// probe it as "a known valid asset path". Export mode additionally snapshots a standalone `out/` tree
|
|
44
44
|
// below; the manifest files it needs are the same bytes, so write the server-served copy first.
|
|
45
|
-
await log.step('build manifest', () => writeBuildManifests(path.join(config.outPath, '
|
|
45
|
+
await log.step('build manifest', () => writeBuildManifests(path.join(config.outPath, 'static')))
|
|
46
46
|
const output = getNextConfig().output
|
|
47
47
|
if (output === 'standalone') {
|
|
48
48
|
await emitStandalone({ config, manifest, log })
|
|
@@ -74,7 +74,7 @@ async function writeExportTree(config: ResolvedConfig, manifest: BuildManifest):
|
|
|
74
74
|
* can be pointed at their new location.
|
|
75
75
|
*/
|
|
76
76
|
async function copyRuntimeAssets(config: ResolvedConfig, outDir: string): Promise<Set<string>> {
|
|
77
|
-
const assetsDir = path.join(config.outPath, '
|
|
77
|
+
const assetsDir = path.join(config.outPath, 'static', 'assets')
|
|
78
78
|
const assets = new Set<string>()
|
|
79
79
|
for (const file of await listFiles(assetsDir)) {
|
|
80
80
|
const relative = toPosixPath(path.relative(assetsDir, file))
|
|
@@ -91,7 +91,7 @@ async function copyPublicTree(
|
|
|
91
91
|
outDir: string,
|
|
92
92
|
assets: ReadonlySet<string>,
|
|
93
93
|
): Promise<void> {
|
|
94
|
-
const publicDir = path.join(config.outPath, '
|
|
94
|
+
const publicDir = path.join(config.outPath, 'static')
|
|
95
95
|
for (const file of await listFiles(publicDir)) {
|
|
96
96
|
const relative = toPosixPath(path.relative(publicDir, file))
|
|
97
97
|
if (relative.startsWith('assets/')) continue
|
|
@@ -159,7 +159,7 @@ function exportPages(config: ResolvedConfig, manifest: BuildManifest): ExportPag
|
|
|
159
159
|
if (metadata.kind !== 'page' || !relative.endsWith('.html')) continue
|
|
160
160
|
const route = metadata.routeId ? routeById.get(metadata.routeId) : undefined
|
|
161
161
|
if (route?.kind !== 'page') continue
|
|
162
|
-
const htmlFile = path.join(config.outPath, '
|
|
162
|
+
const htmlFile = path.join(config.outPath, 'static', ...relative.split('/'))
|
|
163
163
|
pages.push({
|
|
164
164
|
route,
|
|
165
165
|
htmlFile,
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
// `output: 'standalone'` emitter (COMPAT).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// emitted `server.js` is a thin Node launcher that re-execs the real pnext server via Bun, pointed back
|
|
10
|
-
// at the original build root. The child prints the `- Local:` banner itself, which the launcher inherits
|
|
11
|
-
// straight onto its own stdout, so the harness's readiness regex fires without a proxy hop. The original
|
|
12
|
-
// build tree outlives the moved standalone folder for the duration of the test, so absolute references
|
|
13
|
-
// back into it are safe.
|
|
3
|
+
// Every pnext build writes `<outDir>/standalone/`, the self-contained server; with `output:
|
|
4
|
+
// 'standalone'` the out dir defaults to `.next` (compat/next/config-loader), so it lands where Next's
|
|
5
|
+
// does. Next's contract on top: a `server.js` that boots on PORT/HOSTNAME under `node server.js`, and
|
|
6
|
+
// the `.nft.json` traces its suites read. The e2e suites MOVE the folder to a fresh tmp dir, run
|
|
7
|
+
// `node server.js` and wait for the `- Local:` banner; `server.js` hands over to Bun, which serves the
|
|
8
|
+
// folder's own `server/entry.js`.
|
|
14
9
|
import { existsSync, readFileSync } from 'node:fs'
|
|
15
|
-
import { mkdir,
|
|
10
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
16
11
|
import path from 'node:path'
|
|
17
12
|
import type { ResolvedConfig } from '../../config'
|
|
18
13
|
import type { BuildManifest, RouteManifestEntry } from '../../types'
|
|
@@ -37,68 +32,38 @@ export async function emitStandalone({
|
|
|
37
32
|
}
|
|
38
33
|
|
|
39
34
|
async function writeStandalone(config: ResolvedConfig, manifest: BuildManifest): Promise<void> {
|
|
40
|
-
const standaloneDir =
|
|
41
|
-
await
|
|
42
|
-
await mkdir(standaloneDir, { recursive: true })
|
|
43
|
-
await writeServerEntry(config, standaloneDir)
|
|
35
|
+
const standaloneDir = config.outPath
|
|
36
|
+
await writeFile(path.join(standaloneDir, 'server.js'), standaloneServerSource())
|
|
44
37
|
await writeTraceFiles(config, standaloneDir)
|
|
45
38
|
await writeMiddlewareManifest(manifest, standaloneDir)
|
|
46
39
|
}
|
|
47
40
|
|
|
48
41
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
42
|
+
* Starts `server/entry.js` under Bun on the PORT/HOSTNAME the standalone contract passes through the
|
|
43
|
+
* environment. The child's `- Local:` banner is inherited onto this process's stdout, so the harness's
|
|
44
|
+
* readiness regex fires directly. Signals are forwarded so the harness's `killApp` (SIGTERM) tears the
|
|
45
|
+
* whole tree down and lets pending after() callbacks drain.
|
|
53
46
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
`${JSON.stringify({ name: 'pnext-standalone', version: '0.0.0', type: 'commonjs', private: true }, null, 2)}\n`,
|
|
58
|
-
)
|
|
59
|
-
await writeFile(path.join(standaloneDir, 'server.js'), standaloneServerSource(config))
|
|
60
|
-
}
|
|
47
|
+
function standaloneServerSource(): string {
|
|
48
|
+
return `// pnext standalone launcher, generated by pnext build (src/compat/export/standalone.ts).
|
|
49
|
+
import { spawn } from 'node:child_process';
|
|
61
50
|
|
|
62
|
-
|
|
63
|
-
* Boots `pnext start` under Bun against the original build root, on the
|
|
64
|
-
* PORT/HOSTNAME the standalone contract passes through the environment. The
|
|
65
|
-
* child's `- Local:` banner is inherited onto this process's stdout, so the
|
|
66
|
-
* harness's readiness regex fires directly. Signals are forwarded so the
|
|
67
|
-
* harness's `killApp` (SIGTERM) tears the whole tree down and lets pending
|
|
68
|
-
* after() callbacks drain.
|
|
69
|
-
*/
|
|
70
|
-
function standaloneServerSource(config: ResolvedConfig): string {
|
|
71
|
-
const cliPath = path.resolve(import.meta.dirname, '..', '..', 'cli', 'index.ts')
|
|
72
|
-
return `'use strict';
|
|
73
|
-
// pnext standalone launcher. Generated by pnext build; see
|
|
74
|
-
// src/compat/export/standalone.ts. Spawned as \`node server.js\` from the moved
|
|
75
|
-
// standalone directory; re-execs the real pnext server under Bun.
|
|
76
|
-
const { spawn } = require('node:child_process');
|
|
77
|
-
|
|
78
|
-
const PNEXT_CLI = ${JSON.stringify(cliPath)};
|
|
79
|
-
const PNEXT_ROOT = ${JSON.stringify(config.root)};
|
|
80
|
-
const port = String(process.env.PORT || '3000');
|
|
51
|
+
const port = Number(process.env.PORT || '3000');
|
|
81
52
|
const hostname = process.env.HOSTNAME || '0.0.0.0';
|
|
53
|
+
const entry = new URL('./server/entry.js', import.meta.url).href;
|
|
54
|
+
const boot = \`const { start } = await import(\${JSON.stringify(entry)}); await start(\${JSON.stringify({ port, hostname })});\`;
|
|
82
55
|
|
|
83
|
-
const child = spawn(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
BROWSER: 'none',
|
|
95
|
-
NODE_ENV: 'production',
|
|
96
|
-
PORT: port,
|
|
97
|
-
HOSTNAME: hostname,
|
|
98
|
-
},
|
|
99
|
-
stdio: ['ignore', 'inherit', 'inherit'],
|
|
100
|
-
}
|
|
101
|
-
);
|
|
56
|
+
const child = spawn('bun', ['--conditions=react-server', '-e', boot], {
|
|
57
|
+
env: {
|
|
58
|
+
...process.env,
|
|
59
|
+
// Suppresses \`pnext start\`'s "output: standalone" warning (Next gates the
|
|
60
|
+
// same warning on this private env being set by its standalone server).
|
|
61
|
+
__NEXT_PRIVATE_STANDALONE_CONFIG: '1',
|
|
62
|
+
BROWSER: 'none',
|
|
63
|
+
NODE_ENV: 'production',
|
|
64
|
+
},
|
|
65
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
66
|
+
});
|
|
102
67
|
|
|
103
68
|
child.on('error', (error) => {
|
|
104
69
|
console.error('pnext standalone: failed to start the pnext server:', error);
|
|
@@ -378,7 +378,7 @@ async function fetchUpstream(
|
|
|
378
378
|
}
|
|
379
379
|
const publicFile = await readPublicFile(
|
|
380
380
|
[
|
|
381
|
-
path.join(coreConfig.outPath, '
|
|
381
|
+
path.join(coreConfig.outPath, 'static'),
|
|
382
382
|
coreConfig.publicPath,
|
|
383
383
|
path.join(coreConfig.root, 'public'),
|
|
384
384
|
],
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { getWorkUnit } from '../../request/context'
|
|
12
12
|
import { getRequestRuntime } from '../../routing/request-environment'
|
|
13
|
-
import { selectRouteForRequest } from '../../routing/
|
|
13
|
+
import { selectRouteForRequest } from '../../routing/match'
|
|
14
14
|
import path from 'node:path'
|
|
15
15
|
import type { RouteManifestEntry } from '../../types'
|
|
16
16
|
import type { RequestErrorContext, RequestErrorInfo } from '../../extensions'
|
|
@@ -23,6 +23,7 @@ import { build } from '../../utils/esbuild'
|
|
|
23
23
|
import type { ResolvedConfig } from '../../config'
|
|
24
24
|
import { getNextConfig } from '../next/config-loader'
|
|
25
25
|
import { instrumentationLookupRoots } from './instrumentation'
|
|
26
|
+
import { outCachePath } from '../../out-paths'
|
|
26
27
|
|
|
27
28
|
const CLIENT_BASENAMES = [
|
|
28
29
|
'instrumentation-client.ts',
|
|
@@ -90,10 +91,10 @@ export async function buildInstrumentationClient(config: ResolvedConfig): Promis
|
|
|
90
91
|
const userFile = findInstrumentationClient(config)
|
|
91
92
|
if (!userFile) return
|
|
92
93
|
const modules = [...injectEntries(config), userFile]
|
|
93
|
-
const workDir = path.join(config.outPath, '
|
|
94
|
+
const workDir = path.join(outCachePath(config.outPath), 'instrumentation-client')
|
|
94
95
|
mkdirSync(workDir, { recursive: true })
|
|
95
96
|
const entryFile = path.join(workDir, 'entry.ts')
|
|
96
|
-
const outfile = path.join(config.outPath, '
|
|
97
|
+
const outfile = path.join(config.outPath, 'static', INSTRUMENTATION_CLIENT_ASSET)
|
|
97
98
|
mkdirSync(path.dirname(outfile), { recursive: true })
|
|
98
99
|
await Bun.write(entryFile, entrySource(modules))
|
|
99
100
|
const tsconfig = path.join(config.root, 'tsconfig.json')
|
|
@@ -116,7 +117,7 @@ let bundlePresence: boolean | undefined
|
|
|
116
117
|
|
|
117
118
|
/** Whether the built instrumentation-client bundle exists (cached). */
|
|
118
119
|
function hasInstrumentationClientBundle(config: ResolvedConfig): boolean {
|
|
119
|
-
bundlePresence ??= existsSync(path.join(config.outPath, '
|
|
120
|
+
bundlePresence ??= existsSync(path.join(config.outPath, 'static', INSTRUMENTATION_CLIENT_ASSET))
|
|
120
121
|
return bundlePresence
|
|
121
122
|
}
|
|
122
123
|
|
|
@@ -12,7 +12,15 @@
|
|
|
12
12
|
// separate module state) and calling its register() with NEXT_RUNTIME='edge' set for the duration.
|
|
13
13
|
// Apps without edge entities never get the pass.
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
existsSync,
|
|
17
|
+
mkdirSync,
|
|
18
|
+
readFileSync,
|
|
19
|
+
readdirSync,
|
|
20
|
+
rmSync,
|
|
21
|
+
statSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
} from 'node:fs'
|
|
16
24
|
import path from 'node:path'
|
|
17
25
|
import { pathToFileURL } from 'node:url'
|
|
18
26
|
import { createRequire } from 'node:module'
|
|
@@ -21,6 +29,7 @@ import { build } from '../../utils/esbuild'
|
|
|
21
29
|
import type { ResolvedConfig } from '../../config'
|
|
22
30
|
import { resolveExternalLoadTarget } from '../../resolve/imports'
|
|
23
31
|
import { compatAliases, reactServerLayerAliases } from '../aliases'
|
|
32
|
+
import { productionRelease } from '../../runtime/production'
|
|
24
33
|
|
|
25
34
|
const INSTRUMENTATION_BASENAMES = [
|
|
26
35
|
'instrumentation.ts',
|
|
@@ -136,38 +145,89 @@ async function importInstrumentation(
|
|
|
136
145
|
config: ResolvedConfig,
|
|
137
146
|
suffix = '',
|
|
138
147
|
): Promise<InstrumentationModule> {
|
|
139
|
-
const root = config.root
|
|
140
148
|
// Under config.outPath, so a dev server's scratch bundle lives in its own
|
|
141
149
|
// subtree and a concurrent build never removes it mid-import.
|
|
142
150
|
const outDir = path.join(config.outPath, 'instrumentation')
|
|
143
151
|
mkdirSync(outDir, { recursive: true })
|
|
144
152
|
const outfile = path.join(outDir, `instrumentation.${Date.now()}${suffix}.mjs`)
|
|
145
|
-
const tsconfig = path.join(root, 'tsconfig.json')
|
|
146
153
|
try {
|
|
147
|
-
await
|
|
148
|
-
entryPoints: [file],
|
|
149
|
-
outfile,
|
|
150
|
-
bundle: true,
|
|
151
|
-
platform: 'node',
|
|
152
|
-
format: 'esm',
|
|
153
|
-
target: 'esnext',
|
|
154
|
-
packages: 'external',
|
|
155
|
-
plugins: [instrumentationPlugin(root, config)],
|
|
156
|
-
...(existsSync(tsconfig) ? { tsconfig } : {}),
|
|
157
|
-
define: {
|
|
158
|
-
__dirname: JSON.stringify(path.dirname(file)),
|
|
159
|
-
__filename: JSON.stringify(file),
|
|
160
|
-
'import.meta.url': JSON.stringify(pathToFileURL(file).href),
|
|
161
|
-
},
|
|
162
|
-
logLevel: 'silent',
|
|
163
|
-
sourcemap: false,
|
|
164
|
-
})
|
|
154
|
+
await bundleInstrumentation(file, config, outfile)
|
|
165
155
|
return (await import(pathToFileURL(outfile).href)) as InstrumentationModule
|
|
166
156
|
} finally {
|
|
167
157
|
rmSync(outfile, { force: true })
|
|
168
158
|
}
|
|
169
159
|
}
|
|
170
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Bundle instrumentation for a production release: the node instance, plus a separate edge instance
|
|
163
|
+
* file when the app has edge entities. Out-relative paths, or undefined when the app has none.
|
|
164
|
+
*/
|
|
165
|
+
export async function emitReleaseInstrumentation(config: ResolvedConfig, outDir: string) {
|
|
166
|
+
const file = findInstrumentation(config)
|
|
167
|
+
if (!file) return undefined
|
|
168
|
+
const node = await releaseInstrumentation(file, config, outDir, 'instrumentation')
|
|
169
|
+
if (!appHasEdgeEntities(config)) return { file: path.relative(config.outPath, node) }
|
|
170
|
+
const edge = await releaseInstrumentation(file, config, outDir, 'instrumentation.edge')
|
|
171
|
+
return { file: path.relative(config.outPath, node), edge: path.relative(config.outPath, edge) }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** One release instance: located relative to itself, named by its content (a new generation never reuses a module). */
|
|
175
|
+
async function releaseInstrumentation(
|
|
176
|
+
file: string,
|
|
177
|
+
config: ResolvedConfig,
|
|
178
|
+
outDir: string,
|
|
179
|
+
name: string,
|
|
180
|
+
) {
|
|
181
|
+
const temporary = path.join(outDir, `${name}.${process.pid}.tmp.mjs`)
|
|
182
|
+
await bundleInstrumentation(file, config, temporary, outDir)
|
|
183
|
+
const { relocateReleaseBundle } = await import('../../runtime/modules')
|
|
184
|
+
const contents = relocateReleaseBundle(config, temporary, readFileSync(temporary, 'utf8'))
|
|
185
|
+
rmSync(temporary, { force: true })
|
|
186
|
+
const outfile = path.join(outDir, `${name}.${Bun.hash(contents).toString(36)}.mjs`)
|
|
187
|
+
writeFileSync(outfile, contents)
|
|
188
|
+
return outfile
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function bundleInstrumentation(
|
|
192
|
+
file: string,
|
|
193
|
+
config: ResolvedConfig,
|
|
194
|
+
outfile: string,
|
|
195
|
+
releaseDir?: string,
|
|
196
|
+
) {
|
|
197
|
+
const root = config.root
|
|
198
|
+
const tsconfig = path.join(root, 'tsconfig.json')
|
|
199
|
+
// A release instance finds its source relative to itself, never at the build machine's path.
|
|
200
|
+
const sourceUrl = releaseDir
|
|
201
|
+
? `new URL(${JSON.stringify(path.relative(releaseDir, file).split(path.sep).join('/'))}, import.meta.url).href`
|
|
202
|
+
: JSON.stringify(pathToFileURL(file).href)
|
|
203
|
+
await build({
|
|
204
|
+
entryPoints: [file],
|
|
205
|
+
outfile,
|
|
206
|
+
bundle: true,
|
|
207
|
+
platform: 'node',
|
|
208
|
+
format: 'esm',
|
|
209
|
+
target: 'esnext',
|
|
210
|
+
packages: 'external',
|
|
211
|
+
plugins: [instrumentationPlugin(root, config)],
|
|
212
|
+
...(existsSync(tsconfig) ? { tsconfig } : {}),
|
|
213
|
+
banner: {
|
|
214
|
+
js:
|
|
215
|
+
'import { fileURLToPath as __pnextFileURLToPath } from "node:url";\n' +
|
|
216
|
+
'import { dirname as __pnextDirname } from "node:path";\n' +
|
|
217
|
+
`const __pnextSourceUrl = ${sourceUrl};\n` +
|
|
218
|
+
'const __pnextSourceFile = __pnextFileURLToPath(__pnextSourceUrl);\n' +
|
|
219
|
+
'const __pnextSourceDir = __pnextDirname(__pnextSourceFile);',
|
|
220
|
+
},
|
|
221
|
+
define: {
|
|
222
|
+
__dirname: '__pnextSourceDir',
|
|
223
|
+
__filename: '__pnextSourceFile',
|
|
224
|
+
'import.meta.url': '__pnextSourceUrl',
|
|
225
|
+
},
|
|
226
|
+
logLevel: 'silent',
|
|
227
|
+
sourcemap: false,
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
171
231
|
/**
|
|
172
232
|
* Load instrumentation and run register() once. Idempotent: repeated calls
|
|
173
233
|
* (build + start both run init hooks) reuse the first load. Returns immediately;
|
|
@@ -175,6 +235,11 @@ async function importInstrumentation(
|
|
|
175
235
|
*/
|
|
176
236
|
export function loadInstrumentation(config: ResolvedConfig): void {
|
|
177
237
|
if (readyGate) return
|
|
238
|
+
const released = productionRelease(config)
|
|
239
|
+
if (released) {
|
|
240
|
+
readyGate = registerReleased(released.instrumentation)
|
|
241
|
+
return
|
|
242
|
+
}
|
|
178
243
|
const file = findInstrumentation(config)
|
|
179
244
|
if (!file) {
|
|
180
245
|
readyGate = Promise.resolve()
|
|
@@ -197,21 +262,49 @@ export function loadInstrumentation(config: ResolvedConfig): void {
|
|
|
197
262
|
})()
|
|
198
263
|
}
|
|
199
264
|
|
|
265
|
+
/** A release's prebuilt instrumentation: register() on the node instance, then the edge instance. */
|
|
266
|
+
async function registerReleased(instrumentation: { file?: string; edge?: string } | undefined) {
|
|
267
|
+
if (!instrumentation?.file) return
|
|
268
|
+
try {
|
|
269
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
270
|
+
if (!process.env.NEXT_RUNTIME) process.env.NEXT_RUNTIME = 'nodejs'
|
|
271
|
+
loaded = (await import(pathToFileURL(instrumentation.file).href)) as InstrumentationModule
|
|
272
|
+
await loaded.register?.()
|
|
273
|
+
if (instrumentation.edge) {
|
|
274
|
+
await withEdgeRuntime(async () => {
|
|
275
|
+
const edgeInstance = (await import(
|
|
276
|
+
pathToFileURL(instrumentation.edge!).href
|
|
277
|
+
)) as InstrumentationModule
|
|
278
|
+
await edgeInstance.register?.()
|
|
279
|
+
}, 'instrumentation register() (edge pass) failed:')
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error('instrumentation register() failed:', error)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
200
286
|
/**
|
|
201
287
|
* The edge boot pass: a fresh instrumentation instance registered with NEXT_RUNTIME='edge' for the
|
|
202
288
|
* duration of the call. A double provider registration is harmless - @opentelemetry/api rejects a second
|
|
203
289
|
* global registration and keeps the first.
|
|
204
290
|
*/
|
|
205
291
|
async function runEdgeRegisterPass(file: string, config: ResolvedConfig): Promise<void> {
|
|
292
|
+
await withEdgeRuntime(async () => {
|
|
293
|
+
const edgeInstance = await importInstrumentation(file, config, '.edge')
|
|
294
|
+
await edgeInstance.register?.()
|
|
295
|
+
}, 'instrumentation register() (edge pass) failed:')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Run `task` with NEXT_RUNTIME='edge', restoring the previous value. */
|
|
299
|
+
async function withEdgeRuntime(task: () => Promise<void>, failure: string): Promise<void> {
|
|
206
300
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
207
301
|
const previous = process.env.NEXT_RUNTIME
|
|
208
302
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
209
303
|
process.env.NEXT_RUNTIME = 'edge'
|
|
210
304
|
try {
|
|
211
|
-
|
|
212
|
-
await edgeInstance.register?.()
|
|
305
|
+
await task()
|
|
213
306
|
} catch (error) {
|
|
214
|
-
console.error(
|
|
307
|
+
console.error(failure, error)
|
|
215
308
|
} finally {
|
|
216
309
|
if (previous === undefined) {
|
|
217
310
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|