@wular/pnext 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/pnext +9 -2
- package/dist/server/_chunks/aliases-pycbtjt1.js +46 -0
- package/dist/server/_chunks/analyze-4d9e00g9.js +449 -0
- package/dist/server/_chunks/boot-bhemypxz.js +38 -0
- package/dist/server/_chunks/build-c991dv65.js +86 -0
- package/dist/server/_chunks/build-kh5e3x48.js +3341 -0
- package/dist/server/_chunks/build-tier-0a96kmx3.js +2456 -0
- package/dist/server/_chunks/compile-040r79gj.js +22 -0
- package/dist/server/_chunks/config-0tvz03a6.js +24 -0
- package/dist/server/_chunks/config-27rj7830.js +36 -0
- package/dist/server/_chunks/create-9rvwshsp.js +135 -0
- package/dist/server/_chunks/dev-ex9exynt.js +220 -0
- package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
- package/dist/server/_chunks/generate-myw9hef7.js +22 -0
- package/dist/server/_chunks/index-0r5eqfc7.js +279 -0
- package/dist/server/_chunks/index-0yjv5v47.js +105 -0
- package/dist/server/_chunks/index-11xpbfej.js +17 -0
- package/dist/server/_chunks/index-141vcwk6.js +109 -0
- package/dist/server/_chunks/index-1pzm1hdy.js +4130 -0
- package/dist/server/_chunks/index-29pq0kax.js +590 -0
- package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
- package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
- package/dist/server/_chunks/index-38xpdxwd.js +194 -0
- package/dist/server/_chunks/index-3e075kny.js +128 -0
- package/dist/server/_chunks/index-3ycf5ckv.js +472 -0
- package/dist/server/_chunks/index-4399bvd2.js +18 -0
- package/dist/server/_chunks/index-4da76t62.js +297 -0
- package/dist/server/_chunks/index-4t92hdxd.js +172 -0
- package/dist/server/_chunks/index-4zzebszd.js +10 -0
- package/dist/server/_chunks/index-52k54ykj.js +95 -0
- package/dist/server/_chunks/index-5hr4062s.js +70 -0
- package/dist/server/_chunks/index-68m3mwbd.js +84 -0
- package/dist/server/_chunks/index-6b009mt0.js +56 -0
- package/dist/server/_chunks/index-6gex3pfa.js +15 -0
- package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
- package/dist/server/_chunks/index-6q7zvrap.js +134 -0
- package/dist/server/_chunks/index-71885zaq.js +284 -0
- package/dist/server/_chunks/index-73z4esab.js +38 -0
- package/dist/server/_chunks/index-79ngvam8.js +60 -0
- package/dist/server/_chunks/index-7wc9n8be.js +25 -0
- package/dist/server/_chunks/index-8ct7rqy3.js +198 -0
- package/dist/server/_chunks/index-8kcxdfya.js +206 -0
- package/dist/server/_chunks/index-9ch50vtq.js +18 -0
- package/dist/server/_chunks/index-9f49w76j.js +213 -0
- package/dist/server/_chunks/index-9hz3s0m8.js +851 -0
- package/dist/server/_chunks/index-akkrvjn6.js +535 -0
- package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
- package/dist/server/_chunks/index-b7j671dj.js +207 -0
- package/dist/server/_chunks/index-bcws5eh2.js +35 -0
- package/dist/server/_chunks/index-bzd2ef7t.js +10 -0
- package/dist/server/_chunks/index-cjgqs13g.js +65 -0
- package/dist/server/_chunks/index-ckkdpht5.js +41 -0
- package/dist/server/_chunks/index-cn86z041.js +296 -0
- package/dist/server/_chunks/index-cvr4z22m.js +92 -0
- package/dist/server/_chunks/index-cyfednwb.js +87 -0
- package/dist/server/_chunks/index-d158y67j.js +152 -0
- package/dist/server/_chunks/index-d1jsmhhk.js +955 -0
- package/dist/server/_chunks/index-dg0f05zs.js +199 -0
- package/dist/server/_chunks/index-dgr390q7.js +9438 -0
- package/dist/server/_chunks/index-drwv61cc.js +185 -0
- package/dist/server/_chunks/index-e3a6yx84.js +18 -0
- package/dist/server/_chunks/index-e88tyv35.js +45 -0
- package/dist/server/_chunks/index-en7n9f7m.js +22 -0
- package/dist/server/_chunks/index-entm8bmz.js +28 -0
- package/dist/server/_chunks/index-evhd413j.js +57 -0
- package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
- package/dist/server/_chunks/index-fjv96re1.js +5295 -0
- package/dist/server/_chunks/index-fn1chkkd.js +214 -0
- package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
- package/dist/server/_chunks/index-gcmj16xy.js +92 -0
- package/dist/server/_chunks/index-gkndxkxf.js +736 -0
- package/dist/server/_chunks/index-grta8ap3.js +238 -0
- package/dist/server/_chunks/index-h2a70tg4.js +7 -0
- package/dist/server/_chunks/index-h4xy648y.js +51 -0
- package/dist/server/_chunks/index-hdbwtdv2.js +352 -0
- package/dist/server/_chunks/index-he6n2bvp.js +1270 -0
- package/dist/server/_chunks/index-j0m1jxqa.js +1253 -0
- package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
- package/dist/server/_chunks/index-j681c48a.js +2530 -0
- package/dist/server/_chunks/index-jbj7ehef.js +50 -0
- package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
- package/dist/server/_chunks/index-jks0x0a1.js +14 -0
- package/dist/server/_chunks/index-jn9rbhrx.js +1599 -0
- package/dist/server/_chunks/index-jt8e1pje.js +12 -0
- package/dist/server/_chunks/index-kdhxpwyq.js +483 -0
- package/dist/server/_chunks/index-knp0s912.js +7 -0
- package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
- package/dist/server/_chunks/index-kresp2n8.js +445 -0
- package/dist/server/_chunks/index-m63czgq5.js +590 -0
- package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
- package/dist/server/_chunks/index-n4hxpng2.js +11 -0
- package/dist/server/_chunks/index-n629dy38.js +1071 -0
- package/dist/server/_chunks/index-nf3df4jy.js +266 -0
- package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
- package/dist/server/_chunks/index-pym1cezq.js +39 -0
- package/dist/server/_chunks/index-q3r9z8mq.js +213 -0
- package/dist/server/_chunks/index-q738kkhj.js +100 -0
- package/dist/server/_chunks/index-qcrvt6er.js +112 -0
- package/dist/server/_chunks/index-qjj6gddn.js +54 -0
- package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
- package/dist/server/_chunks/index-r97ptz1q.js +97 -0
- package/dist/server/_chunks/index-ras0sdab.js +26 -0
- package/dist/server/_chunks/index-rcs322t1.js +19 -0
- package/dist/server/_chunks/index-rgj5mx84.js +101 -0
- package/dist/server/_chunks/index-rjegyfx4.js +1435 -0
- package/dist/server/_chunks/index-rt9qq1va.js +4 -0
- package/dist/server/_chunks/index-rthrsed5.js +356 -0
- package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
- package/dist/server/_chunks/index-stbk3jhn.js +31 -0
- package/dist/server/_chunks/index-tf4j19ge.js +130 -0
- package/dist/server/_chunks/index-tgcakdxc.js +125 -0
- package/dist/server/_chunks/index-tgsfjmep.js +74 -0
- package/dist/server/_chunks/index-tq1f96v7.js +51 -0
- package/dist/server/_chunks/index-tq3b39a5.js +107 -0
- package/dist/server/_chunks/index-typcbcsv.js +819 -0
- package/dist/server/_chunks/index-v1ags1na.js +132 -0
- package/dist/server/_chunks/index-vmr35jjw.js +170 -0
- package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
- package/dist/server/_chunks/index-vz0km5qk.js +33 -0
- package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
- package/dist/server/_chunks/index-web361b8.js +138 -0
- package/dist/server/_chunks/index-wm36rj4v.js +311 -0
- package/dist/server/_chunks/index-x0y005nh.js +283 -0
- package/dist/server/_chunks/index-x2m17v9c.js +6166 -0
- package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
- package/dist/server/_chunks/index-x9c55pzy.js +871 -0
- package/dist/server/_chunks/index-xh1nbk46.js +1299 -0
- package/dist/server/_chunks/index-xvj80c3a.js +30 -0
- package/dist/server/_chunks/index-xywjg2vc.js +100 -0
- package/dist/server/_chunks/index-y4d02znn.js +66 -0
- package/dist/server/_chunks/index-y7mzvq2q.js +110 -0
- package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
- package/dist/server/_chunks/index-yhxkxghe.js +56 -0
- package/dist/server/_chunks/index-yrjkqtfj.js +86 -0
- package/dist/server/_chunks/index-z88qv16t.js +11 -0
- package/dist/server/_chunks/index-zfrwq472.js +154 -0
- package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
- package/dist/server/_chunks/loader-5en7wpt5.js +80 -0
- package/dist/server/_chunks/modules-t92favpj.js +76 -0
- package/dist/server/_chunks/pipeline-4t9q43ht.js +836 -0
- package/dist/server/_chunks/production-385bw8df.js +55 -0
- package/dist/server/_chunks/proxy-config-60gprphe.js +23 -0
- package/dist/server/_chunks/proxy-gfhmktbk.js +35 -0
- package/dist/server/_chunks/router-xnrva921.js +501 -0
- package/dist/server/_chunks/routes-ht868pdc.js +66 -0
- package/dist/server/_chunks/run-d40d63ag.js +697 -0
- package/dist/server/_chunks/server-2p8fgqq2.js +1839 -0
- package/dist/server/_chunks/tsconfig-defaults-bcn34eqb.js +21 -0
- package/dist/server/_chunks/typegen-dvtcjtaw.js +37 -0
- package/dist/server/api/client-cache.js +14 -0
- package/dist/server/cli/index.js +375 -0
- package/dist/server/cli/start.js +158 -0
- package/dist/server/client/reference.js +16 -0
- package/dist/server/compat/next/cache.js +56 -0
- package/dist/server/compat/next/canonical-url.js +13 -0
- package/dist/server/compat/next/client-cache.js +57 -0
- package/dist/server/compat/next/client-navigation.js +232 -0
- package/dist/server/compat/next/client-only.js +1 -0
- package/dist/server/compat/next/client-script.js +178 -0
- package/dist/server/compat/next/client-server.js +34 -0
- package/dist/server/compat/next/config-headers.js +34 -0
- package/dist/server/compat/next/config-loader.js +25 -0
- package/dist/server/compat/next/config.js +10 -0
- package/dist/server/compat/next/constants.js +18 -0
- package/dist/server/compat/next/custom-server.js +10 -0
- package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
- package/dist/server/compat/next/dynamic.js +21 -0
- package/dist/server/compat/next/error.js +112 -0
- package/dist/server/compat/next/font/cache.js +16 -0
- package/dist/server/compat/next/font/google.js +3 -0
- package/dist/server/compat/next/font/index.js +1 -0
- package/dist/server/compat/next/font/local.js +24 -0
- package/dist/server/compat/next/font/runtime-client.js +33 -0
- package/dist/server/compat/next/font/runtime.js +43 -0
- package/dist/server/compat/next/font/shared.js +22 -0
- package/dist/server/compat/next/form.js +129 -0
- package/dist/server/compat/next/head.js +10 -0
- package/dist/server/compat/next/headers.js +30 -0
- package/dist/server/compat/next/image/client.js +11 -0
- package/dist/server/compat/next/image/config.js +18 -0
- package/dist/server/compat/next/image/optimizer.js +25 -0
- package/dist/server/compat/next/image/patterns.js +12 -0
- package/dist/server/compat/next/image/props.js +16 -0
- package/dist/server/compat/next/image/shared.js +86 -0
- package/dist/server/compat/next/image/static-metadata.js +32 -0
- package/dist/server/compat/next/image/validate.js +8 -0
- package/dist/server/compat/next/image.js +59 -0
- package/dist/server/compat/next/index.js +1 -0
- package/dist/server/compat/next/legacy-image.js +78 -0
- package/dist/server/compat/next/legacy-request-apis.js +24 -0
- package/dist/server/compat/next/link-transform.js +15 -0
- package/dist/server/compat/next/link.js +14 -0
- package/dist/server/compat/next/navigation.js +191 -0
- package/dist/server/compat/next/offline.js +45 -0
- package/dist/server/compat/next/og.js +8 -0
- package/dist/server/compat/next/preferred-region.js +8 -0
- package/dist/server/compat/next/redirects.js +32 -0
- package/dist/server/compat/next/resource-hints.js +30 -0
- package/dist/server/compat/next/rewrites.js +43 -0
- package/dist/server/compat/next/root-params.js +121 -0
- package/dist/server/compat/next/route-state.js +23 -0
- package/dist/server/compat/next/router.js +103 -0
- package/dist/server/compat/next/script.js +37 -0
- package/dist/server/compat/next/server-only.js +1 -0
- package/dist/server/compat/next/server.js +131 -0
- package/dist/server/compat/next/svgr.js +14 -0
- package/dist/server/compat/next/telemetry.js +10 -0
- package/dist/server/compat/next/usage.js +13 -0
- package/dist/server/compat/next/user-agent.js +12 -0
- package/dist/server/compat/next/web-vitals.js +35 -0
- package/dist/server/compat/react/action-state.js +11 -0
- package/dist/server/compat/react/client-lite.js +83 -0
- package/dist/server/compat/react/client.js +131 -0
- package/dist/server/compat/react/compiler-runtime.js +42 -0
- package/dist/server/compat/react/dom-client.js +106 -0
- package/dist/server/compat/react/dom-react-server.js +37 -0
- package/dist/server/compat/react/dom-server.js +40 -0
- package/dist/server/compat/react/dom.js +52 -0
- package/dist/server/compat/react/hooks-extra.js +12 -0
- package/dist/server/compat/react/internals.js +14 -0
- package/dist/server/compat/react/parity.js +11 -0
- package/dist/server/compat/react/preact.js +113 -0
- package/dist/server/compat/react/react-server.js +133 -0
- package/dist/server/compat/react/router-shim.js +8 -0
- package/dist/server/compat/react/server-component-use.js +14 -0
- package/dist/server/compat/react/server-inserted-html.js +14 -0
- package/dist/server/compat/react/server.js +194 -0
- package/dist/server/compat/react/style-values.js +10 -0
- package/dist/server/compat/react/use.js +10 -0
- package/dist/server/compat/react/view-transition.js +12 -0
- package/dist/server/generation.json +1 -0
- package/package.json +4 -1
- package/reference/compat.md +1 -1
- package/reference/config.md +2 -2
- package/reference/dev.md +1 -1
- package/reference/getting-started.md +1 -1
- package/reference/rendering.md +4 -4
- package/src/api/dynamic.tsx +86 -4
- package/src/api/server.ts +24 -6
- package/src/cli/adapters/vercel-warm.ts +327 -62
- package/src/cli/adapters/vercel.ts +164 -1054
- package/src/cli/analyze.ts +3 -2
- package/src/cli/build/cache.ts +6 -6
- package/src/cli/build.ts +78 -45
- package/src/cli/index.ts +21 -3
- package/src/cli/serve/immutable.ts +31 -0
- package/src/cli/serve/pipeline.ts +97 -93
- package/src/cli/serve/standalone-worker.ts +8 -0
- package/src/cli/serve/standalone.ts +703 -0
- package/src/cli/start.ts +31 -8
- package/src/client/build.ts +1 -1
- package/src/client/chunk-fold.ts +19 -6
- package/src/client/react-tier.ts +3 -2
- package/src/client/reference-stub.ts +23 -36
- package/src/compat/actions/client-plugin.ts +4 -2
- package/src/compat/actions/config.ts +6 -5
- package/src/compat/actions/extensions.ts +5 -5
- package/src/compat/aliases.ts +8 -1
- package/src/compat/bundler/config.ts +88 -0
- package/src/compat/bundler/optimize-package-imports.ts +86 -26
- package/src/compat/bundler/relay-transform.ts +15 -3
- package/src/compat/bundler/require-context.ts +2 -1
- package/src/compat/bundler/webpack-loaders.ts +3 -2
- package/src/compat/bundler/worker.ts +2 -2
- package/src/compat/cache-control.ts +16 -8
- package/src/compat/css/inline-css.ts +1 -1
- package/src/compat/css/modules.ts +18 -5
- package/src/compat/export/build-complete.ts +1 -1
- package/src/compat/export/emit.ts +4 -4
- package/src/compat/export/standalone.ts +30 -65
- package/src/compat/image-optimizer/optimize.ts +1 -1
- package/src/compat/lifecycle/error-funnel.ts +1 -1
- package/src/compat/lifecycle/instrumentation-client.ts +4 -3
- package/src/compat/lifecycle/instrumentation.ts +117 -24
- package/src/compat/lifecycle/testmode.ts +3 -2
- package/src/compat/metadata-artifacts.ts +1 -1
- package/src/compat/next/config-loader.ts +140 -13
- package/src/compat/next/dynamic.tsx +10 -23
- package/src/compat/next/font/cache.ts +2 -1
- package/src/compat/next/font/runtime.ts +23 -3
- package/src/compat/next/og.ts +3 -3
- package/src/compat/next/usage.ts +3 -2
- package/src/compat/pages/api.ts +83 -14
- package/src/compat/pages/router.ts +30 -14
- package/src/compat/register/bundler.ts +3 -1
- package/src/compat/register/image.ts +1 -1
- package/src/compat/register/middleware.ts +1 -1
- package/src/compat/register/otel.ts +5 -9
- package/src/compat/register/render.ts +3 -1
- package/src/compat/register/use-cache.ts +3 -1
- package/src/compat/release.ts +46 -0
- package/src/compat/segment/serve.ts +1 -1
- package/src/compat/typecheck/check.ts +6 -4
- package/src/compat/validation/validate.ts +10 -7
- package/src/config.ts +76 -9
- package/src/css/assets.ts +213 -0
- package/src/css/build.ts +190 -247
- package/src/dev/client-chunk-store.ts +2 -1
- package/src/dev/restart/client-key.ts +2 -1
- package/src/dev/restart/global-css.ts +2 -1
- package/src/dev/restart/route-bundle-key.ts +2 -1
- package/src/dev/restart/route-facts.ts +2 -1
- package/src/dev/server.ts +34 -14
- package/src/extensions.ts +4 -0
- package/src/out-paths.ts +10 -0
- package/src/render/hooks.ts +13 -0
- package/src/render/renderer.ts +53 -33
- package/src/request/context.ts +9 -0
- package/src/resolve/dynamic.ts +7 -1
- package/src/resolve/engine.ts +2 -12
- package/src/resolve/imports.ts +12 -52
- package/src/resolve/package-json.ts +56 -0
- package/src/resolve/scan-facts.ts +250 -1
- package/src/routing/href.ts +10 -3
- package/src/routing/match.ts +287 -0
- package/src/routing/metadata-files.ts +20 -6
- package/src/routing/proxy-config.ts +137 -0
- package/src/routing/proxy.ts +35 -134
- package/src/routing/routes.ts +22 -281
- package/src/runtime/fingerprint.ts +23 -8
- package/src/runtime/load.ts +170 -0
- package/src/runtime/loader.ts +218 -44
- package/src/runtime/module-cache.ts +15 -1
- package/src/runtime/modules.ts +405 -82
- package/src/runtime/prebundle.ts +101 -0
- package/src/runtime/production.ts +456 -0
- package/src/runtime/release-graph.ts +342 -0
- package/src/runtime/vendor-build.ts +750 -17
- package/src/runtime/vendor.ts +16 -3
- package/src/types.ts +4 -3
- package/src/utils/directive.ts +40 -0
- package/src/utils/fs.ts +95 -4
- package/src/utils/resource-query.ts +12 -0
- package/src/cli/serve/entry.ts +0 -45
|
@@ -20,6 +20,7 @@ import { setRouteFactsStore, type RouteFacts, type RouteFactsStore } from '../..
|
|
|
20
20
|
import { traceEnabled } from '../../utils/trace-flags'
|
|
21
21
|
import { restartCacheEnabled } from './enabled'
|
|
22
22
|
import { hash, lazyRecordCacheKey, revalidate, sourceEntry, type SourceEntry } from './record'
|
|
23
|
+
import { outCachePath } from '../../out-paths'
|
|
23
24
|
|
|
24
25
|
interface RecordFile {
|
|
25
26
|
version: number
|
|
@@ -45,7 +46,7 @@ export function installRouteFactsCache(config: ResolvedConfig) {
|
|
|
45
46
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
46
47
|
if (process.env.PNEXT_DEV_FACTS_CACHE === '0') return
|
|
47
48
|
const cache: FactsCache = {
|
|
48
|
-
dir: path.join(config.outPath, '
|
|
49
|
+
dir: path.join(outCachePath(config.outPath), 'route-facts'),
|
|
49
50
|
key: lazyRecordCacheKey(config, RECORD_VERSION),
|
|
50
51
|
written: new Set(),
|
|
51
52
|
}
|
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 {
|
|
@@ -114,6 +121,7 @@ import { cacheRoot, setDevWatcherFreshness } from '../runtime/module-cache'
|
|
|
114
121
|
import { abortUpstreamFetchOnDisconnect } from '../runtime/fetch-host'
|
|
115
122
|
import { markBoot } from '../cli/boot/trace'
|
|
116
123
|
import { formatDuration } from '../utils/verbose'
|
|
124
|
+
import { outCachePath } from '../out-paths'
|
|
117
125
|
|
|
118
126
|
interface DevServerOptions {
|
|
119
127
|
config: ResolvedConfig
|
|
@@ -210,7 +218,7 @@ async function evictStaleClientCaches(outPath: string) {
|
|
|
210
218
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
211
219
|
const keep = Number(process.env.PNEXT_DEV_CLIENT_CACHE_KEEP || 32)
|
|
212
220
|
if (!Number.isFinite(keep) || keep <= 0) return
|
|
213
|
-
const clientRoot = path.join(outPath, '
|
|
221
|
+
const clientRoot = path.join(outCachePath(outPath), 'client')
|
|
214
222
|
try {
|
|
215
223
|
const entries = await readdir(clientRoot)
|
|
216
224
|
if (entries.length <= keep) return
|
|
@@ -290,6 +298,7 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
290
298
|
markBoot('boot:scanRoutes')
|
|
291
299
|
await validateProxyFiles(config)
|
|
292
300
|
let proxyRunner = createProxyRunner(config)
|
|
301
|
+
const exactNames = exactNameIndex(config.root)
|
|
293
302
|
markBoot('boot:proxy')
|
|
294
303
|
let devImportVersion = String(Date.now())
|
|
295
304
|
// The proxy runs serially in front of every request, so its compile+import is
|
|
@@ -436,6 +445,8 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
436
445
|
if (badRequest) return badRequest
|
|
437
446
|
request = withForwardedHeaders(request, server)
|
|
438
447
|
let url = new URL(request.url)
|
|
448
|
+
const slashRedirect = repeatedSlashRedirect(url)
|
|
449
|
+
if (slashRedirect) return slashRedirect
|
|
439
450
|
const profile = devRequestProfile(request, url)
|
|
440
451
|
if (profile) logDevProfile(profile, 'prologue (bootstrap/headers/url)', prologueStart)
|
|
441
452
|
let pageLog = startDevPageStallTimer(pendingDevPageLoadLog(routes, request, url))
|
|
@@ -475,6 +486,10 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
475
486
|
}
|
|
476
487
|
|
|
477
488
|
try {
|
|
489
|
+
// Before the proxy, for every method, as in Next: the proxy only ever sees canonical paths.
|
|
490
|
+
const canonicalRedirect = trailingSlashRedirect(config, url)
|
|
491
|
+
if (canonicalRedirect) return finish(canonicalRedirect)
|
|
492
|
+
|
|
478
493
|
const initialPrefetchResponse = maybeDevPagePrefetchResponse(routes, url.pathname, request)
|
|
479
494
|
if (initialPrefetchResponse) return finish(initialPrefetchResponse)
|
|
480
495
|
|
|
@@ -570,7 +585,7 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
570
585
|
}
|
|
571
586
|
|
|
572
587
|
const staticResponse = await profileDevStep(profile, 'static lookup', () =>
|
|
573
|
-
maybeStaticFile(config.publicPath, url.pathname),
|
|
588
|
+
maybeStaticFile(config.publicPath, url.pathname, exactNames),
|
|
574
589
|
)
|
|
575
590
|
if (staticResponse) {
|
|
576
591
|
setWorkUnitRoute('static-asset', 'static')
|
|
@@ -582,7 +597,11 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
582
597
|
.staticAssetPublicPrefixes()
|
|
583
598
|
.some(prefix => url.pathname.startsWith(prefix))
|
|
584
599
|
) {
|
|
585
|
-
const emitted = await maybeStaticFile(
|
|
600
|
+
const emitted = await maybeStaticFile(
|
|
601
|
+
path.join(config.outPath, 'static'),
|
|
602
|
+
url.pathname,
|
|
603
|
+
exactNames,
|
|
604
|
+
)
|
|
586
605
|
if (emitted) {
|
|
587
606
|
setWorkUnitRoute('static-asset', 'static')
|
|
588
607
|
return finish(applyProxyResponse(emitted, proxyResponse))
|
|
@@ -595,8 +614,9 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
595
614
|
)
|
|
596
615
|
if (staticAssetPathname) {
|
|
597
616
|
const outPublicStatic = await maybeStaticFile(
|
|
598
|
-
path.join(config.outPath, '
|
|
617
|
+
path.join(config.outPath, 'static'),
|
|
599
618
|
staticAssetPathname,
|
|
619
|
+
exactNames,
|
|
600
620
|
)
|
|
601
621
|
if (outPublicStatic) {
|
|
602
622
|
setWorkUnitRoute('static-asset', 'static')
|
|
@@ -647,9 +667,6 @@ export async function startDevServer(options: DevServerOptions) {
|
|
|
647
667
|
}
|
|
648
668
|
}
|
|
649
669
|
|
|
650
|
-
const canonicalRedirect = trailingSlashRedirect(config, url, request.method.toUpperCase())
|
|
651
|
-
if (canonicalRedirect) return finish(applyProxyResponse(canonicalRedirect, proxyResponse))
|
|
652
|
-
|
|
653
670
|
const nav = parseNavState(request)
|
|
654
671
|
const matched = profileDevSyncStep(profile, 'match route', () =>
|
|
655
672
|
selectRouteForRequest(routes, url.pathname, nav),
|
|
@@ -1258,7 +1275,7 @@ async function buildDevClient(config: ResolvedConfig, route: RouteManifestEntry)
|
|
|
1258
1275
|
batchRoutes.length === 1
|
|
1259
1276
|
? cacheKeys[0]!
|
|
1260
1277
|
: `batch-${clientSourceHash([...cacheKeys].sort().join('\n'))}`
|
|
1261
|
-
const outDir = path.join(config.outPath, '
|
|
1278
|
+
const outDir = path.join(outCachePath(config.outPath), 'client', cacheKey)
|
|
1262
1279
|
const outFile = path.join(outDir, `${clientEntryName(route)}.js`)
|
|
1263
1280
|
|
|
1264
1281
|
// Dedup in-flight builds first. A single page view fires up to three requests
|
|
@@ -1345,7 +1362,7 @@ async function resolveDevClientChunk(config: ResolvedConfig, name: string) {
|
|
|
1345
1362
|
const settled = clientChunks.get(name)
|
|
1346
1363
|
if (settled && existsSync(settled)) return settled
|
|
1347
1364
|
|
|
1348
|
-
const clientRoot = path.join(config.outPath, '
|
|
1365
|
+
const clientRoot = path.join(outCachePath(config.outPath), 'client')
|
|
1349
1366
|
for (const generation of await readdir(clientRoot).catch(() => [])) {
|
|
1350
1367
|
const chunksDir = path.join(clientRoot, generation, 'chunks')
|
|
1351
1368
|
const file = path.join(chunksDir, name)
|
|
@@ -1402,9 +1419,12 @@ async function maybeStaticMetadataFile(config: ResolvedConfig, url: URL) {
|
|
|
1402
1419
|
})
|
|
1403
1420
|
}
|
|
1404
1421
|
|
|
1405
|
-
async function maybeStaticFile(publicPath: string, pathname: string) {
|
|
1422
|
+
async function maybeStaticFile(publicPath: string, pathname: string, exactNames: ExactNames) {
|
|
1406
1423
|
const filePath = path.join(publicPath, pathname.replace(/^\/+/, ''))
|
|
1407
1424
|
if (!isInside(publicPath, filePath) || !existsSync(filePath)) return null
|
|
1425
|
+
if (exactNames && !hasExactName(exactNames, publicPath, path.relative(publicPath, filePath))) {
|
|
1426
|
+
return null
|
|
1427
|
+
}
|
|
1408
1428
|
const fileStat = await stat(filePath)
|
|
1409
1429
|
if (!fileStat.isFile()) return null
|
|
1410
1430
|
return devResponse(await readFile(filePath), contentType(filePath))
|
|
@@ -1481,8 +1501,8 @@ async function maybeBuiltAsset(
|
|
|
1481
1501
|
}
|
|
1482
1502
|
|
|
1483
1503
|
const outPath = config.outPath
|
|
1484
|
-
const filePath = path.join(outPath,
|
|
1485
|
-
if (!isInside(path.join(outPath
|
|
1504
|
+
const filePath = path.join(outCachePath(outPath), pathname.replace(/^\/+/, ''))
|
|
1505
|
+
if (!isInside(path.join(outCachePath(outPath)), filePath) || !existsSync(filePath)) return null
|
|
1486
1506
|
const fileStat = await stat(filePath)
|
|
1487
1507
|
if (!fileStat.isFile()) return null
|
|
1488
1508
|
return new Response(await readFile(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/out-paths.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
/** The release a build writes under the out root: everything a production server reads. */
|
|
4
|
+
export const standaloneOutSegment = 'standalone'
|
|
5
|
+
|
|
6
|
+
/** The build cache beside a release (`<outRoot>/cache`); dev keeps its own. */
|
|
7
|
+
export function outCachePath(outPath: string) {
|
|
8
|
+
const owner = path.basename(outPath) === standaloneOutSegment ? path.dirname(outPath) : outPath
|
|
9
|
+
return path.join(owner, 'cache')
|
|
10
|
+
}
|
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 {
|
package/src/render/renderer.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { stat, unlink, writeFile } from 'node:fs/promises'
|
|
|
3
3
|
import { basename, dirname, join, relative, sep } from 'node:path'
|
|
4
4
|
import { createHash } from 'node:crypto'
|
|
5
5
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
6
|
-
import { drainPreplanBuilds } from '../runtime/vendor'
|
|
7
6
|
import {
|
|
8
7
|
Component,
|
|
9
8
|
Fragment,
|
|
@@ -29,10 +28,13 @@ import { markErrorLogged } from '../utils/error-log'
|
|
|
29
28
|
import {
|
|
30
29
|
devClientModuleHref,
|
|
31
30
|
devServerModuleHref,
|
|
31
|
+
drainPreplanBuilds,
|
|
32
32
|
importDevModule,
|
|
33
33
|
importModuleOnce,
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
registerServerRuntime,
|
|
35
|
+
serverBundleTargetForRuntime,
|
|
36
|
+
} from '../runtime/load'
|
|
37
|
+
import { conventionFileExists, productionRelease, servedConventions } from '../runtime/production'
|
|
36
38
|
import {
|
|
37
39
|
getActionModuleExtensions,
|
|
38
40
|
getActiveMetadataExtensions,
|
|
@@ -63,7 +65,7 @@ import {
|
|
|
63
65
|
routeCssAssetNames,
|
|
64
66
|
routeCssHref,
|
|
65
67
|
withAssetPrefix,
|
|
66
|
-
} from '../css/
|
|
68
|
+
} from '../css/assets'
|
|
67
69
|
import { dynamicReferenceSymbol, type DynamicReference } from '../api/dynamic'
|
|
68
70
|
import {
|
|
69
71
|
isForbiddenError,
|
|
@@ -98,13 +100,11 @@ import {
|
|
|
98
100
|
trackPrerenderDynamic,
|
|
99
101
|
} from './ppr'
|
|
100
102
|
import {
|
|
101
|
-
collectFileCss,
|
|
102
|
-
collectNotFoundCss,
|
|
103
103
|
findConventionFiles,
|
|
104
104
|
findGlobalError,
|
|
105
105
|
findLayouts,
|
|
106
106
|
serverActionsUnsupportedMessage,
|
|
107
|
-
} from '../routing/
|
|
107
|
+
} from '../routing/match'
|
|
108
108
|
import { matchSegments, pathnameSegments, slotDirectoriesIn } from '../routing/slots'
|
|
109
109
|
import { getRequestRuntime } from '../routing/request-environment'
|
|
110
110
|
import { toNextRequest } from '../api/server'
|
|
@@ -121,7 +121,6 @@ import {
|
|
|
121
121
|
ISLAND_BOUNDARY_ERROR_MESSAGE_ATTRIBUTE,
|
|
122
122
|
} from './boundary-error'
|
|
123
123
|
import { captureCacheScope, runWithCacheScope } from '../request/cache'
|
|
124
|
-
import { registerServerRuntime } from '../runtime/loader'
|
|
125
124
|
import { readText } from '../utils/fs'
|
|
126
125
|
import { traceEnabled } from '../utils/trace-flags'
|
|
127
126
|
import {
|
|
@@ -804,7 +803,7 @@ function moduleHref(file: string, options: ModuleLoadOptions) {
|
|
|
804
803
|
? devServerModuleHref(options.config, file, options.devImportVersion ?? String(Date.now()), {
|
|
805
804
|
conditionTarget,
|
|
806
805
|
})
|
|
807
|
-
: reactCompatEnabled(options.config)
|
|
806
|
+
: reactCompatEnabled(options.config) || productionRelease(options.config)
|
|
808
807
|
? devServerModuleHref(options.config, file, 'build', { conditionTarget })
|
|
809
808
|
: pathToFileHref(file)
|
|
810
809
|
}
|
|
@@ -851,6 +850,17 @@ async function importClientModule(file: string, options: ModuleLoadOptions) {
|
|
|
851
850
|
return importModuleOnce<Record<string, unknown>>(href)
|
|
852
851
|
}
|
|
853
852
|
|
|
853
|
+
/** A synthetic route's CSS: in a release, the stylesheet its build emitted; else a source scan. */
|
|
854
|
+
async function syntheticRouteCss(
|
|
855
|
+
config: ResolvedConfig,
|
|
856
|
+
id: string,
|
|
857
|
+
scan: (routes: typeof import('../routing/routes')) => Promise<string[]>,
|
|
858
|
+
) {
|
|
859
|
+
if (!productionRelease(config)) return scan(await import('../routing/routes'))
|
|
860
|
+
const name = `${id}.css`
|
|
861
|
+
return emittedAssetName(config, name) === name ? [] : [name]
|
|
862
|
+
}
|
|
863
|
+
|
|
854
864
|
function clientScriptPath(route: RouteManifestEntry, dev?: boolean) {
|
|
855
865
|
return dev
|
|
856
866
|
? `/__pnext/client/${route.id}.js`
|
|
@@ -1530,7 +1540,7 @@ async function serializablePageProps(props: PageProps, omitSearchParams = false)
|
|
|
1530
1540
|
|
|
1531
1541
|
export async function staticParamsFor(config: ResolvedConfig, route: RouteManifestEntry) {
|
|
1532
1542
|
const moduleFiles = [
|
|
1533
|
-
...findLayouts(config.appPath, route.file).filter(
|
|
1543
|
+
...findLayouts(config.appPath, route.file).filter(conventionFileExists),
|
|
1534
1544
|
route.file,
|
|
1535
1545
|
]
|
|
1536
1546
|
let paramSets: Record<string, RouteParamValue>[] = [{}]
|
|
@@ -1615,7 +1625,7 @@ export async function renderPage(options: RenderOptions) {
|
|
|
1615
1625
|
export async function renderPageWithStatus(
|
|
1616
1626
|
options: RenderOptions,
|
|
1617
1627
|
): Promise<{ html: string; status: number; location?: string }> {
|
|
1618
|
-
registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1628
|
+
await registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1619
1629
|
await seedPrerenderSidecar(options)
|
|
1620
1630
|
const request = renderScopeRequest(options)
|
|
1621
1631
|
return runWithRequest(
|
|
@@ -1648,7 +1658,7 @@ export async function renderPageWithStatus(
|
|
|
1648
1658
|
}
|
|
1649
1659
|
|
|
1650
1660
|
export async function renderPageStream(options: RenderOptions) {
|
|
1651
|
-
registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1661
|
+
await registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1652
1662
|
await seedPrerenderSidecar(options)
|
|
1653
1663
|
|
|
1654
1664
|
const request = renderScopeRequest(options)
|
|
@@ -1666,7 +1676,7 @@ export async function renderPageStream(options: RenderOptions) {
|
|
|
1666
1676
|
}
|
|
1667
1677
|
|
|
1668
1678
|
export async function renderPageResponse(options: RenderOptions) {
|
|
1669
|
-
registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1679
|
+
await registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1670
1680
|
const method = options.request?.method.toUpperCase() ?? 'GET'
|
|
1671
1681
|
if (method !== 'GET' && method !== 'HEAD') {
|
|
1672
1682
|
return new Response('Method Not Allowed', {
|
|
@@ -1871,7 +1881,7 @@ const rejectedPprShellUpgrades = new Set<string>()
|
|
|
1871
1881
|
* when dynamic data escapes every boundary - the route must then be served fully dynamically.
|
|
1872
1882
|
*/
|
|
1873
1883
|
export async function renderPartialShell(options: RenderOptions): Promise<PrebuiltShell | null> {
|
|
1874
|
-
registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1884
|
+
await registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1875
1885
|
const sidecar = getRenderExtensions().prerenderSidecar
|
|
1876
1886
|
const sidecarContext = prerenderSidecarContext(options)
|
|
1877
1887
|
await sidecar.begin(sidecarContext)
|
|
@@ -1960,7 +1970,7 @@ export async function renderPartialShell(options: RenderOptions): Promise<Prebui
|
|
|
1960
1970
|
export async function renderRuntimePrefetchDocument(
|
|
1961
1971
|
options: RenderOptions,
|
|
1962
1972
|
): Promise<{ html: string; postponed: boolean } | null> {
|
|
1963
|
-
registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1973
|
+
await registerServerRuntime(options.config, options.route.sourceFiles)
|
|
1964
1974
|
// Seed (read-only) the resume-data sidecar so 'use cache' scopes resolve
|
|
1965
1975
|
// their build-time fills; unlike renderPartialShell nothing is collected or
|
|
1966
1976
|
// persisted back.
|
|
@@ -2512,7 +2522,7 @@ function hasParamFreeRootLayout(config: ResolvedConfig): boolean {
|
|
|
2512
2522
|
const cached = paramFreeRootLayoutCache.get(config.appPath)
|
|
2513
2523
|
if (cached !== undefined) return cached
|
|
2514
2524
|
const found = ['tsx', 'jsx', 'ts', 'js'].some(ext =>
|
|
2515
|
-
|
|
2525
|
+
conventionFileExists(join(config.appPath, `layout.${ext}`)),
|
|
2516
2526
|
)
|
|
2517
2527
|
paramFreeRootLayoutCache.set(config.appPath, found)
|
|
2518
2528
|
return found
|
|
@@ -2636,7 +2646,7 @@ export async function renderGlobalNotFoundResponse(
|
|
|
2636
2646
|
) {
|
|
2637
2647
|
const globalFile = ['tsx', 'ts', 'jsx', 'js']
|
|
2638
2648
|
.map(ext => `${options.config.appPath}/global-not-found.${ext}`)
|
|
2639
|
-
.find(
|
|
2649
|
+
.find(conventionFileExists)
|
|
2640
2650
|
// Render as GET regardless of the original method: the 404 page is what a
|
|
2641
2651
|
// browser should see for a stray POST too (Next's MPA fallback), not a 405.
|
|
2642
2652
|
const notFoundRequest = options.request
|
|
@@ -2664,9 +2674,9 @@ export async function renderGlobalNotFoundResponse(
|
|
|
2664
2674
|
// Include CSS shared with the root layout: this document replaces the
|
|
2665
2675
|
// whole page (no root layout render), so the global sheet isn't linked
|
|
2666
2676
|
// and anything it covered must ship in this route's own chunk.
|
|
2667
|
-
cssImports: await
|
|
2668
|
-
includeGlobalCss: true,
|
|
2669
|
-
|
|
2677
|
+
cssImports: await syntheticRouteCss(options.config, 'global-not-found', routes =>
|
|
2678
|
+
routes.collectFileCss(options.config.appPath, [globalFile], { includeGlobalCss: true }),
|
|
2679
|
+
),
|
|
2670
2680
|
sourceFiles: [globalFile],
|
|
2671
2681
|
synthetic: true,
|
|
2672
2682
|
}
|
|
@@ -2706,7 +2716,9 @@ export async function renderGlobalNotFoundResponse(
|
|
|
2706
2716
|
clientReferences: rootRoute?.clientReferences ?? [],
|
|
2707
2717
|
// Root not-found ships its own CSS (`/assets/not-found.css`) alongside the
|
|
2708
2718
|
// root-layout global sheet (`/assets/global.css`, emitted via globalCssHref).
|
|
2709
|
-
cssImports: await
|
|
2719
|
+
cssImports: await syntheticRouteCss(options.config, 'not-found', routes =>
|
|
2720
|
+
routes.collectNotFoundCss(options.config.appPath),
|
|
2721
|
+
),
|
|
2710
2722
|
sourceFiles: rootRoute?.sourceFiles ?? [anchor],
|
|
2711
2723
|
...(rootRoute?.needsRouterEntry ? { needsRouterEntry: true } : {}),
|
|
2712
2724
|
// Serve the ROOT route's built client entry: the synthetic id has no
|
|
@@ -2863,6 +2875,8 @@ const documentLayoutDefaults = new Map<string, { mtimeMs: number; hasDefault: bo
|
|
|
2863
2875
|
async function routeHasDocumentLayout(layoutFiles: string[]) {
|
|
2864
2876
|
const rootLayout = layoutFiles[0]
|
|
2865
2877
|
if (!rootLayout) return false
|
|
2878
|
+
const served = servedConventions()
|
|
2879
|
+
if (served) return served.documentLayouts.has(rootLayout)
|
|
2866
2880
|
let mtimeMs: number
|
|
2867
2881
|
try {
|
|
2868
2882
|
mtimeMs = statSync(rootLayout).mtimeMs
|
|
@@ -2923,7 +2937,7 @@ async function pageRender(options: RenderOptions, stream: boolean): Promise<Page
|
|
|
2923
2937
|
// Drop the non-existent anchor file so we don't try to import it; the
|
|
2924
2938
|
// layout's `children` is supplied by the `@children` slot instead (see
|
|
2925
2939
|
// childrenFromSlots).
|
|
2926
|
-
if (pageFile && !
|
|
2940
|
+
if (pageFile && !conventionFileExists(pageFile)) pageFile = undefined
|
|
2927
2941
|
}
|
|
2928
2942
|
const props = profileRenderSyncStep(profile, 'create page props', () =>
|
|
2929
2943
|
createPageProps(options),
|
|
@@ -3254,7 +3268,7 @@ async function renderAuthInterruptPage(
|
|
|
3254
3268
|
const fallbackTree = httpAccessFallbackTree(status, message)
|
|
3255
3269
|
const file = nearestConventionFile(options, `${kind}.tsx`)
|
|
3256
3270
|
const boundaryOptions = optionsForNotFoundBoundary(options, file)
|
|
3257
|
-
if (!file || !
|
|
3271
|
+
if (!file || !conventionFileExists(file)) {
|
|
3258
3272
|
return renderTreeOrFallback(
|
|
3259
3273
|
boundaryOptions,
|
|
3260
3274
|
fallbackTree,
|
|
@@ -3322,7 +3336,7 @@ async function renderGlobalErrorPage(
|
|
|
3322
3336
|
// global-error.js is a client component ('use client'): import it through
|
|
3323
3337
|
// the client module loader and SSR it to a full document. Server components
|
|
3324
3338
|
// (no directive) load through the server loader.
|
|
3325
|
-
const clientDirective =
|
|
3339
|
+
const clientDirective = await conventionUsesClient(file)
|
|
3326
3340
|
const module = (
|
|
3327
3341
|
clientDirective ? await importClientModule(file, options) : await importModule(file, options)
|
|
3328
3342
|
) as ErrorModule
|
|
@@ -3389,7 +3403,7 @@ export function withDevReloadScript(html: string, request?: Request): string {
|
|
|
3389
3403
|
}
|
|
3390
3404
|
|
|
3391
3405
|
function withGlobalErrorStylesheet(html: string, config: ResolvedConfig): string {
|
|
3392
|
-
const asset = `${config.outPath}/
|
|
3406
|
+
const asset = `${config.outPath}/static/assets/${emittedAssetName(config, 'global-error.css')}`
|
|
3393
3407
|
if (!existsSync(asset)) return html
|
|
3394
3408
|
const link = `<link rel="stylesheet" href="${assetHref(config, 'global-error.css')}">`
|
|
3395
3409
|
if (html.includes('</head>')) return html.replace('</head>', `${link}</head>`)
|
|
@@ -3956,7 +3970,7 @@ async function renderTreeInFrame(
|
|
|
3956
3970
|
// global-not-found replaces the document without the root layout, so the
|
|
3957
3971
|
// root layout's global sheet must not load (its CSS ships in the route's
|
|
3958
3972
|
// own chunk, built with includeGlobalCss).
|
|
3959
|
-
options.route.id === 'global-not-found' ? undefined : globalCssHref(options.config)
|
|
3973
|
+
options.route.id === 'global-not-found' ? undefined : await globalCssHref(options.config)
|
|
3960
3974
|
let routeStylesheet = routeCssHref(options.route, options.config)
|
|
3961
3975
|
// File names, not logical ones: the inline path READS these off disk, so it has
|
|
3962
3976
|
// to spell them the way the build emitted them (content-hashed in production).
|
|
@@ -4378,7 +4392,7 @@ async function buildLoadingBoundaries(
|
|
|
4378
4392
|
options.route.file,
|
|
4379
4393
|
'loading.tsx',
|
|
4380
4394
|
)) {
|
|
4381
|
-
if (!
|
|
4395
|
+
if (!conventionFileExists(loadingFile)) continue
|
|
4382
4396
|
const fallback = await buildLoadingFallback(options, loadingFile)
|
|
4383
4397
|
if (fallback) fallbackByDir.set(dirname(loadingFile), fallback)
|
|
4384
4398
|
}
|
|
@@ -4485,7 +4499,7 @@ async function renderNotFoundPage(
|
|
|
4485
4499
|
// A `'use client'` not-found.js with a discovered client reference renders as an island (same as
|
|
4486
4500
|
// error.js) so it HYDRATES - its hooks must work on the 404 document. Server-rendering it would
|
|
4487
4501
|
// serialize child event-handler props as dead action stubs.
|
|
4488
|
-
const clientDirective =
|
|
4502
|
+
const clientDirective = await conventionUsesClient(file)
|
|
4489
4503
|
const clientReference = clientDirective
|
|
4490
4504
|
? conventionDefaultReference(notFoundOptions, file)
|
|
4491
4505
|
: undefined
|
|
@@ -4598,7 +4612,7 @@ async function renderErrorPage(options: RenderOptions, error: unknown, stream: b
|
|
|
4598
4612
|
if (!file) return renderGenericErrorPage(options, resolvedError, stream)
|
|
4599
4613
|
|
|
4600
4614
|
try {
|
|
4601
|
-
const clientDirective =
|
|
4615
|
+
const clientDirective = await conventionUsesClient(file)
|
|
4602
4616
|
const module = (
|
|
4603
4617
|
clientDirective ? await importClientModule(file, options) : await importModule(file, options)
|
|
4604
4618
|
) as ErrorModule
|
|
@@ -4867,10 +4881,16 @@ function generatedFallbackPage(
|
|
|
4867
4881
|
}
|
|
4868
4882
|
}
|
|
4869
4883
|
|
|
4884
|
+
/** Whether a convention file is `'use client'`: the frozen fact in production, its source otherwise. */
|
|
4885
|
+
async function conventionUsesClient(file: string) {
|
|
4886
|
+
const served = servedConventions()
|
|
4887
|
+
return served ? served.client.has(file) : hasUseClientDirective(await readText(file))
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4870
4890
|
function nearestConventionFile(options: RenderOptions, name: string) {
|
|
4871
4891
|
return [...findConventionFiles(options.config.appPath, options.route.file, name)]
|
|
4872
4892
|
.reverse()
|
|
4873
|
-
.find(
|
|
4893
|
+
.find(conventionFileExists)
|
|
4874
4894
|
}
|
|
4875
4895
|
|
|
4876
4896
|
/**
|
|
@@ -6541,7 +6561,7 @@ function dynamicTargetReference(
|
|
|
6541
6561
|
const target = dynamicReference.target
|
|
6542
6562
|
if (!target) return undefined
|
|
6543
6563
|
const stored = state.clientReferences.get(
|
|
6544
|
-
`c-${clientReferenceId(target.file, target.exportName)}`,
|
|
6564
|
+
target.id ?? `c-${clientReferenceId(target.file, target.exportName)}`,
|
|
6545
6565
|
)
|
|
6546
6566
|
if (stored) return stored
|
|
6547
6567
|
for (const reference of state.clientReferences.values()) {
|
|
@@ -7616,7 +7636,7 @@ async function applyLayouts(
|
|
|
7616
7636
|
await profileRenderStep(profile, 'import layouts', async () => {
|
|
7617
7637
|
for (const layoutPath of options.layoutFiles ??
|
|
7618
7638
|
findLayouts(options.config.appPath, options.route.file)) {
|
|
7619
|
-
if (!options.moduleLoader && !
|
|
7639
|
+
if (!options.moduleLoader && !conventionFileExists(layoutPath)) continue
|
|
7620
7640
|
const layoutModule = (await importModule(layoutPath, options)) as LayoutModule
|
|
7621
7641
|
markServerReference(layoutModule.default)
|
|
7622
7642
|
// Cheap leaf span for the segment-module resolution (nested under the
|
|
@@ -8025,7 +8045,7 @@ function fullSegmentPrefetchSkipsSharedLayout(options: RenderOptions): boolean {
|
|
|
8025
8045
|
options.config.appPath,
|
|
8026
8046
|
options.route.file,
|
|
8027
8047
|
'layout.tsx',
|
|
8028
|
-
).filter(
|
|
8048
|
+
).filter(conventionFileExists)
|
|
8029
8049
|
const documentDir = layoutFiles[0] ? dirname(layoutFiles[0]) : undefined
|
|
8030
8050
|
return layoutFiles
|
|
8031
8051
|
.slice(1)
|
package/src/request/context.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
PostponeError,
|
|
9
9
|
} from '../render/ppr'
|
|
10
10
|
import type { NextRequest, RouteParamValue } from '../types'
|
|
11
|
+
import type { Release } from '../runtime/production'
|
|
11
12
|
|
|
12
13
|
// Request work-unit store (CORE seam for compat after()/onRequestError).
|
|
13
14
|
//
|
|
@@ -46,6 +47,8 @@ export interface WorkUnit {
|
|
|
46
47
|
* grows no dependency on compat.
|
|
47
48
|
*/
|
|
48
49
|
compat?: Record<symbol, unknown>
|
|
50
|
+
/** The production release this request serves from; dev and build leave it unset. */
|
|
51
|
+
release?: Release
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
// Anchored on globalThis (like requestStorage below) so compiled compat
|
|
@@ -67,6 +70,12 @@ export function getWorkUnit(): WorkUnit | undefined {
|
|
|
67
70
|
return workUnitStorage.getStore()
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
/** Mark the current work unit as serving `release` (production reads its app facts from it). */
|
|
74
|
+
export function setWorkUnitRelease(release: Release): void {
|
|
75
|
+
const unit = workUnitStorage.getStore()
|
|
76
|
+
if (unit) unit.release = release
|
|
77
|
+
}
|
|
78
|
+
|
|
70
79
|
/** Set the current work-unit phase (compat toggles render/action/handler/...). */
|
|
71
80
|
export function setPhase(phase: WorkUnitPhase): void {
|
|
72
81
|
const unit = workUnitStorage.getStore()
|
package/src/resolve/dynamic.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { clientReferenceId } from '../client/reference'
|
|
1
2
|
import { dynamicCallFacts, rewriteFacts, type DynamicCallFact } from './scan-facts'
|
|
2
3
|
|
|
3
4
|
export interface DynamicCall {
|
|
@@ -132,7 +133,8 @@ export function rewriteDynamicCallTargets(
|
|
|
132
133
|
const args = source.slice(call.open + 1, call.close)
|
|
133
134
|
const argCount = topLevelArgCount(args)
|
|
134
135
|
if (argCount < 1 || argCount > 2) continue
|
|
135
|
-
const
|
|
136
|
+
const id = `c-${clientReferenceId(file, target.exportName)}`
|
|
137
|
+
const literal = JSON.stringify({ file, exportName: target.exportName, id })
|
|
136
138
|
const separator = /,\s*$/.test(args) ? '' : ', '
|
|
137
139
|
edits.push({
|
|
138
140
|
at: call.close,
|
|
@@ -222,6 +224,7 @@ export function deferredDynamicImportSpecifiers(source: string, file?: string) {
|
|
|
222
224
|
}
|
|
223
225
|
|
|
224
226
|
const facts = dynamicCallFacts(source, file)
|
|
227
|
+
const rendered = new Set<string>()
|
|
225
228
|
for (const call of dynamicCallsFromSource(source, dynamicNames)) {
|
|
226
229
|
const target = loaderImportTargetForCall(call, facts)
|
|
227
230
|
if (!target) continue
|
|
@@ -237,7 +240,10 @@ export function deferredDynamicImportSpecifiers(source: string, file?: string) {
|
|
|
237
240
|
const visible =
|
|
238
241
|
/\bload\s*:\s*['"]visible['"]/.test(options) && !/\bssr\s*:\s*true\b/.test(options)
|
|
239
242
|
if (ssrFalse || visible) deferred.add(target.specifier)
|
|
243
|
+
else rendered.add(target.specifier)
|
|
240
244
|
}
|
|
245
|
+
// A target another call server-renders must compile for the server.
|
|
246
|
+
for (const specifier of rendered) deferred.delete(specifier)
|
|
241
247
|
return deferred
|
|
242
248
|
}
|
|
243
249
|
|
package/src/resolve/engine.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync } from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import type { ResolverFactory, NapiResolveOptions } from 'oxc-resolver'
|
|
4
4
|
import { loadNative } from '../utils/native-require'
|
|
5
|
+
import { splitResourceQuery } from '../utils/resource-query'
|
|
5
6
|
|
|
6
7
|
// Lazy: the native binding costs ~1.3 MB RSS and a prod server may never resolve.
|
|
7
8
|
function createResolverFactory(options: NapiResolveOptions): ResolverFactory {
|
|
@@ -95,18 +96,7 @@ export function tsConfigFileFor(root: string): string | undefined {
|
|
|
95
96
|
return file
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
* Split a webpack resource specifier into its file request and its `?query#fragment` suffix - loader
|
|
100
|
-
* plumbing (turbopack rules, `.wasm?module`) that takes no part in the on-disk lookup. A leading `#` is a
|
|
101
|
-
* package-imports specifier, not a fragment.
|
|
102
|
-
*/
|
|
103
|
-
export function splitResourceQuery(specifier: string): { path: string; query: string } {
|
|
104
|
-
const offset = specifier.startsWith('#') ? 1 : 0
|
|
105
|
-
const match = /[?#]/.exec(specifier.slice(offset))
|
|
106
|
-
if (!match) return { path: specifier, query: '' }
|
|
107
|
-
const index = offset + match.index
|
|
108
|
-
return { path: specifier.slice(0, index), query: specifier.slice(index) }
|
|
109
|
-
}
|
|
99
|
+
export { splitResourceQuery }
|
|
110
100
|
|
|
111
101
|
/**
|
|
112
102
|
* Resolve `specifier` from `dir`. `tsConfigRoot` opts the lookup into that
|