@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
package/src/css/build.ts
CHANGED
|
@@ -1,20 +1,45 @@
|
|
|
1
|
-
import { existsSync
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { productionRelease } from '../runtime/production'
|
|
2
3
|
import { readFile, rename, writeFile } from 'node:fs/promises'
|
|
3
4
|
import path from 'node:path'
|
|
4
5
|
import type { Plugin } from 'esbuild'
|
|
5
6
|
import { hashedAssetName } from '../utils/asset-hash'
|
|
6
7
|
import { build } from '../utils/esbuild'
|
|
7
|
-
import {
|
|
8
|
+
import { ensureDir, readText } from '../utils/fs'
|
|
8
9
|
import { postcssConfigFile, runPostcss } from './postcss'
|
|
9
10
|
import { extraPageExtensions, getCssExtensions } from '../extensions'
|
|
10
|
-
import { nextCompatEnabled } from '../render/hooks'
|
|
11
11
|
import { resolveImport } from '../resolve/imports'
|
|
12
|
+
import { readSourceSync } from '../resolve/source-text'
|
|
12
13
|
import { createVerboseLogger } from '../utils/verbose'
|
|
13
14
|
import type { ClientReference } from '../client/reference'
|
|
14
15
|
import type { ResolvedConfig } from '../config'
|
|
15
16
|
import type { RouteManifestEntry } from '../types'
|
|
16
17
|
|
|
17
18
|
import type { CssWorkerRequest, CssWorkerResponse } from './worker'
|
|
19
|
+
import {
|
|
20
|
+
cssClassNames,
|
|
21
|
+
cssModuleClassName,
|
|
22
|
+
cssModuleMapping,
|
|
23
|
+
isCssModuleFile,
|
|
24
|
+
recordEmittedAsset,
|
|
25
|
+
} from './assets'
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
assetHref,
|
|
29
|
+
assetPathname,
|
|
30
|
+
clearEmittedAssets,
|
|
31
|
+
cssModuleMapping,
|
|
32
|
+
emitFontCssStylesheet,
|
|
33
|
+
emittedAssetName,
|
|
34
|
+
emittedAssetNames,
|
|
35
|
+
publishEmittedAssets,
|
|
36
|
+
recordEmittedAsset,
|
|
37
|
+
registerCssRuntime,
|
|
38
|
+
routeCssAssetNames,
|
|
39
|
+
routeCssHref,
|
|
40
|
+
withAssetPrefix,
|
|
41
|
+
type AssetHrefConfig,
|
|
42
|
+
} from './assets'
|
|
18
43
|
|
|
19
44
|
interface Pending {
|
|
20
45
|
resolve: () => void
|
|
@@ -126,8 +151,6 @@ interface CssBuildOptions {
|
|
|
126
151
|
verbose?: boolean
|
|
127
152
|
}
|
|
128
153
|
|
|
129
|
-
let cssRuntimeRegistered = false
|
|
130
|
-
|
|
131
154
|
export function globalCssSource(config: ResolvedConfig) {
|
|
132
155
|
return globalCssSources(config)[0]
|
|
133
156
|
}
|
|
@@ -135,7 +158,10 @@ export function globalCssSource(config: ResolvedConfig) {
|
|
|
135
158
|
export function globalCssSources(
|
|
136
159
|
config: Pick<ResolvedConfig, 'root' | 'appPath'> & Partial<Pick<ResolvedConfig, 'workspaceRoot'>>,
|
|
137
160
|
) {
|
|
138
|
-
return
|
|
161
|
+
return (
|
|
162
|
+
productionRelease(config)?.globalCss ??
|
|
163
|
+
globalCssSourcesForPaths(config.root, config.appPath, config.workspaceRoot)
|
|
164
|
+
)
|
|
139
165
|
}
|
|
140
166
|
|
|
141
167
|
// The walk below reads and resolves the ROOT LAYOUT'S WHOLE IMPORT GRAPH, and every render asks it
|
|
@@ -213,7 +239,7 @@ function collectGlobalCssSources(
|
|
|
213
239
|
}
|
|
214
240
|
visited.add(resolvedFile)
|
|
215
241
|
|
|
216
|
-
for (const specifier of moduleSpecifiers(
|
|
242
|
+
for (const specifier of moduleSpecifiers(readSourceSync(resolvedFile))) {
|
|
217
243
|
const resolved = resolveImport(root, resolvedFile, specifier, workspaceRoot)
|
|
218
244
|
if (!resolved) continue
|
|
219
245
|
if (isCssFile(resolved)) {
|
|
@@ -233,130 +259,6 @@ function rootLayoutFile(appPath: string, missing?: Set<string>) {
|
|
|
233
259
|
return path.join(appPath, 'layout.tsx')
|
|
234
260
|
}
|
|
235
261
|
|
|
236
|
-
export function globalCssHref(config: ResolvedConfig) {
|
|
237
|
-
return globalCssSources(config).length > 0 ? assetHref(config, 'global.css') : undefined
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export type AssetHrefConfig = Pick<ResolvedConfig, 'assetPrefix' | 'compat' | 'outPath'>
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Logical build-asset name -> the content-hashed name the build actually emitted
|
|
244
|
-
* (`global.css` -> `global-1f4a9c2b3d5e6f70.css`). A production asset name must
|
|
245
|
-
* carry its content, or the URL cannot honestly be served `immutable`: the same
|
|
246
|
-
* name would answer different bytes after a deploy.
|
|
247
|
-
*
|
|
248
|
-
* Keyed by outPath, never process-global: one process builds several apps (the
|
|
249
|
-
* test suite does it constantly) and their names must not cross. Empty in dev,
|
|
250
|
-
* where names stay flat and every asset is served `no-cache` anyway.
|
|
251
|
-
*/
|
|
252
|
-
const emittedAssets = new Map<string, Map<string, string>>()
|
|
253
|
-
|
|
254
|
-
export function recordEmittedAsset(outPath: string, logical: string, emitted: string): void {
|
|
255
|
-
const names = emittedAssets.get(outPath) ?? new Map<string, string>()
|
|
256
|
-
names.set(logical, emitted)
|
|
257
|
-
emittedAssets.set(outPath, names)
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** Re-publish the build's name map at server boot (see BuildManifest.assetNames). */
|
|
261
|
-
export function publishEmittedAssets(
|
|
262
|
-
outPath: string,
|
|
263
|
-
names: Record<string, string> | undefined,
|
|
264
|
-
): void {
|
|
265
|
-
if (!names) return
|
|
266
|
-
for (const [logical, emitted] of Object.entries(names))
|
|
267
|
-
recordEmittedAsset(outPath, logical, emitted)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function emittedAssetNames(outPath: string): Record<string, string> {
|
|
271
|
-
return Object.fromEntries(emittedAssets.get(outPath) ?? [])
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export function clearEmittedAssets(outPath: string): void {
|
|
275
|
-
emittedAssets.delete(outPath)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/** The file name a logical asset name resolves to. Identity until a build records one. */
|
|
279
|
-
export function emittedAssetName(
|
|
280
|
-
config: Pick<ResolvedConfig, 'outPath'> | undefined,
|
|
281
|
-
name: string,
|
|
282
|
-
): string {
|
|
283
|
-
if (!config?.outPath) return name
|
|
284
|
-
return emittedAssets.get(config.outPath)?.get(name) ?? name
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Where a built asset lives in the URL space. next-compat serves the build output under Next's
|
|
288
|
-
// static path, so a compat app's document references its CSS/JS exactly as Next does; core keeps
|
|
289
|
-
// `/assets/`. Every document-emitted build-asset URL goes through here (and the dev/prod servers
|
|
290
|
-
// accept both spellings), so an emitted href can never name a path the server will not serve —
|
|
291
|
-
// including the content hash the production name carries.
|
|
292
|
-
export function assetPathname(
|
|
293
|
-
config: Pick<ResolvedConfig, 'compat' | 'outPath'> | undefined,
|
|
294
|
-
name: string,
|
|
295
|
-
) {
|
|
296
|
-
const emitted = emittedAssetName(config, name)
|
|
297
|
-
return nextCompatEnabled(config ?? {}) ? `/_next/static/${emitted}` : `/assets/${emitted}`
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
export function assetHref(config: AssetHrefConfig | undefined, name: string) {
|
|
301
|
-
return withAssetPrefix(config, assetPathname(config, name))
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// A route's built CSS filenames - the one rule behind the document's links, the
|
|
305
|
-
// inline-CSS path and analyze, so no consumer can disagree about whether a
|
|
306
|
-
// route has CSS. compat cssChunking records split names in cssAssets.
|
|
307
|
-
export function routeCssAssetNames(
|
|
308
|
-
route: Pick<RouteManifestEntry, 'id' | 'cssImports' | 'cssAssets'>,
|
|
309
|
-
): string[] {
|
|
310
|
-
if (route.cssImports.length === 0) return []
|
|
311
|
-
return route.cssAssets?.length ? route.cssAssets : [`${route.id}.css`]
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export function routeCssHref(
|
|
315
|
-
route: RouteManifestEntry,
|
|
316
|
-
config?: AssetHrefConfig,
|
|
317
|
-
): string | string[] | undefined {
|
|
318
|
-
const assets = routeCssAssetNames(route)
|
|
319
|
-
if (assets.length === 0) return undefined
|
|
320
|
-
return assets.map(asset => assetHref(config, asset))
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Put a render's next/font rules in the first stylesheet chunk, matching Next's
|
|
325
|
-
* linked CSS delivery without changing the rest of the route's chunk order.
|
|
326
|
-
*/
|
|
327
|
-
export async function emitFontCssStylesheet(
|
|
328
|
-
config: ResolvedConfig,
|
|
329
|
-
routeId: string,
|
|
330
|
-
fontCss: string,
|
|
331
|
-
baseAsset: string | undefined,
|
|
332
|
-
options: { dev: boolean },
|
|
333
|
-
) {
|
|
334
|
-
const outDir = path.join(config.outPath, options.dev ? 'cache' : 'public', 'assets')
|
|
335
|
-
await ensureDir(outDir)
|
|
336
|
-
const baseFile = baseAsset ? path.join(outDir, baseAsset) : undefined
|
|
337
|
-
const baseCss = baseFile && existsSync(baseFile) ? await readFile(baseFile, 'utf8') : ''
|
|
338
|
-
const contents = [fontCss, baseCss].filter(Boolean).join('\n')
|
|
339
|
-
const logicalName = baseAsset
|
|
340
|
-
? baseAsset.replace(/-[0-9a-f]{16}(?=\.css$)/, '')
|
|
341
|
-
: `${routeId}.css`
|
|
342
|
-
const name = hashedAssetName(logicalName, contents)
|
|
343
|
-
const file = path.join(outDir, name)
|
|
344
|
-
if (!existsSync(file) || (await readFile(file, 'utf8')) !== contents)
|
|
345
|
-
await writeFile(file, contents)
|
|
346
|
-
return name
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Prepend the configured assetPrefix (a CDN origin or path) to an app-absolute
|
|
350
|
-
// asset URL. Link hrefs use basePath instead and must NOT go through here.
|
|
351
|
-
export function withAssetPrefix(
|
|
352
|
-
config: Pick<ResolvedConfig, 'assetPrefix'> | undefined,
|
|
353
|
-
href: string,
|
|
354
|
-
) {
|
|
355
|
-
const prefix = config?.assetPrefix
|
|
356
|
-
if (!prefix) return href
|
|
357
|
-
return `${prefix.replace(/\/$/, '')}${href}`
|
|
358
|
-
}
|
|
359
|
-
|
|
360
262
|
/**
|
|
361
263
|
* Spawn the CSS worker and load the app's postcss config before any stylesheet
|
|
362
264
|
* is asked for, so Tailwind's cold boot overlaps with the rest of startup
|
|
@@ -394,7 +296,7 @@ export async function buildGlobalCss(config: ResolvedConfig, options: CssBuildOp
|
|
|
394
296
|
await log.step('global css: esbuild bundle', () =>
|
|
395
297
|
build({
|
|
396
298
|
stdin: {
|
|
397
|
-
contents:
|
|
299
|
+
contents: stdinImports(config.root, sources),
|
|
398
300
|
loader: 'css',
|
|
399
301
|
resolveDir: config.root,
|
|
400
302
|
sourcefile: 'global.css',
|
|
@@ -447,8 +349,9 @@ async function fingerprintAsset(
|
|
|
447
349
|
outDir: string,
|
|
448
350
|
assetName: string,
|
|
449
351
|
options: CssBuildOptions,
|
|
352
|
+
file = assetName,
|
|
450
353
|
) {
|
|
451
|
-
const outfile = path.join(outDir,
|
|
354
|
+
const outfile = path.join(outDir, file)
|
|
452
355
|
if (options.dev) return outfile
|
|
453
356
|
const emittedName = hashedAssetName(assetName, await readFile(outfile))
|
|
454
357
|
const emitted = path.join(outDir, emittedName)
|
|
@@ -457,6 +360,19 @@ async function fingerprintAsset(
|
|
|
457
360
|
return emitted
|
|
458
361
|
}
|
|
459
362
|
|
|
363
|
+
// Relative to the build's resolveDir: an absolute specifier would match the public-url plugin's
|
|
364
|
+
// `^/` filter and cost a JS round trip per import.
|
|
365
|
+
function stdinImports(root: string, files: string[]) {
|
|
366
|
+
return files
|
|
367
|
+
.map(file => {
|
|
368
|
+
const relative = path.relative(root, file).split(path.sep).join('/')
|
|
369
|
+
const specifier =
|
|
370
|
+
path.isAbsolute(relative) || relative.startsWith('../') ? relative : `./${relative}`
|
|
371
|
+
return `@import ${JSON.stringify(specifier)};`
|
|
372
|
+
})
|
|
373
|
+
.join('\n')
|
|
374
|
+
}
|
|
375
|
+
|
|
460
376
|
function moduleSpecifiers(source: string) {
|
|
461
377
|
const specifiers: string[] = []
|
|
462
378
|
const pattern = /(?:import|export)\s+(?:[^'";]+?\s+from\s+)?['"]([^'"]+)['"]/g
|
|
@@ -501,38 +417,120 @@ export function prepareRouteCssChunks(routes: Pick<RouteManifestEntry, 'id' | 'c
|
|
|
501
417
|
for (const [id, segments] of plan) routeCssPlan.set(id, segments)
|
|
502
418
|
}
|
|
503
419
|
|
|
420
|
+
interface CssChunk {
|
|
421
|
+
imports: string[]
|
|
422
|
+
name: string
|
|
423
|
+
label: string
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** A route's stylesheet chunks, one per planned slice, and the split names the route records. */
|
|
427
|
+
function routeCssChunks(route: RouteManifestEntry) {
|
|
428
|
+
if (route.cssImports.length === 0) return undefined
|
|
429
|
+
const segments = routeCssPlan.get(route.id)
|
|
430
|
+
if (segments && segments.length > 1) {
|
|
431
|
+
const cssAssets = segments.map((_, index) => `${route.id}-${index}.css`)
|
|
432
|
+
const chunks: CssChunk[] = segments.map((imports, index) => ({
|
|
433
|
+
imports,
|
|
434
|
+
name: cssAssets[index]!,
|
|
435
|
+
label: `route css ${route.route} #${index + 1}`,
|
|
436
|
+
}))
|
|
437
|
+
return { cssAssets, chunks }
|
|
438
|
+
}
|
|
439
|
+
const chunks: CssChunk[] = [
|
|
440
|
+
{ imports: route.cssImports, name: `${route.id}.css`, label: `route css ${route.route}` },
|
|
441
|
+
]
|
|
442
|
+
return { cssAssets: undefined, chunks }
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function clientReferenceCssChunks(reference: ClientReference): CssChunk[] {
|
|
446
|
+
if (!reference.cssImports || reference.cssImports.length === 0) return []
|
|
447
|
+
return [
|
|
448
|
+
{
|
|
449
|
+
imports: reference.cssImports,
|
|
450
|
+
name: `${reference.id}.css`,
|
|
451
|
+
label: `island css ${reference.id}`,
|
|
452
|
+
},
|
|
453
|
+
]
|
|
454
|
+
}
|
|
455
|
+
|
|
504
456
|
export async function buildRouteCss(
|
|
505
457
|
config: ResolvedConfig,
|
|
506
458
|
route: RouteManifestEntry,
|
|
507
459
|
options: CssBuildOptions = {},
|
|
508
460
|
) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
for (const [index, segment] of segments.entries()) {
|
|
516
|
-
files.push(
|
|
517
|
-
await bundleCssChunk(
|
|
518
|
-
config,
|
|
519
|
-
segment,
|
|
520
|
-
assetNames[index]!,
|
|
521
|
-
`route css ${route.route} #${index + 1}`,
|
|
522
|
-
options,
|
|
523
|
-
),
|
|
524
|
-
)
|
|
525
|
-
}
|
|
526
|
-
return files
|
|
461
|
+
const css = routeCssChunks(route)
|
|
462
|
+
if (!css) return undefined
|
|
463
|
+
route.cssAssets = css.cssAssets
|
|
464
|
+
const files: string[] = []
|
|
465
|
+
for (const chunk of css.chunks) {
|
|
466
|
+
files.push(await bundleCssChunk(config, chunk.imports, chunk.name, chunk.label, options))
|
|
527
467
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
468
|
+
return css.cssAssets ? files : files[0]
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** Logical names the document stylesheets own; a route chunk spelled the same waits for them. */
|
|
472
|
+
const DOCUMENT_CSS = new Set([
|
|
473
|
+
'global.css',
|
|
474
|
+
'not-found.css',
|
|
475
|
+
'global-not-found.css',
|
|
476
|
+
'global-error.css',
|
|
477
|
+
])
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Every route's and island's stylesheet for a production build, bundled at once rather than one
|
|
481
|
+
* route after another and alongside the document stylesheets. Each route gets a `publish` that the
|
|
482
|
+
* prerender loop calls in route order once the document sheets are done: it records the route's
|
|
483
|
+
* names exactly when, and in the order, a serial pass would, so the manifest is unchanged.
|
|
484
|
+
*/
|
|
485
|
+
export function buildRouteStylesheets(
|
|
486
|
+
config: ResolvedConfig,
|
|
487
|
+
routes: RouteManifestEntry[],
|
|
488
|
+
documentCss: Promise<unknown>,
|
|
489
|
+
options: CssBuildOptions = {},
|
|
490
|
+
) {
|
|
491
|
+
// One bundle per distinct input; an island several routes reach is built once.
|
|
492
|
+
const builds = new Map<string, { file: string; outDir: Promise<string>; emitted?: string }>()
|
|
493
|
+
const taken = new Set<string>()
|
|
494
|
+
const publish = new Map<RouteManifestEntry, () => Promise<void>>()
|
|
495
|
+
for (const route of routes) {
|
|
496
|
+
const css = routeCssChunks(route)
|
|
497
|
+
const chunks = [
|
|
498
|
+
...(css?.chunks ?? []),
|
|
499
|
+
...route.clientReferences.flatMap(clientReferenceCssChunks),
|
|
500
|
+
]
|
|
501
|
+
const own = chunks.map(chunk => {
|
|
502
|
+
const key = `${chunk.name}\0${chunk.imports.join('\0')}`
|
|
503
|
+
let build = builds.get(key)
|
|
504
|
+
if (!build) {
|
|
505
|
+
// Two routes can share an id (`/a-b`, `/a/b`): different input under a taken name gets its own file.
|
|
506
|
+
const file = taken.has(chunk.name) ? `.${builds.size}-${chunk.name}` : chunk.name
|
|
507
|
+
taken.add(chunk.name)
|
|
508
|
+
const write = () => writeCssChunk(config, chunk.imports, file, chunk.label, options)
|
|
509
|
+
const outDir = DOCUMENT_CSS.has(file) ? documentCss.then(write) : write()
|
|
510
|
+
outDir.catch(() => undefined)
|
|
511
|
+
build = { file, outDir }
|
|
512
|
+
builds.set(key, build)
|
|
513
|
+
}
|
|
514
|
+
return { name: chunk.name, build }
|
|
515
|
+
})
|
|
516
|
+
publish.set(route, async () => {
|
|
517
|
+
if (css) route.cssAssets = css.cssAssets
|
|
518
|
+
for (const { name, build } of own) {
|
|
519
|
+
if (build.emitted) recordEmittedAsset(config.outPath, name, build.emitted)
|
|
520
|
+
else {
|
|
521
|
+
const emitted = await fingerprintAsset(
|
|
522
|
+
config,
|
|
523
|
+
await build.outDir,
|
|
524
|
+
name,
|
|
525
|
+
options,
|
|
526
|
+
build.file,
|
|
527
|
+
)
|
|
528
|
+
build.emitted = path.basename(emitted)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
})
|
|
532
|
+
}
|
|
533
|
+
return publish
|
|
536
534
|
}
|
|
537
535
|
|
|
538
536
|
// The synthetic document conventions are created at render time and never
|
|
@@ -581,14 +579,9 @@ export async function buildClientReferenceCss(
|
|
|
581
579
|
reference: ClientReference,
|
|
582
580
|
options: CssBuildOptions = {},
|
|
583
581
|
) {
|
|
584
|
-
|
|
585
|
-
return
|
|
586
|
-
|
|
587
|
-
reference.cssImports,
|
|
588
|
-
`${reference.id}.css`,
|
|
589
|
-
`island css ${reference.id}`,
|
|
590
|
-
options,
|
|
591
|
-
)
|
|
582
|
+
const [chunk] = clientReferenceCssChunks(reference)
|
|
583
|
+
if (!chunk) return undefined
|
|
584
|
+
return bundleCssChunk(config, chunk.imports, chunk.name, chunk.label, options)
|
|
592
585
|
}
|
|
593
586
|
|
|
594
587
|
async function bundleCssChunk(
|
|
@@ -597,6 +590,18 @@ async function bundleCssChunk(
|
|
|
597
590
|
assetName: string,
|
|
598
591
|
label: string,
|
|
599
592
|
options: CssBuildOptions,
|
|
593
|
+
) {
|
|
594
|
+
const outDir = await writeCssChunk(config, cssImports, assetName, label, options)
|
|
595
|
+
return fingerprintAsset(config, outDir, assetName, options)
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** Bundle (and postcss) one stylesheet under its logical name; returns its directory. */
|
|
599
|
+
async function writeCssChunk(
|
|
600
|
+
config: ResolvedConfig,
|
|
601
|
+
cssImports: string[],
|
|
602
|
+
assetName: string,
|
|
603
|
+
label: string,
|
|
604
|
+
options: CssBuildOptions,
|
|
600
605
|
) {
|
|
601
606
|
const log = createVerboseLogger(options.verbose ?? false, 'css')
|
|
602
607
|
|
|
@@ -611,7 +616,7 @@ async function bundleCssChunk(
|
|
|
611
616
|
const postcss = hasPostcssConfig(config.root)
|
|
612
617
|
await build({
|
|
613
618
|
stdin: {
|
|
614
|
-
contents:
|
|
619
|
+
contents: stdinImports(config.root, cssImports),
|
|
615
620
|
loader: 'css',
|
|
616
621
|
resolveDir: config.root,
|
|
617
622
|
sourcefile: assetName,
|
|
@@ -649,8 +654,7 @@ async function bundleCssChunk(
|
|
|
649
654
|
await rewriteTailwindConfigDirectives(outfile, cssImports)
|
|
650
655
|
await log.step(`${label}: postcss`, () => runPostcssOffThread(config, outfile, options))
|
|
651
656
|
}
|
|
652
|
-
|
|
653
|
-
return fingerprintAsset(config, outDir, assetName, options)
|
|
657
|
+
return outDir
|
|
654
658
|
}
|
|
655
659
|
|
|
656
660
|
// A leading slash in a CSS url() is a public URL, not an app-root filesystem
|
|
@@ -667,34 +671,6 @@ function cssPublicUrlPlugin(): Plugin {
|
|
|
667
671
|
}
|
|
668
672
|
}
|
|
669
673
|
|
|
670
|
-
export function registerCssRuntime() {
|
|
671
|
-
if (cssRuntimeRegistered) return
|
|
672
|
-
cssRuntimeRegistered = true
|
|
673
|
-
|
|
674
|
-
Bun.plugin({
|
|
675
|
-
name: 'pnext-css-runtime',
|
|
676
|
-
setup(plugin) {
|
|
677
|
-
plugin.onLoad({ filter: /\.(?:css|scss|sass)$/ }, async ({ path: file }) =>
|
|
678
|
-
isCssModuleFile(file)
|
|
679
|
-
? {
|
|
680
|
-
exports: { default: await cssModuleMapping(file) },
|
|
681
|
-
loader: 'object',
|
|
682
|
-
}
|
|
683
|
-
: {
|
|
684
|
-
contents: 'export default undefined;',
|
|
685
|
-
loader: 'js',
|
|
686
|
-
},
|
|
687
|
-
)
|
|
688
|
-
},
|
|
689
|
-
})
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// Sass is unsupported (no compiler); its imports still must not break the
|
|
693
|
-
// bundle, so .scss/.sass load as empty modules with module class-name maps.
|
|
694
|
-
function isCssModuleFile(file: string) {
|
|
695
|
-
return /\.module\.(?:css|scss|sass)$/.test(file)
|
|
696
|
-
}
|
|
697
|
-
|
|
698
674
|
export function cssModuleClientPlugin(): Plugin {
|
|
699
675
|
return {
|
|
700
676
|
name: 'pnext-css-modules',
|
|
@@ -822,31 +798,6 @@ function cssModuleBuildPlugin(): Plugin {
|
|
|
822
798
|
}
|
|
823
799
|
}
|
|
824
800
|
|
|
825
|
-
async function cssModuleMapping(file: string) {
|
|
826
|
-
// Compat handles *.module.{scss,sass} (sass compiles + scopes); core keeps
|
|
827
|
-
// plain .module.css. Lazy read: the registry populates at compat bootstrap.
|
|
828
|
-
const compatMapping = getCssExtensions().resolveCssModule(file)
|
|
829
|
-
if (compatMapping) return compatMapping
|
|
830
|
-
const source = await readText(file)
|
|
831
|
-
const classNames = cssClassNames(source)
|
|
832
|
-
|
|
833
|
-
return Object.fromEntries(
|
|
834
|
-
[...classNames].map(className => [className, cssModuleClassName(file, className)]),
|
|
835
|
-
)
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
function cssClassNames(source: string) {
|
|
839
|
-
const classNames = new Set<string>()
|
|
840
|
-
const classPattern = /(^|[^\\])\.(-?[_a-zA-Z][\w-]*)/g
|
|
841
|
-
let match: RegExpExecArray | null
|
|
842
|
-
|
|
843
|
-
while ((match = classPattern.exec(source))) {
|
|
844
|
-
if (match[2]) classNames.add(match[2])
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
return classNames
|
|
848
|
-
}
|
|
849
|
-
|
|
850
801
|
function transformCssModule(source: string, file: string) {
|
|
851
802
|
let css = source
|
|
852
803
|
for (const className of cssClassNames(source)) {
|
|
@@ -899,15 +850,6 @@ function keyframeNames(css: string) {
|
|
|
899
850
|
return names
|
|
900
851
|
}
|
|
901
852
|
|
|
902
|
-
function cssModuleClassName(file: string, className: string) {
|
|
903
|
-
const base = path
|
|
904
|
-
.basename(file)
|
|
905
|
-
.replace(/\.module\.css$/, '')
|
|
906
|
-
.replace(/[^_a-zA-Z0-9]/g, '_')
|
|
907
|
-
const hash = pathHash(cssModuleScopePath(file))
|
|
908
|
-
return `${base}_${className}_${hash}`
|
|
909
|
-
}
|
|
910
|
-
|
|
911
853
|
function rewriteClassSelector(css: string, scopedClassName: string, originalClassName: string) {
|
|
912
854
|
const esbuildNamePattern = new RegExp(
|
|
913
855
|
`\\.${escapeRegex(originalClassName)}(?![-_a-zA-Z0-9])`,
|
|
@@ -916,12 +858,6 @@ function rewriteClassSelector(css: string, scopedClassName: string, originalClas
|
|
|
916
858
|
return css.replace(esbuildNamePattern, `.${scopedClassName}`)
|
|
917
859
|
}
|
|
918
860
|
|
|
919
|
-
function pathHash(file: string) {
|
|
920
|
-
let hash = 5381
|
|
921
|
-
for (const char of file) hash = ((hash << 5) + hash) ^ char.charCodeAt(0)
|
|
922
|
-
return (hash >>> 0).toString(36).slice(0, 5)
|
|
923
|
-
}
|
|
924
|
-
|
|
925
861
|
function escapeRegex(value: string) {
|
|
926
862
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
927
863
|
}
|
package/src/dev/server.ts
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
staticMetadataCacheControl,
|
|
53
53
|
} from '../routing/metadata-files'
|
|
54
54
|
import { handleRouteModule, type RouteHandlerModule } from '../routing/handler'
|
|
55
|
-
import { malformedUrlResponse, trailingSlashRedirect } from '../routing/href'
|
|
55
|
+
import { malformedUrlResponse, repeatedSlashRedirect, trailingSlashRedirect } from '../routing/href'
|
|
56
56
|
import { type PeerAddressSource, withForwardedHeaders } from '../routing/forwarded'
|
|
57
57
|
import {
|
|
58
58
|
assertNoServerActionsWithoutCompat,
|
|
@@ -87,7 +87,14 @@ import {
|
|
|
87
87
|
setWorkUnitRoute,
|
|
88
88
|
} from '../request/context'
|
|
89
89
|
import { setRequestRuntime } from '../routing/request-environment'
|
|
90
|
-
import {
|
|
90
|
+
import {
|
|
91
|
+
ensureDir,
|
|
92
|
+
exactNameIndex,
|
|
93
|
+
type ExactNames,
|
|
94
|
+
hasExactName,
|
|
95
|
+
listFiles,
|
|
96
|
+
writeText,
|
|
97
|
+
} from '../utils/fs'
|
|
91
98
|
import { contentType } from '../utils/content-type'
|
|
92
99
|
import { traceEnabled } from '../utils/trace-flags'
|
|
93
100
|
import {
|
|
@@ -290,6 +297,7 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
290
297
|
markBoot('boot:scanRoutes')
|
|
291
298
|
await validateProxyFiles(config)
|
|
292
299
|
let proxyRunner = createProxyRunner(config)
|
|
300
|
+
const exactNames = exactNameIndex(config.root)
|
|
293
301
|
markBoot('boot:proxy')
|
|
294
302
|
let devImportVersion = String(Date.now())
|
|
295
303
|
// The proxy runs serially in front of every request, so its compile+import is
|
|
@@ -436,6 +444,8 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
436
444
|
if (badRequest) return badRequest
|
|
437
445
|
request = withForwardedHeaders(request, server)
|
|
438
446
|
let url = new URL(request.url)
|
|
447
|
+
const slashRedirect = repeatedSlashRedirect(url)
|
|
448
|
+
if (slashRedirect) return slashRedirect
|
|
439
449
|
const profile = devRequestProfile(request, url)
|
|
440
450
|
if (profile) logDevProfile(profile, 'prologue (bootstrap/headers/url)', prologueStart)
|
|
441
451
|
let pageLog = startDevPageStallTimer(pendingDevPageLoadLog(routes, request, url))
|
|
@@ -475,6 +485,10 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
475
485
|
}
|
|
476
486
|
|
|
477
487
|
try {
|
|
488
|
+
// Before the proxy, for every method, as in Next: the proxy only ever sees canonical paths.
|
|
489
|
+
const canonicalRedirect = trailingSlashRedirect(config, url)
|
|
490
|
+
if (canonicalRedirect) return finish(canonicalRedirect)
|
|
491
|
+
|
|
478
492
|
const initialPrefetchResponse = maybeDevPagePrefetchResponse(routes, url.pathname, request)
|
|
479
493
|
if (initialPrefetchResponse) return finish(initialPrefetchResponse)
|
|
480
494
|
|
|
@@ -570,7 +584,7 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
570
584
|
}
|
|
571
585
|
|
|
572
586
|
const staticResponse = await profileDevStep(profile, 'static lookup', () =>
|
|
573
|
-
maybeStaticFile(config.publicPath, url.pathname),
|
|
587
|
+
maybeStaticFile(config.publicPath, url.pathname, exactNames),
|
|
574
588
|
)
|
|
575
589
|
if (staticResponse) {
|
|
576
590
|
setWorkUnitRoute('static-asset', 'static')
|
|
@@ -582,7 +596,11 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
582
596
|
.staticAssetPublicPrefixes()
|
|
583
597
|
.some(prefix => url.pathname.startsWith(prefix))
|
|
584
598
|
) {
|
|
585
|
-
const emitted = await maybeStaticFile(
|
|
599
|
+
const emitted = await maybeStaticFile(
|
|
600
|
+
path.join(config.outPath, 'public'),
|
|
601
|
+
url.pathname,
|
|
602
|
+
exactNames,
|
|
603
|
+
)
|
|
586
604
|
if (emitted) {
|
|
587
605
|
setWorkUnitRoute('static-asset', 'static')
|
|
588
606
|
return finish(applyProxyResponse(emitted, proxyResponse))
|
|
@@ -597,6 +615,7 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
597
615
|
const outPublicStatic = await maybeStaticFile(
|
|
598
616
|
path.join(config.outPath, 'public'),
|
|
599
617
|
staticAssetPathname,
|
|
618
|
+
exactNames,
|
|
600
619
|
)
|
|
601
620
|
if (outPublicStatic) {
|
|
602
621
|
setWorkUnitRoute('static-asset', 'static')
|
|
@@ -647,9 +666,6 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
647
666
|
}
|
|
648
667
|
}
|
|
649
668
|
|
|
650
|
-
const canonicalRedirect = trailingSlashRedirect(config, url, request.method.toUpperCase())
|
|
651
|
-
if (canonicalRedirect) return finish(applyProxyResponse(canonicalRedirect, proxyResponse))
|
|
652
|
-
|
|
653
669
|
const nav = parseNavState(request)
|
|
654
670
|
const matched = profileDevSyncStep(profile, 'match route', () =>
|
|
655
671
|
selectRouteForRequest(routes, url.pathname, nav),
|
|
@@ -1402,9 +1418,12 @@ async function maybeStaticMetadataFile(config: ResolvedConfig, url: URL) {
|
|
|
1402
1418
|
})
|
|
1403
1419
|
}
|
|
1404
1420
|
|
|
1405
|
-
async function maybeStaticFile(publicPath: string, pathname: string) {
|
|
1421
|
+
async function maybeStaticFile(publicPath: string, pathname: string, exactNames: ExactNames) {
|
|
1406
1422
|
const filePath = path.join(publicPath, pathname.replace(/^\/+/, ''))
|
|
1407
1423
|
if (!isInside(publicPath, filePath) || !existsSync(filePath)) return null
|
|
1424
|
+
if (exactNames && !hasExactName(exactNames, publicPath, path.relative(publicPath, filePath))) {
|
|
1425
|
+
return null
|
|
1426
|
+
}
|
|
1408
1427
|
const fileStat = await stat(filePath)
|
|
1409
1428
|
if (!fileStat.isFile()) return null
|
|
1410
1429
|
return devResponse(await readFile(filePath), contentType(filePath))
|
package/src/extensions.ts
CHANGED
|
@@ -80,6 +80,9 @@ export function createExtensionHost(): ExtensionHost {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
let activeHost = createExtensionHost()
|
|
83
|
+
// Anchored for modules that must not import this one (api/server, shared by embedded hosts).
|
|
84
|
+
const ANCHOR = Symbol.for('pnext.extensionHost')
|
|
85
|
+
;(globalThis as Record<symbol, unknown>)[ANCHOR] ??= activeHost
|
|
83
86
|
|
|
84
87
|
/** The host every accessor in this module reads. */
|
|
85
88
|
export function getExtensionHost(): ExtensionHost {
|
|
@@ -148,6 +151,7 @@ export function withExtensionHost<T>(host: ExtensionHost, callback: () => T): T
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
function announceHostChange() {
|
|
154
|
+
;(globalThis as Record<symbol, unknown>)[ANCHOR] = activeHost
|
|
151
155
|
for (const handler of resetHandlers) handler()
|
|
152
156
|
// Consumers latch the loadable-extension set (the server load plugin's filter
|
|
153
157
|
// regex); a swap changes it, so invalidate exactly as a registration would.
|
package/src/render/hooks.ts
CHANGED
|
@@ -66,12 +66,25 @@ export interface FontExtensions {
|
|
|
66
66
|
* the same memo the render reads. Default: none.
|
|
67
67
|
*/
|
|
68
68
|
prewarmFontAssets: (config: ResolvedConfig, options: { dev?: boolean }) => Promise<void>
|
|
69
|
+
|
|
70
|
+
/** Resolve every declared font for a release, keyed like the render looks them up. Default: none. */
|
|
71
|
+
releaseFonts: (config: ResolvedConfig) => Promise<Record<string, ReleasedFont>>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** A font resolution as a release stores it; production serves it instead of resolving. */
|
|
75
|
+
export interface ReleasedFont {
|
|
76
|
+
css: string
|
|
77
|
+
sizeAdjust: boolean
|
|
78
|
+
preloads: import('../types').MetadataLink[]
|
|
79
|
+
usesFonts: boolean
|
|
80
|
+
files: string[]
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
const fontExtensions: FontExtensions = {
|
|
72
84
|
runWithFontScope: callback => callback(),
|
|
73
85
|
collectFontAssets: () => Promise.resolve({ css: '', preloads: [] }),
|
|
74
86
|
prewarmFontAssets: () => Promise.resolve(),
|
|
87
|
+
releaseFonts: () => Promise.resolve({}),
|
|
75
88
|
}
|
|
76
89
|
|
|
77
90
|
export function getFontExtensions(): FontExtensions {
|