@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
|
@@ -3,8 +3,9 @@ import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync }
|
|
|
3
3
|
import { builtinModules } from 'node:module'
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
|
-
import { DEFAULT_OUT_DIR, pathToFileHref } from '../../config'
|
|
6
|
+
import { DEFAULT_OUT_DIR, devOutSegment, pathToFileHref } from '../../config'
|
|
7
7
|
import type { ResolvedConfig } from '../../config'
|
|
8
|
+
import { compiledClientReferenceFiles } from '../../client/reference'
|
|
8
9
|
import { globalCssSources } from '../../css/build'
|
|
9
10
|
import { getImportAliasExtensions } from '../../extensions'
|
|
10
11
|
import { nextCompatEnabled } from '../../render/hooks'
|
|
@@ -14,6 +15,15 @@ import { resolveImport, workspacePackageRoots } from '../../resolve/imports'
|
|
|
14
15
|
import { findProxyFile, proxyRoutePatterns, type ProxyModule } from '../../routing/proxy'
|
|
15
16
|
import { cacheRoot } from '../boot/named-bin'
|
|
16
17
|
import { startWarmChild, type WarmChild } from './vercel-warm'
|
|
18
|
+
import {
|
|
19
|
+
immutableAssetPath,
|
|
20
|
+
immutableAssetPrefixes,
|
|
21
|
+
immutableCacheControl,
|
|
22
|
+
} from '../serve/immutable'
|
|
23
|
+
import { frameworkFingerprint } from '../../runtime/fingerprint'
|
|
24
|
+
import { readPrebundleStamp, runtimeEntryDirs, runtimeEntryFiles } from '../../runtime/prebundle'
|
|
25
|
+
import { buildIndexFile, readBuildIndex, releaseSourceFile } from '../../runtime/production'
|
|
26
|
+
import { compiledSourceGraph, flushDevModuleCaches } from '../../runtime/module-cache'
|
|
17
27
|
import { escapeRegex } from '../../utils/code'
|
|
18
28
|
import { listFiles, toPosixPath, writeText } from '../../utils/fs'
|
|
19
29
|
import { createVerboseLogger, type VerboseLogger } from '../../utils/verbose'
|
|
@@ -71,8 +81,14 @@ const droppedFileSuffixes = [
|
|
|
71
81
|
interface PackRules {
|
|
72
82
|
prunedDirs: Set<string>
|
|
73
83
|
droppedSuffixes: string[]
|
|
84
|
+
/** Absolute app sources the release compiled: dropped unless `adapter.keep` names them. */
|
|
85
|
+
compiled: Set<string>
|
|
86
|
+
/** `adapter.keep` entries: names and `.suffix`es that always ship. */
|
|
87
|
+
keep: Set<string>
|
|
74
88
|
/** Absolute sources exempt from the prune list — the app's own build output. */
|
|
75
89
|
keepPaths: Set<string>
|
|
90
|
+
/** Absolute sources never shipped: the dev server's `<outRoot>/dev`, which a build leaves in place. */
|
|
91
|
+
devPaths: Set<string>
|
|
76
92
|
}
|
|
77
93
|
|
|
78
94
|
// Test seam: the packing suite builds one app both ways and diffs the trees,
|
|
@@ -89,13 +105,24 @@ export function setPackPruningEnabled(enabled: boolean) {
|
|
|
89
105
|
}
|
|
90
106
|
|
|
91
107
|
function packRules(config: ResolvedConfig): PackRules {
|
|
108
|
+
// An out dir inside a dev path (`outDir: '.pnext/dev'`) is the production output and must ship.
|
|
109
|
+
const devPaths = new Set(
|
|
110
|
+
[config.outRootPath, path.resolve(config.root, DEFAULT_OUT_DIR)]
|
|
111
|
+
.map(root => path.resolve(root, devOutSegment))
|
|
112
|
+
.filter(dev => !isInsideDir(dev, config.outPath)),
|
|
113
|
+
)
|
|
114
|
+
// Materialized pages sources: the release serves their compiled artifacts.
|
|
115
|
+
devPaths.add(path.join(config.outRootPath, 'pnext-pages-compat'))
|
|
92
116
|
if (!packPruningEnabled) {
|
|
93
117
|
return {
|
|
94
118
|
// The two the function could never resolve through stay pruned even
|
|
95
119
|
// here: a nested store or object database is not a packing choice.
|
|
96
120
|
prunedDirs: new Set(['node_modules', '.git']),
|
|
97
121
|
droppedSuffixes: [],
|
|
122
|
+
compiled: new Set(),
|
|
123
|
+
keep: new Set(),
|
|
98
124
|
keepPaths: new Set([path.resolve(config.outPath)]),
|
|
125
|
+
devPaths,
|
|
99
126
|
}
|
|
100
127
|
}
|
|
101
128
|
const keep = new Set(config.adapter?.keep ?? [])
|
|
@@ -110,11 +137,14 @@ function packRules(config: ResolvedConfig): PackRules {
|
|
|
110
137
|
droppedSuffixes: [...droppedFileSuffixes, ...extra.filter(isSuffix)].filter(
|
|
111
138
|
suffix => !keep.has(suffix),
|
|
112
139
|
),
|
|
140
|
+
compiled: new Set(),
|
|
141
|
+
keep,
|
|
113
142
|
// The app's outDir shares its name with the prune list; it holds the
|
|
114
143
|
// compiled module cache the function serves from and must survive. The
|
|
115
144
|
// default out root goes with it: a `distDir` app moved its output away, but
|
|
116
145
|
// the next.config bundle the function imports at boot still lives there.
|
|
117
146
|
keepPaths: new Set([path.resolve(config.outPath), path.resolve(config.root, DEFAULT_OUT_DIR)]),
|
|
147
|
+
devPaths,
|
|
118
148
|
}
|
|
119
149
|
}
|
|
120
150
|
|
|
@@ -139,12 +169,60 @@ function withinKeepPath(pack: PackRules, source: string) {
|
|
|
139
169
|
* that would pull the whole store into the function.
|
|
140
170
|
*/
|
|
141
171
|
function shipsDir(pack: PackRules, name: string, source: string, isLink = false) {
|
|
172
|
+
if (pack.devPaths.has(path.resolve(source))) return false
|
|
142
173
|
if (!pack.prunedDirs.has(name)) return true
|
|
143
174
|
return !isLink && withinKeepPath(pack, source)
|
|
144
175
|
}
|
|
145
176
|
|
|
146
|
-
function shipsFile(pack: PackRules, name: string) {
|
|
147
|
-
|
|
177
|
+
function shipsFile(pack: PackRules, name: string, source: string) {
|
|
178
|
+
if (pack.droppedSuffixes.some(suffix => name.endsWith(suffix))) return false
|
|
179
|
+
if (!pack.compiled.has(path.resolve(source)) || withinKeepPath(pack, source)) return true
|
|
180
|
+
return [...pack.keep].some(
|
|
181
|
+
entry => name === entry || (entry.startsWith('.') && name.endsWith(entry)),
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* App sources a release compiled into its output: the closure of `build-index.json`'s modules over the
|
|
187
|
+
* compile graph, plus the proxy, instrumentation and config it froze. Anything else may be read at
|
|
188
|
+
* request time and ships.
|
|
189
|
+
*/
|
|
190
|
+
function releaseCompiledSources(config: ResolvedConfig) {
|
|
191
|
+
flushDevModuleCaches()
|
|
192
|
+
const index = readBuildIndex(config.outPath)
|
|
193
|
+
const graph = compiledSourceGraph(config.outPath, config.workspaceRoot)
|
|
194
|
+
const queue = Object.keys(index.modules).map(key =>
|
|
195
|
+
releaseSourceFile(
|
|
196
|
+
key.slice(key.indexOf(':', key.indexOf(':') + 1) + 1),
|
|
197
|
+
config.root,
|
|
198
|
+
config.workspaceRoot,
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
if (index.proxy) queue.push(path.resolve(config.root, index.proxy.file))
|
|
202
|
+
const script = /\.(?:[cm]?[jt]s|[jt]sx)$/
|
|
203
|
+
const frozen = (dir: string, pattern: RegExp) =>
|
|
204
|
+
(readDirEntries(dir) ?? [])
|
|
205
|
+
.filter(entry => pattern.test(entry.name) && script.test(entry.name))
|
|
206
|
+
.forEach(entry => queue.push(path.join(dir, entry.name)))
|
|
207
|
+
frozen(config.root, /^(?:pnext|next)\.config\./)
|
|
208
|
+
if (index.instrumentation) {
|
|
209
|
+
for (const dir of [config.root, path.join(config.root, 'src')])
|
|
210
|
+
frozen(dir, /^instrumentation\./)
|
|
211
|
+
}
|
|
212
|
+
const compiled = new Set<string>()
|
|
213
|
+
for (const file of queue) {
|
|
214
|
+
if (compiled.has(file)) continue
|
|
215
|
+
compiled.add(file)
|
|
216
|
+
let real = file
|
|
217
|
+
try {
|
|
218
|
+
real = realpathSync(file)
|
|
219
|
+
} catch {
|
|
220
|
+
continue
|
|
221
|
+
}
|
|
222
|
+
compiled.add(real)
|
|
223
|
+
queue.push(...(graph.get(file) ?? []), ...(graph.get(real) ?? []))
|
|
224
|
+
}
|
|
225
|
+
return compiled
|
|
148
226
|
}
|
|
149
227
|
|
|
150
228
|
interface VercelConfig {
|
|
@@ -156,6 +234,7 @@ interface VercelConfig {
|
|
|
156
234
|
methods?: string[]
|
|
157
235
|
headers?: Record<string, string>
|
|
158
236
|
continue?: boolean
|
|
237
|
+
important?: boolean
|
|
159
238
|
}
|
|
160
239
|
| { handle: 'filesystem' }
|
|
161
240
|
)[]
|
|
@@ -184,7 +263,10 @@ export async function writeVercelOutput(
|
|
|
184
263
|
const warmedModulesEarly = new Promise<string[]>(resolve => {
|
|
185
264
|
resolveWarmedModules = resolve
|
|
186
265
|
})
|
|
187
|
-
const warmSettled = warm.finish(log, modules => resolveWarmedModules(modules)
|
|
266
|
+
const warmSettled = warm.finish(log, modules => resolveWarmedModules(modules), {
|
|
267
|
+
globalCss: globalCssSources(config),
|
|
268
|
+
clientReferences: [...compiledClientReferenceFiles()],
|
|
269
|
+
})
|
|
188
270
|
// Nothing awaits it until writeServerFunction's copy step; park the
|
|
189
271
|
// rejection so it never surfaces as unhandled in between (it never actually
|
|
190
272
|
// rejects — warmWithRestarts catches everything itself — but the gap
|
|
@@ -213,7 +295,7 @@ export async function writeVercelOutput(
|
|
|
213
295
|
// server function: served, but at function cost with no edge cache.
|
|
214
296
|
...compatStaticRewrite(config, outputPath),
|
|
215
297
|
// Every content-hashed build asset, exactly the set `pnext start` serves immutable.
|
|
216
|
-
await
|
|
298
|
+
...(await immutableAssetRoutes(path.join(config.outPath, 'public'), manifest.publicAssets)),
|
|
217
299
|
// Proxy-matched paths go to the server function before the CDN filesystem
|
|
218
300
|
// check — `pnext start` runs the proxy ahead of static files too.
|
|
219
301
|
...(await proxyRoutes(config)),
|
|
@@ -281,7 +363,8 @@ async function proxyRoutes(config: ResolvedConfig) {
|
|
|
281
363
|
const proxyFile = findProxyFile(config)
|
|
282
364
|
if (!proxyFile) return []
|
|
283
365
|
const proxyModule = (await import(pathToFileHref(proxyFile))) as ProxyModule
|
|
284
|
-
|
|
366
|
+
// Percent-encoded paths and repeated slashes go to the function, which decodes or 308s them.
|
|
367
|
+
return [...proxyRoutePatterns(proxyModule.config), '^.*(?:%|//).*$'].map(src => ({
|
|
285
368
|
src,
|
|
286
369
|
dest: `/${SERVER_FUNCTION}`,
|
|
287
370
|
}))
|
|
@@ -305,14 +388,18 @@ async function writeServerFunction(
|
|
|
305
388
|
const pack = packRules(config)
|
|
306
389
|
const framework = await resolveFrameworkPackage(workspaceRoot)
|
|
307
390
|
const { root: pnextRoot, inWorkspace: pnextInWorkspace, targetRel: pnextTargetRel } = framework
|
|
391
|
+
const release = releaseEntries(config, manifest)
|
|
392
|
+
// A release served by the framework's prebundle needs none of its other source.
|
|
393
|
+
const prebundle = release ? readPrebundleStamp(pnextRoot, frameworkFingerprint()) : undefined
|
|
308
394
|
const closure = await traceNodeModulesClosure(
|
|
309
395
|
config,
|
|
310
396
|
manifest,
|
|
311
397
|
functionPath,
|
|
312
398
|
framework,
|
|
313
|
-
warmedModules,
|
|
399
|
+
[...warmedModules, ...(release ?? [])],
|
|
314
400
|
pack,
|
|
315
401
|
log,
|
|
402
|
+
Boolean(release),
|
|
316
403
|
)
|
|
317
404
|
|
|
318
405
|
const replicaPathFor = (file: string) => {
|
|
@@ -338,17 +425,16 @@ async function writeServerFunction(
|
|
|
338
425
|
for (const relative of closure.workspacePackages) {
|
|
339
426
|
neededRoots.add(path.resolve(workspaceRoot, relative))
|
|
340
427
|
}
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
428
|
+
// Without a release the server compiles app source at request time: the renderer re-resolves the
|
|
429
|
+
// root layout's global css imports, and a compat compile resolves the shipped sources' imports for
|
|
430
|
+
// real, so the packages behind them and the declared workspace dependencies must be present.
|
|
431
|
+
if (!release) {
|
|
432
|
+
for (const file of globalCssSources(config)) {
|
|
433
|
+
const root = packageRoots.find(candidate => isInsideDir(candidate, file))
|
|
434
|
+
if (root) neededRoots.add(root)
|
|
435
|
+
}
|
|
436
|
+
addWorkspaceDependencies(neededRoots, packageRoots, [path.resolve(config.root), ...neededRoots])
|
|
346
437
|
}
|
|
347
|
-
// Tracing sees what the *server* loaded, which is not everything the shipped source can still ask
|
|
348
|
-
// for: the app's own sources travel with the function and a compat compile at request time resolves
|
|
349
|
-
// their imports for real. A workspace package one of them names but no traced module reached would
|
|
350
|
-
// not be here, so close over the declared workspace dependencies too.
|
|
351
|
-
addWorkspaceDependencies(neededRoots, packageRoots, [path.resolve(config.root), ...neededRoots])
|
|
352
438
|
neededRoots.delete(path.resolve(config.root))
|
|
353
439
|
neededRoots.delete(pnextRoot)
|
|
354
440
|
|
|
@@ -364,16 +450,22 @@ async function writeServerFunction(
|
|
|
364
450
|
await log.step(`copy function tree (${closure.packageCount} packages, ${roots} roots)`, () =>
|
|
365
451
|
Promise.all([
|
|
366
452
|
closure.copy(),
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
453
|
+
// A release ships the app tree minus what it compiled: request code may read files beside
|
|
454
|
+
// its source. `public` is served by the CDN, never from the function; the rest are named
|
|
455
|
+
// again because the app root is the one tree whose build output ships, so it
|
|
456
|
+
// cannot rely on the depth-wise prune alone.
|
|
457
|
+
copyTree(
|
|
458
|
+
config.root,
|
|
459
|
+
path.join(functionPath, appRel),
|
|
460
|
+
release ? { ...pack, compiled: releaseCompiledSources(config) } : pack,
|
|
461
|
+
['public', '.vercel', '.next', '.turbo'],
|
|
462
|
+
),
|
|
463
|
+
copyPackageTree(
|
|
464
|
+
pnextRoot,
|
|
465
|
+
path.join(functionPath, pnextTargetRel),
|
|
466
|
+
pack,
|
|
467
|
+
prebundle && ['config', 'dist', ...prebundle.source],
|
|
468
|
+
),
|
|
377
469
|
...[...neededRoots].map(packageRoot =>
|
|
378
470
|
copyPackageTree(
|
|
379
471
|
packageRoot,
|
|
@@ -407,7 +499,9 @@ async function writeServerFunction(
|
|
|
407
499
|
injectCompatPaths(config, functionPath, pnextRoot, replicaPathFor),
|
|
408
500
|
)
|
|
409
501
|
|
|
410
|
-
const startEntry = toPosixPath(
|
|
502
|
+
const startEntry = toPosixPath(
|
|
503
|
+
path.join(pnextTargetRel, prebundle ? 'dist/server/cli/start.js' : 'src/cli/start.ts'),
|
|
504
|
+
)
|
|
411
505
|
await writeText(
|
|
412
506
|
path.join(functionPath, 'index.mjs'),
|
|
413
507
|
`import path from 'node:path';
|
|
@@ -544,7 +638,7 @@ async function copyTree(
|
|
|
544
638
|
visited.add(link.path)
|
|
545
639
|
return copyTree(link.path, target, pack, [], visited)
|
|
546
640
|
}
|
|
547
|
-
return shipsFile(pack, entry.name) ? linkOrCopyFile(link.path, target) : undefined
|
|
641
|
+
return shipsFile(pack, entry.name, source) ? linkOrCopyFile(link.path, target) : undefined
|
|
548
642
|
}
|
|
549
643
|
// One syscall for the whole subtree beats one per file — the excluded
|
|
550
644
|
// names are stripped from the copy afterwards.
|
|
@@ -552,7 +646,8 @@ async function copyTree(
|
|
|
552
646
|
return normalizeClone(target, source, pack, visited)
|
|
553
647
|
}
|
|
554
648
|
if (entry.isDirectory()) return copyTree(source, target, pack, [], visited)
|
|
555
|
-
if (entry.isFile() && shipsFile(pack, entry.name
|
|
649
|
+
if (entry.isFile() && shipsFile(pack, entry.name, source))
|
|
650
|
+
return linkOrCopyFile(source, target)
|
|
556
651
|
}),
|
|
557
652
|
)
|
|
558
653
|
}
|
|
@@ -631,19 +726,20 @@ async function normalizeClone(
|
|
|
631
726
|
if (!shipsDir(pack, entry.name, source, entry.isSymbolicLink())) {
|
|
632
727
|
rmSync(full, { recursive: true, force: true })
|
|
633
728
|
} else if (entry.isSymbolicLink()) {
|
|
634
|
-
|
|
729
|
+
// From the source: a relative link in the clone would resolve against the function tree.
|
|
730
|
+
const link = resolveLinkTarget(source)
|
|
635
731
|
rmSync(full, { force: true })
|
|
636
732
|
if (!link) continue
|
|
637
733
|
if (link.isDirectory) {
|
|
638
734
|
if (visited.has(link.path)) continue
|
|
639
735
|
visited.add(link.path)
|
|
640
736
|
pending.push(copyTree(link.path, full, pack, [], visited))
|
|
641
|
-
} else if (shipsFile(pack, entry.name)) {
|
|
737
|
+
} else if (shipsFile(pack, entry.name, source)) {
|
|
642
738
|
pending.push(linkOrCopyFile(link.path, full))
|
|
643
739
|
}
|
|
644
740
|
} else if (entry.isDirectory()) {
|
|
645
741
|
stack.push([full, source])
|
|
646
|
-
} else if (!shipsFile(pack, entry.name)) {
|
|
742
|
+
} else if (!shipsFile(pack, entry.name, source)) {
|
|
647
743
|
rmSync(full, { force: true })
|
|
648
744
|
}
|
|
649
745
|
}
|
|
@@ -703,10 +799,10 @@ const packageCopyExcludes = [
|
|
|
703
799
|
* Copies a workspace package the way npm would publish it: a `files` list is the package's own
|
|
704
800
|
* statement of what it ships, so it beats guessing at build-time directory names. Glob entries fall
|
|
705
801
|
* back to the exclude list - matching npm's glob semantics is not worth it for a packaging copy.
|
|
802
|
+
* `only` names a narrower list.
|
|
706
803
|
*/
|
|
707
|
-
async function copyPackageTree(from: string, to: string, pack: PackRules) {
|
|
708
|
-
const
|
|
709
|
-
const files = packageJson?.files
|
|
804
|
+
async function copyPackageTree(from: string, to: string, pack: PackRules, only?: string[]) {
|
|
805
|
+
const files = only ?? (await readPackageJson(from))?.files
|
|
710
806
|
if (!files?.length || files.some(entry => /[*?[\]{}!]/.test(entry))) {
|
|
711
807
|
return copyTree(from, to, pack, packageCopyExcludes)
|
|
712
808
|
}
|
|
@@ -721,7 +817,8 @@ async function copyPackageTree(from: string, to: string, pack: PackRules) {
|
|
|
721
817
|
const stats = statSync(source, { throwIfNoEntry: false })
|
|
722
818
|
if (!stats) return
|
|
723
819
|
if (stats.isDirectory()) return copyTree(source, path.join(to, name), pack)
|
|
724
|
-
if (!shipsFile(pack, name)) return
|
|
820
|
+
if (!shipsFile(pack, name, source)) return
|
|
821
|
+
await mkdir(path.dirname(path.join(to, name)), { recursive: true })
|
|
725
822
|
return linkOrCopyFile(source, path.join(to, name))
|
|
726
823
|
}),
|
|
727
824
|
)
|
|
@@ -958,10 +1055,15 @@ async function traceNodeModulesClosure(
|
|
|
958
1055
|
warmedModules: string[],
|
|
959
1056
|
pack: PackRules,
|
|
960
1057
|
log: VerboseLogger,
|
|
1058
|
+
// A release imports only build output, so its closure is traced from that alone.
|
|
1059
|
+
release = false,
|
|
961
1060
|
) {
|
|
962
1061
|
const workspaceRoot = config.workspaceRoot
|
|
963
1062
|
const specifiers = new Set<string>()
|
|
964
1063
|
const tracedFiles = new Set<string>()
|
|
1064
|
+
// Package directories compiled modules import by absolute href (natively loaded server
|
|
1065
|
+
// dependencies, externals). One outside the top-level node_modules ships where it is.
|
|
1066
|
+
const hrefPackageDirs = new Set<string>()
|
|
965
1067
|
// Compat-aliased specifiers whose target lives in the framework source
|
|
966
1068
|
// (react, next/*) never resolve from node_modules at runtime — shipping
|
|
967
1069
|
// them would drag in the full next/react trees. Aliases that point into
|
|
@@ -972,7 +1074,8 @@ async function traceNodeModulesClosure(
|
|
|
972
1074
|
await log.step('trace runtime imports', async () => {
|
|
973
1075
|
// Only code Bun imports raw at request time needs real node_modules: route handlers, the proxy,
|
|
974
1076
|
// the config chain, and the compiled modules the warm step just wrote. Pages resolve through that
|
|
975
|
-
// compiled cache
|
|
1077
|
+
// compiled cache; what it does not vendor (server dependencies Bun loads natively, externals) it
|
|
1078
|
+
// imports by absolute href, and those packages ship with their dependency closure below.
|
|
976
1079
|
const queue: string[] = []
|
|
977
1080
|
const seen = tracedFiles
|
|
978
1081
|
const enqueue = (file: string | undefined) => {
|
|
@@ -983,12 +1086,14 @@ async function traceNodeModulesClosure(
|
|
|
983
1086
|
queue.push(resolved)
|
|
984
1087
|
}
|
|
985
1088
|
|
|
986
|
-
|
|
987
|
-
|
|
1089
|
+
if (!release) {
|
|
1090
|
+
for (const route of manifest.routes) {
|
|
1091
|
+
if (route.kind === 'handler') enqueue(route.file)
|
|
1092
|
+
}
|
|
1093
|
+
enqueue(findProxyFile(config) ?? undefined)
|
|
1094
|
+
enqueue(path.join(config.root, 'pnext.config.ts'))
|
|
1095
|
+
enqueue(path.join(config.root, 'next.config.js'))
|
|
988
1096
|
}
|
|
989
|
-
enqueue(findProxyFile(config) ?? undefined)
|
|
990
|
-
enqueue(path.join(config.root, 'pnext.config.ts'))
|
|
991
|
-
enqueue(path.join(config.root, 'next.config.js'))
|
|
992
1097
|
for (const file of warmedModules) enqueue(file)
|
|
993
1098
|
|
|
994
1099
|
const visit = async (file: string) => {
|
|
@@ -1001,10 +1106,14 @@ async function traceNodeModulesClosure(
|
|
|
1001
1106
|
// external — by absolute href. Follow the ones inside the build output
|
|
1002
1107
|
// and ship the packages the rest point into.
|
|
1003
1108
|
const absolute = absolutePathFromSpecifier(specifier)
|
|
1109
|
+
// The framework ships whole at its own location, where baked paths are rewritten to.
|
|
1110
|
+
if (absolute && isInsideDir(framework.root, absolute)) continue
|
|
1004
1111
|
if (absolute) {
|
|
1005
1112
|
const name = packageNameFromPath(absolute)
|
|
1006
|
-
if (name)
|
|
1007
|
-
|
|
1113
|
+
if (name) {
|
|
1114
|
+
specifiers.add(name)
|
|
1115
|
+
hrefPackageDirs.add(packageDirFromPath(absolute, name))
|
|
1116
|
+
} else if (isInsideDir(config.outPath, absolute)) enqueue(absolute)
|
|
1008
1117
|
continue
|
|
1009
1118
|
}
|
|
1010
1119
|
if (/^(?:node:|bun$|bun:|data:)/.test(specifier)) continue
|
|
@@ -1020,6 +1129,12 @@ async function traceNodeModulesClosure(
|
|
|
1020
1129
|
) {
|
|
1021
1130
|
enqueue(resolved)
|
|
1022
1131
|
}
|
|
1132
|
+
// A release reaches an installed package it cannot name bare by a relative path.
|
|
1133
|
+
const installed = specifier.startsWith('.') && resolved && packageNameFromPath(resolved)
|
|
1134
|
+
if (installed) {
|
|
1135
|
+
specifiers.add(installed)
|
|
1136
|
+
hrefPackageDirs.add(packageDirFromPath(resolved, installed))
|
|
1137
|
+
}
|
|
1023
1138
|
const name = packageNameFromSpecifier(specifier)
|
|
1024
1139
|
if (name) specifiers.add(name)
|
|
1025
1140
|
}
|
|
@@ -1037,6 +1152,9 @@ async function traceNodeModulesClosure(
|
|
|
1037
1152
|
})
|
|
1038
1153
|
|
|
1039
1154
|
const packageDirs = new Map<string, string>()
|
|
1155
|
+
// A dependency version nested under the package that needs it (a version conflict): it ships
|
|
1156
|
+
// under that package's copy, where Bun resolves it from at runtime, not over the hoisted one.
|
|
1157
|
+
const nestedCopies = new Map<string, string>()
|
|
1040
1158
|
const workspaceLinks = new Map<string, string>()
|
|
1041
1159
|
// Native bindings resolved here are built for the build host; the function
|
|
1042
1160
|
// needs the ones for its own platform, fetched below.
|
|
@@ -1046,8 +1164,13 @@ async function traceNodeModulesClosure(
|
|
|
1046
1164
|
// registry. Its optional deps back compat features that only load when the app uses them, so they
|
|
1047
1165
|
// ship only where the app declares them too.
|
|
1048
1166
|
const appDependencies = await declaredDependencies(config.root)
|
|
1167
|
+
// A release never compiles, so only the dependencies its runtime entries import ship - not the
|
|
1168
|
+
// compilers the framework also depends on for build and dev.
|
|
1169
|
+
const runtimeDependencies = release ? await frameworkRuntimePackages(framework.root) : undefined
|
|
1049
1170
|
const queue: { name: string; from: string; owner?: PackageVersion }[] = [
|
|
1050
|
-
...framework.dependencies
|
|
1171
|
+
...framework.dependencies
|
|
1172
|
+
.filter(name => !runtimeDependencies || runtimeDependencies.has(name))
|
|
1173
|
+
.map(name => ({ name, from: framework.root })),
|
|
1051
1174
|
...framework.optionalDependencies
|
|
1052
1175
|
.filter(name => appDependencies.has(name))
|
|
1053
1176
|
.map(name => ({ name, from: framework.root })),
|
|
@@ -1087,16 +1210,34 @@ async function traceNodeModulesClosure(
|
|
|
1087
1210
|
}
|
|
1088
1211
|
packageDirs.set(name, dir)
|
|
1089
1212
|
if (!packageJson) continue
|
|
1090
|
-
const self = { name, version: packageJson.version ?? '' }
|
|
1091
1213
|
// Peer dependencies are deliberately not expanded — they fan out to whole
|
|
1092
1214
|
// ecosystems (react, next, ...) that are only shipped when something
|
|
1093
1215
|
// actually imports them.
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1216
|
+
const expand = async (
|
|
1217
|
+
packageDir: string,
|
|
1218
|
+
packageJson: Awaited<ReturnType<typeof readPackageJson>>,
|
|
1219
|
+
target: string,
|
|
1220
|
+
) => {
|
|
1221
|
+
const self = { name: packageJson?.name ?? name, version: packageJson?.version ?? '' }
|
|
1222
|
+
for (const dependency of [
|
|
1223
|
+
...Object.keys(packageJson?.dependencies ?? {}),
|
|
1224
|
+
...Object.keys(packageJson?.optionalDependencies ?? {}),
|
|
1225
|
+
]) {
|
|
1226
|
+
const nested = path.join(packageDir, 'node_modules', dependency)
|
|
1227
|
+
const nestedJson = existsSync(path.join(nested, 'package.json'))
|
|
1228
|
+
? await readPackageJson(nested)
|
|
1229
|
+
: undefined
|
|
1230
|
+
if (!nestedJson || nestedJson.os || nestedJson.cpu) {
|
|
1231
|
+
queue.push({ name: dependency, from: packageDir, owner: self })
|
|
1232
|
+
continue
|
|
1233
|
+
}
|
|
1234
|
+
const nestedTarget = path.join(target, 'node_modules', dependency)
|
|
1235
|
+
if (nestedCopies.has(nestedTarget)) continue
|
|
1236
|
+
nestedCopies.set(nestedTarget, nested)
|
|
1237
|
+
await expand(nested, nestedJson, nestedTarget)
|
|
1238
|
+
}
|
|
1099
1239
|
}
|
|
1240
|
+
await expand(dir, packageJson, path.join('node_modules', name))
|
|
1100
1241
|
}
|
|
1101
1242
|
|
|
1102
1243
|
if (hostNatives.size > 0 && !skipDependencyClosure()) {
|
|
@@ -1119,6 +1260,19 @@ async function traceNodeModulesClosure(
|
|
|
1119
1260
|
}),
|
|
1120
1261
|
)
|
|
1121
1262
|
}
|
|
1263
|
+
for (const [target, dir] of skipDependencyClosure() ? [] : nestedCopies) {
|
|
1264
|
+
await mkdir(path.dirname(path.join(functionPath, target)), { recursive: true })
|
|
1265
|
+
await copyTree(dir, path.join(functionPath, target), pack)
|
|
1266
|
+
}
|
|
1267
|
+
// Baked paths map the workspace root onto the function root, so an href into a nested or
|
|
1268
|
+
// app-level node_modules needs that exact directory there.
|
|
1269
|
+
for (const dir of skipDependencyClosure() ? [] : hrefPackageDirs) {
|
|
1270
|
+
const relative = path.relative(workspaceRoot, dir)
|
|
1271
|
+
const target = path.join(functionPath, relative)
|
|
1272
|
+
if (relative.startsWith('..') || existsSync(target)) continue
|
|
1273
|
+
await mkdir(path.dirname(target), { recursive: true })
|
|
1274
|
+
await copyTree(dir, target, pack)
|
|
1275
|
+
}
|
|
1122
1276
|
for (const [name, workspaceRelative] of workspaceLinks) {
|
|
1123
1277
|
const linkPath = path.join(functionPath, 'node_modules', name)
|
|
1124
1278
|
await mkdir(path.dirname(linkPath), { recursive: true })
|
|
@@ -1143,6 +1297,80 @@ interface PackageVersion {
|
|
|
1143
1297
|
version: string
|
|
1144
1298
|
}
|
|
1145
1299
|
|
|
1300
|
+
/** Every compiled entry `<out>/server/build-index.json` names, when the build emitted one. */
|
|
1301
|
+
function releaseEntries(config: ResolvedConfig, manifest: BuildManifest): string[] | undefined {
|
|
1302
|
+
if (!existsSync(buildIndexFile(config.outPath))) return undefined
|
|
1303
|
+
const index = readBuildIndex(config.outPath)
|
|
1304
|
+
return [
|
|
1305
|
+
...Object.values(index.modules),
|
|
1306
|
+
index.nextConfig,
|
|
1307
|
+
index.instrumentation?.file,
|
|
1308
|
+
index.instrumentation?.edge,
|
|
1309
|
+
...Object.values(index.compat?.cacheHandlers ?? {}),
|
|
1310
|
+
manifest.proxyModule,
|
|
1311
|
+
]
|
|
1312
|
+
.filter(artifact => artifact !== undefined)
|
|
1313
|
+
.map(artifact => path.resolve(config.outPath, artifact))
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Packages the framework's production entries import, statically or dynamically. Lazy `require`s
|
|
1318
|
+
* are the compiler facades (esbuild, oxc), which only build and dev reach.
|
|
1319
|
+
*/
|
|
1320
|
+
async function frameworkRuntimePackages(frameworkRoot: string) {
|
|
1321
|
+
const src = path.join(frameworkRoot, 'src')
|
|
1322
|
+
const scanners = {
|
|
1323
|
+
ts: new Bun.Transpiler({ loader: 'ts' }),
|
|
1324
|
+
tsx: new Bun.Transpiler({ loader: 'tsx' }),
|
|
1325
|
+
}
|
|
1326
|
+
const queue = [
|
|
1327
|
+
...runtimeEntryFiles.map(file => path.join(src, file)),
|
|
1328
|
+
...runtimeEntryDirs.flatMap(dir =>
|
|
1329
|
+
listSourceFiles(path.join(src, dir)).filter(file => /(?<!\.d)\.tsx?$/.test(file)),
|
|
1330
|
+
),
|
|
1331
|
+
]
|
|
1332
|
+
const seen = new Set(queue)
|
|
1333
|
+
const packages = new Set<string>()
|
|
1334
|
+
for (const file of queue) {
|
|
1335
|
+
const scanner = file.endsWith('.tsx') || file.endsWith('.jsx') ? scanners.tsx : scanners.ts
|
|
1336
|
+
for (const edge of scanner.scanImports(await readFile(file, 'utf8'))) {
|
|
1337
|
+
if (edge.kind !== 'import-statement' && edge.kind !== 'dynamic-import') continue
|
|
1338
|
+
if (!edge.path.startsWith('.')) {
|
|
1339
|
+
const name = packageNameFromSpecifier(edge.path)
|
|
1340
|
+
if (name) packages.add(name)
|
|
1341
|
+
continue
|
|
1342
|
+
}
|
|
1343
|
+
const target = resolveFrom(edge.path, path.dirname(file))
|
|
1344
|
+
if (
|
|
1345
|
+
target &&
|
|
1346
|
+
!seen.has(target) &&
|
|
1347
|
+
isInsideDir(src, target) &&
|
|
1348
|
+
scriptFilePattern.test(target)
|
|
1349
|
+
) {
|
|
1350
|
+
seen.add(target)
|
|
1351
|
+
queue.push(target)
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return packages
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function resolveFrom(specifier: string, dir: string) {
|
|
1359
|
+
try {
|
|
1360
|
+
return Bun.resolveSync(specifier, dir)
|
|
1361
|
+
} catch {
|
|
1362
|
+
return undefined
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
function listSourceFiles(dir: string): string[] {
|
|
1367
|
+
return readdirSync(dir, { withFileTypes: true }).flatMap(entry =>
|
|
1368
|
+
entry.isDirectory()
|
|
1369
|
+
? listSourceFiles(path.join(dir, entry.name))
|
|
1370
|
+
: [path.join(dir, entry.name)],
|
|
1371
|
+
)
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1146
1374
|
/**
|
|
1147
1375
|
* Native bindings for the function's platform, not the build host's. The host install only ever
|
|
1148
1376
|
* carries its own platform's optional deps, so the right builds have to come from the registry: one
|
|
@@ -1297,6 +1525,13 @@ function absolutePathFromSpecifier(specifier: string) {
|
|
|
1297
1525
|
return path.isAbsolute(specifier) ? specifier : undefined
|
|
1298
1526
|
}
|
|
1299
1527
|
|
|
1528
|
+
/** The `<...>/node_modules/<name>` directory holding `file`. */
|
|
1529
|
+
function packageDirFromPath(file: string, name: string) {
|
|
1530
|
+
const posix = toPosixPath(file)
|
|
1531
|
+
const marker = `/node_modules/${name}/`
|
|
1532
|
+
return posix.slice(0, posix.lastIndexOf(marker) + marker.length - 1)
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1300
1535
|
/** The package an absolute path belongs to, if it points inside node_modules. */
|
|
1301
1536
|
function packageNameFromPath(file: string) {
|
|
1302
1537
|
const parts = toPosixPath(file).split('/node_modules/')
|
|
@@ -1379,14 +1614,50 @@ async function staticOverrides(
|
|
|
1379
1614
|
return overrides
|
|
1380
1615
|
}
|
|
1381
1616
|
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
const
|
|
1385
|
-
|
|
1386
|
-
|
|
1617
|
+
// `important` lets route headers win over the CDN's own static-file cache-control, as Next's builder does.
|
|
1618
|
+
async function immutableAssetRoutes(publicDir: string, publicAssets: string[] = []) {
|
|
1619
|
+
const app = new Set(publicAssets)
|
|
1620
|
+
const built =
|
|
1621
|
+
publicAssets.length > 0
|
|
1622
|
+
? (await listFiles(publicDir))
|
|
1623
|
+
.map(file => toPosixPath(path.relative(publicDir, file)))
|
|
1624
|
+
.filter(relative => !app.has(relative) && immutableAssetPath(relative))
|
|
1625
|
+
: []
|
|
1626
|
+
const patterns = immutableAssetPatterns(built, publicAssets)
|
|
1627
|
+
return routeSources(patterns, source => `^/(?:${source})`).map(src => ({
|
|
1628
|
+
src,
|
|
1387
1629
|
headers: { 'cache-control': immutableCacheControl },
|
|
1388
1630
|
continue: true,
|
|
1631
|
+
important: true,
|
|
1632
|
+
}))
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Whole immutable prefixes that hold no app public file; under the others, each build file collapsed
|
|
1637
|
+
* to its topmost folder below the prefix that holds no app public file, else its exact name.
|
|
1638
|
+
*/
|
|
1639
|
+
function immutableAssetPatterns(built: string[], publicAssets: string[]) {
|
|
1640
|
+
const appDirs = new Set(publicAssets.flatMap(ancestorDirs))
|
|
1641
|
+
const prefixes = [...new Set(immutableAssetPrefixes())]
|
|
1642
|
+
const patterns = prefixes.filter(prefix => !appDirs.has(prefix)).map(escapeRegex)
|
|
1643
|
+
for (const relative of built) {
|
|
1644
|
+
const prefix = prefixes.find(prefix => relative.startsWith(prefix))
|
|
1645
|
+
if (!prefix || !appDirs.has(prefix)) continue
|
|
1646
|
+
const dir = ancestorDirs(relative).find(dir => dir.length > prefix.length && !appDirs.has(dir))
|
|
1647
|
+
patterns.push(dir ? escapeRegex(requestPath(dir)) : `${escapeRegex(requestPath(relative))}$`)
|
|
1389
1648
|
}
|
|
1649
|
+
return [...new Set(patterns)]
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/** A public-relative path as browsers request it (the WHATWG path percent-encode set). */
|
|
1653
|
+
function requestPath(relative: string) {
|
|
1654
|
+
return relative.replace(/[\0-\x20"#<>?`{}\x7f-\u{10ffff}]/gu, char => encodeURIComponent(char))
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
/** `a/b/c.js` -> `['a/', 'a/b/']`. */
|
|
1658
|
+
function ancestorDirs(relative: string) {
|
|
1659
|
+
const parts = relative.split('/').slice(0, -1)
|
|
1660
|
+
return parts.map((_, index) => `${parts.slice(0, index + 1).join('/')}/`)
|
|
1390
1661
|
}
|
|
1391
1662
|
|
|
1392
1663
|
// Headers a CDN route cannot replay; a file that sets one stays on the server function.
|
|
@@ -1434,23 +1705,29 @@ function staticHeaderRoutes(staticFiles: Record<string, StaticFileMetadata>) {
|
|
|
1434
1705
|
groups.set(key, group)
|
|
1435
1706
|
group.patterns.push(servedPathPattern(relative))
|
|
1436
1707
|
}
|
|
1437
|
-
return [...groups.values()].flatMap(({ headers, patterns }) =>
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
const last = sources.length - 1
|
|
1441
|
-
if (last >= 0 && sources[last]!.length + pattern.length < maxRouteSourceLength) {
|
|
1442
|
-
sources[last] += `|${pattern}`
|
|
1443
|
-
} else {
|
|
1444
|
-
sources.push(pattern)
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
return sources.map(source => ({
|
|
1448
|
-
src: `^/(?:${source})$`,
|
|
1708
|
+
return [...groups.values()].flatMap(({ headers, patterns }) =>
|
|
1709
|
+
routeSources(patterns, source => `^/(?:${source})$`).map(src => ({
|
|
1710
|
+
src,
|
|
1449
1711
|
methods: ['GET', 'HEAD'],
|
|
1450
1712
|
headers,
|
|
1451
1713
|
continue: true,
|
|
1452
|
-
|
|
1453
|
-
|
|
1714
|
+
important: true,
|
|
1715
|
+
})),
|
|
1716
|
+
)
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
/** Joins patterns into as few `wrap`ped route sources as fit `maxRouteSourceLength`. */
|
|
1720
|
+
function routeSources(patterns: string[], wrap: (alternation: string) => string) {
|
|
1721
|
+
const sources: string[] = []
|
|
1722
|
+
for (const pattern of patterns) {
|
|
1723
|
+
const last = sources.length - 1
|
|
1724
|
+
if (last >= 0 && wrap(`${sources[last]}|${pattern}`).length <= maxRouteSourceLength) {
|
|
1725
|
+
sources[last] += `|${pattern}`
|
|
1726
|
+
} else {
|
|
1727
|
+
sources.push(pattern)
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
return sources.map(wrap)
|
|
1454
1731
|
}
|
|
1455
1732
|
|
|
1456
1733
|
/** A static file's request paths: `a/index.html` also answers `/a` and `/a/`. */
|