vinext 1.0.0-beta.2 → 1.0.0-beta.4
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/README.md +6 -9
- package/dist/build/client-build-config.js +7 -1
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +12 -2
- package/dist/check.js +4 -0
- package/dist/cli-args.d.ts +2 -1
- package/dist/cli-args.js +10 -0
- package/dist/cli.js +14 -8
- package/dist/client/navigation-runtime.d.ts +6 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/dotenv.d.ts +3 -4
- package/dist/config/dotenv.js +30 -22
- package/dist/config/next-config.d.ts +16 -5
- package/dist/config/next-config.js +7 -0
- package/dist/entries/app-browser-entry.d.ts +4 -10
- package/dist/entries/app-browser-entry.js +20 -4
- package/dist/entries/app-rsc-entry.js +21 -3
- package/dist/entries/app-rsc-manifest.js +19 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +13 -3
- package/dist/index.js +122 -49
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/plugins/client-reference-dedup.js +7 -5
- package/dist/plugins/extensionless-dynamic-import.js +23 -18
- package/dist/plugins/ignore-dynamic-requests.js +3 -1
- package/dist/plugins/import-meta-url.js +17 -6
- package/dist/plugins/require-context.js +20 -15
- package/dist/plugins/sass.js +3 -4
- package/dist/plugins/transform-cache.d.ts +19 -0
- package/dist/plugins/transform-cache.js +36 -0
- package/dist/routing/app-route-graph.d.ts +14 -6
- package/dist/routing/app-route-graph.js +106 -16
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +7 -6
- package/dist/server/app-bfcache-identity.js +28 -2
- package/dist/server/app-browser-entry.js +175 -75
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +30 -5
- package/dist/server/app-browser-prefetch-response.d.ts +9 -0
- package/dist/server/app-browser-prefetch-response.js +32 -0
- package/dist/server/app-browser-state.d.ts +8 -3
- package/dist/server/app-browser-state.js +9 -3
- package/dist/server/app-page-cache-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +37 -8
- package/dist/server/app-page-element-builder.d.ts +4 -1
- package/dist/server/app-page-element-builder.js +34 -7
- package/dist/server/app-page-head.d.ts +3 -3
- package/dist/server/app-page-head.js +58 -13
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
- package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
- package/dist/server/app-page-probe.d.ts +4 -0
- package/dist/server/app-page-probe.js +6 -2
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +13 -3
- package/dist/server/app-page-request.d.ts +3 -1
- package/dist/server/app-page-request.js +4 -13
- package/dist/server/app-page-response.d.ts +2 -0
- package/dist/server/app-page-response.js +7 -2
- package/dist/server/app-page-route-wiring.d.ts +10 -2
- package/dist/server/app-page-route-wiring.js +269 -59
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +3 -1
- package/dist/server/app-route-handler-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +9 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +6 -0
- package/dist/server/app-route-module-loader.js +3 -0
- package/dist/server/app-router-entry.js +6 -3
- package/dist/server/app-rsc-cache-busting.d.ts +7 -0
- package/dist/server/app-rsc-cache-busting.js +6 -0
- package/dist/server/app-rsc-errors.js +10 -0
- package/dist/server/app-rsc-handler.d.ts +2 -0
- package/dist/server/app-rsc-handler.js +30 -13
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.js +65 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -0
- package/dist/server/app-rsc-route-matching.js +6 -0
- package/dist/server/app-server-action-execution.d.ts +1 -1
- package/dist/server/app-ssr-entry.js +4 -4
- package/dist/server/app-visited-response-cache.d.ts +6 -1
- package/dist/server/app-visited-response-cache.js +49 -1
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- package/dist/server/dev-server.d.ts +3 -1
- package/dist/server/dev-server.js +204 -348
- package/dist/server/edge-api-runtime.d.ts +10 -1
- package/dist/server/edge-api-runtime.js +29 -1
- package/dist/server/headers.d.ts +4 -2
- package/dist/server/headers.js +6 -3
- package/dist/server/isr-cache.d.ts +10 -33
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- package/dist/server/pages-api-route.d.ts +4 -0
- package/dist/server/pages-api-route.js +6 -3
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +6 -4
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-document-asset-props.d.ts +26 -0
- package/dist/server/pages-document-asset-props.js +69 -0
- package/dist/server/pages-get-initial-props.d.ts +1 -1
- package/dist/server/pages-get-initial-props.js +1 -4
- package/dist/server/pages-i18n.js +64 -16
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +10 -6
- package/dist/server/pages-page-data.d.ts +61 -9
- package/dist/server/pages-page-data.js +334 -74
- package/dist/server/pages-page-handler.d.ts +6 -1
- package/dist/server/pages-page-handler.js +119 -20
- package/dist/server/pages-page-response.d.ts +7 -3
- package/dist/server/pages-page-response.js +41 -33
- package/dist/server/pages-request-pipeline.d.ts +7 -0
- package/dist/server/pages-request-pipeline.js +5 -1
- package/dist/server/pages-revalidate.d.ts +1 -1
- package/dist/server/pages-revalidate.js +54 -8
- package/dist/server/pages-router-entry.d.ts +1 -0
- package/dist/server/pages-router-entry.js +10 -4
- package/dist/server/prerender-manifest.d.ts +1 -0
- package/dist/server/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +38 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +30 -0
- package/dist/shims/app-router-scroll-state.d.ts +2 -1
- package/dist/shims/app-router-scroll-state.js +7 -2
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- package/dist/shims/cache-runtime.d.ts +6 -0
- package/dist/shims/cache-runtime.js +4 -1
- package/dist/shims/cache.js +1 -1
- package/dist/shims/document.js +15 -2
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +1 -1
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/hash-scroll.d.ts +1 -1
- package/dist/shims/hash-scroll.js +2 -1
- package/dist/shims/headers.d.ts +10 -13
- package/dist/shims/headers.js +85 -36
- package/dist/shims/internal/cookie-serialize.d.ts +10 -9
- package/dist/shims/internal/cookie-serialize.js +9 -8
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- package/dist/shims/link.d.ts +2 -0
- package/dist/shims/link.js +77 -24
- package/dist/shims/metadata.d.ts +18 -34
- package/dist/shims/metadata.js +98 -56
- package/dist/shims/navigation.d.ts +18 -2
- package/dist/shims/navigation.js +70 -21
- package/dist/shims/request-context.d.ts +6 -2
- package/dist/shims/router.js +18 -7
- package/dist/shims/script.js +1 -1
- package/dist/shims/server.d.ts +7 -6
- package/dist/shims/server.js +156 -57
- package/dist/shims/slot.d.ts +2 -1
- package/dist/shims/slot.js +6 -2
- package/dist/shims/streamed-icons.d.ts +9 -0
- package/dist/shims/streamed-icons.js +33 -0
- package/dist/shims/unified-request-context.d.ts +21 -2
- package/dist/shims/unified-request-context.js +82 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- package/dist/utils/html-limited-bots.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/package.json +1 -1
|
@@ -133,11 +133,10 @@ declare function resolvePendingNavigationCommitDispositionDecision(options: {
|
|
|
133
133
|
startedNavigationId: number;
|
|
134
134
|
targetHref?: string;
|
|
135
135
|
}): PendingNavigationCommitDispositionDecision;
|
|
136
|
-
|
|
136
|
+
type CreatePendingNavigationCommitOptions = {
|
|
137
137
|
currentState: AppRouterState;
|
|
138
138
|
navigationCommitKind?: "authoritative" | "detached";
|
|
139
139
|
navigationId?: number;
|
|
140
|
-
nextElements: Promise<AppElements>;
|
|
141
140
|
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
142
141
|
operationLane: OperationLane;
|
|
143
142
|
payloadOrigin: AppNavigationPayloadOrigin;
|
|
@@ -146,6 +145,12 @@ declare function createPendingNavigationCommit(options: {
|
|
|
146
145
|
restoredBfcacheIds?: BfcacheIdMap | null;
|
|
147
146
|
reuseCurrentBfcacheIds?: boolean;
|
|
148
147
|
type: "navigate" | "replace" | "traverse";
|
|
148
|
+
};
|
|
149
|
+
declare function createPendingNavigationCommitFromElements(options: CreatePendingNavigationCommitOptions & {
|
|
150
|
+
nextElements: AppElements;
|
|
151
|
+
}): PendingNavigationCommit;
|
|
152
|
+
declare function createPendingNavigationCommit(options: CreatePendingNavigationCommitOptions & {
|
|
153
|
+
nextElements: Promise<AppElements>;
|
|
149
154
|
}): Promise<PendingNavigationCommit>;
|
|
150
155
|
//#endregion
|
|
151
|
-
export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState,
|
|
156
|
+
export { AppNavigationPayloadOrigin, AppRouterAction, AppRouterState, COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, CommittedOperationRecord, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, type HistoryTraversalIntent, type OperationLane, PendingNavigationCommit, PendingOperationRecord, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, createPendingNavigationCommitFromElements, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
|
|
@@ -279,8 +279,8 @@ function mergeSkippedLayoutSlotPreservation(options) {
|
|
|
279
279
|
}
|
|
280
280
|
return preservePreviousSlotIds;
|
|
281
281
|
}
|
|
282
|
-
|
|
283
|
-
const elements =
|
|
282
|
+
function createPendingNavigationCommitFromElements(options) {
|
|
283
|
+
const elements = options.nextElements;
|
|
284
284
|
const metadata = AppElementsWire.readMetadata(elements);
|
|
285
285
|
const cacheEntryReuseProof = metadata.cacheEntryReuseProof ?? (requiresCacheEntryReuseProof(options.payloadOrigin) ? createCacheEntryReuseProof(null) : void 0);
|
|
286
286
|
const requestedPreviousNextUrl = options.previousNextUrl !== void 0 ? options.previousNextUrl : options.currentState.previousNextUrl;
|
|
@@ -328,5 +328,11 @@ async function createPendingNavigationCommit(options) {
|
|
|
328
328
|
skippedLayoutIds: metadata.skippedLayoutIds
|
|
329
329
|
};
|
|
330
330
|
}
|
|
331
|
+
async function createPendingNavigationCommit(options) {
|
|
332
|
+
return createPendingNavigationCommitFromElements({
|
|
333
|
+
...options,
|
|
334
|
+
nextElements: await options.nextElements
|
|
335
|
+
});
|
|
336
|
+
}
|
|
331
337
|
//#endregion
|
|
332
|
-
export { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
|
|
338
|
+
export { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, createInitialBfcacheIdMap, createNextBfcacheIdMap, createPendingNavigationCommit, createPendingNavigationCommitFromElements, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, isHistoryStateBfcacheVersionCurrent, preserveBfcacheIdsForMergedElements, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NEXTJS_CACHE_HEADER, VINEXT_CACHE_HEADER } from "./headers.js";
|
|
2
|
-
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
3
2
|
import { applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
3
|
import { buildAppPageCacheValue } from "./isr-cache.js";
|
|
4
|
+
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
5
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
6
6
|
import { createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
7
7
|
//#region src/server/app-page-cache-finalizer.ts
|
|
@@ -18,7 +18,7 @@ type AppPageCacheOutcomeMetric = Readonly<{
|
|
|
18
18
|
*/
|
|
19
19
|
cacheKey: string;
|
|
20
20
|
outcome: "hit" | "miss" | "stale";
|
|
21
|
-
reason: "empty-entry" | "no-entry" | "non-app-page-entry" | "query-variant-unproven" | "read-error" | "served" | "stale-empty-entry";
|
|
21
|
+
reason: "empty-entry" | "expired" | "no-entry" | "non-app-page-entry" | "query-variant-unproven" | "read-error" | "served" | "stale-empty-entry";
|
|
22
22
|
}>;
|
|
23
23
|
type AppPageCacheOutcomeRecorder = (metric: AppPageCacheOutcomeMetric) => void;
|
|
24
24
|
type AppPageCacheRenderResult = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { VINEXT_MOUNTED_SLOTS_HEADER } from "./headers.js";
|
|
2
|
-
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
3
2
|
import { applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
3
|
import { decideIsr } from "./isr-decision.js";
|
|
5
4
|
import { buildAppPageCacheValue } from "./isr-cache.js";
|
|
6
5
|
import { encodeCacheTag } from "../utils/encode-cache-tag.js";
|
|
6
|
+
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
7
7
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
8
8
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
9
9
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
@@ -58,7 +58,7 @@ function hasQueryInvariantAppPageProof(cachedValue) {
|
|
|
58
58
|
function resolveRegeneratedAppPageCachePolicy(options) {
|
|
59
59
|
let revalidateSeconds = options.routeRevalidateSeconds;
|
|
60
60
|
const renderRevalidateSeconds = options.renderCacheControl?.revalidate;
|
|
61
|
-
if (renderRevalidateSeconds
|
|
61
|
+
if (typeof renderRevalidateSeconds === "number") revalidateSeconds = revalidateSeconds > 0 ? Math.min(revalidateSeconds, renderRevalidateSeconds) : renderRevalidateSeconds;
|
|
62
62
|
return {
|
|
63
63
|
expireSeconds: options.renderCacheControl?.expire ?? options.expireSeconds,
|
|
64
64
|
revalidateSeconds
|
|
@@ -105,6 +105,10 @@ function buildAppPageCachedResponse(cachedValue, options) {
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
async function serveAppPageCachedHtml(options, transformValue) {
|
|
108
|
+
if (options.cached?.isExpired) {
|
|
109
|
+
options.isrDebug?.("MISS (expired)", options.pathname);
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
108
112
|
if (typeof options.cachedValue.html !== "string" || options.cachedValue.html.length === 0) {
|
|
109
113
|
if (options.cached?.isStale) options.scheduleRegeneration();
|
|
110
114
|
options.isrDebug?.(options.emptyDebugMessage, options.pathname);
|
|
@@ -137,6 +141,16 @@ async function readAppPageCacheResponse(options) {
|
|
|
137
141
|
try {
|
|
138
142
|
const cached = await options.isrGet(isrKey);
|
|
139
143
|
const cachedValue = getCachedAppPageValue(cached);
|
|
144
|
+
if (cached?.isExpired) {
|
|
145
|
+
recordAppPageCacheOutcome(options.recordCacheOutcome, {
|
|
146
|
+
artifact,
|
|
147
|
+
cacheKey: isrKey,
|
|
148
|
+
outcome: "miss",
|
|
149
|
+
reason: "expired"
|
|
150
|
+
});
|
|
151
|
+
options.isrDebug?.("MISS (expired)", options.cleanPathname);
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
140
154
|
if (cached && !cachedValue) {
|
|
141
155
|
recordAppPageCacheOutcome(options.recordCacheOutcome, {
|
|
142
156
|
artifact,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ClassificationReason } from "../build/layout-classification-types.js";
|
|
2
2
|
import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
|
|
3
3
|
import { AppOutgoingElements } from "./app-elements-wire.js";
|
|
4
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
4
5
|
import { NavigationContext } from "../shims/navigation-context-state.js";
|
|
5
6
|
import { AppPageFontPreload, LayoutClassificationOptions } from "./app-page-execution.js";
|
|
6
7
|
import { AppPageMiddlewareContext } from "./app-page-response.js";
|
|
7
8
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
8
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
9
9
|
import { RootParams } from "../shims/root-params.js";
|
|
10
10
|
import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
11
11
|
import { CachedAppPageValue } from "../shims/cache-handler.js";
|
|
@@ -36,6 +36,8 @@ type AppPageDispatchIntercept<TPage = unknown> = {
|
|
|
36
36
|
interceptLayouts?: readonly unknown[] | null;
|
|
37
37
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
38
38
|
interceptBranchSegments?: readonly string[] | null;
|
|
39
|
+
interceptLoadings?: readonly unknown[] | null;
|
|
40
|
+
interceptLoadingTreePositions?: readonly number[] | null;
|
|
39
41
|
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
40
42
|
notFound?: unknown;
|
|
41
43
|
notFoundTreePosition?: number | null;
|
|
@@ -52,6 +54,8 @@ type AppPageDispatchInterceptOptions<TPage = unknown> = {
|
|
|
52
54
|
interceptLayouts?: readonly unknown[] | null;
|
|
53
55
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
54
56
|
interceptBranchSegments?: readonly string[] | null;
|
|
57
|
+
interceptLoadings?: readonly unknown[] | null;
|
|
58
|
+
interceptLoadingTreePositions?: readonly number[] | null;
|
|
55
59
|
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
56
60
|
interceptNotFound?: unknown;
|
|
57
61
|
interceptNotFoundTreePosition?: number | null;
|
|
@@ -69,6 +73,8 @@ type AppPageModule = {
|
|
|
69
73
|
};
|
|
70
74
|
type AppPageDispatchSlot = {
|
|
71
75
|
default?: AppPageModule | null;
|
|
76
|
+
loading?: AppPageModule | null;
|
|
77
|
+
loadings?: readonly (AppPageModule | null | undefined)[] | null;
|
|
72
78
|
page?: AppPageModule | null;
|
|
73
79
|
slotPatternParts?: readonly string[] | null;
|
|
74
80
|
slotParamNames?: readonly string[] | null;
|
|
@@ -85,6 +91,8 @@ type AppPageDispatchRoute = {
|
|
|
85
91
|
layouts: readonly AppPageModule[];
|
|
86
92
|
layoutTreePositions?: readonly number[];
|
|
87
93
|
loading?: AppPageModule | null;
|
|
94
|
+
loadings?: readonly (AppPageModule | null | undefined)[];
|
|
95
|
+
loadingTreePositions?: readonly number[];
|
|
88
96
|
notFound?: AppPageModule | null;
|
|
89
97
|
notFounds?: readonly (AppPageModule | null | undefined)[];
|
|
90
98
|
params: readonly string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
1
|
+
import { closeAfterResponse, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
3
3
|
import "../utils/protocol-headers.js";
|
|
4
4
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
@@ -23,6 +23,22 @@ import { resolveAppPageMethodResponse } from "./app-page-method.js";
|
|
|
23
23
|
import { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
|
|
24
24
|
import { renderAppPageLifecycle } from "./app-page-render.js";
|
|
25
25
|
//#region src/server/app-page-dispatch.ts
|
|
26
|
+
function getActiveLoadingTreePositions(route) {
|
|
27
|
+
const positions = [];
|
|
28
|
+
for (const [index, loadingModule] of (route.loadings ?? []).entries()) {
|
|
29
|
+
if (!loadingModule?.default) continue;
|
|
30
|
+
const treePosition = route.loadingTreePositions?.[index];
|
|
31
|
+
if (treePosition !== void 0) positions.push(treePosition);
|
|
32
|
+
}
|
|
33
|
+
if (positions.length === 0 && route.loading?.default) positions.push(route.routeSegments.length);
|
|
34
|
+
return positions;
|
|
35
|
+
}
|
|
36
|
+
function getAppPageLayoutProbeCount(route, loadingTreePositions) {
|
|
37
|
+
const firstLoadingTreePosition = loadingTreePositions.reduce((first, position) => first === null || position < first ? position : first, null);
|
|
38
|
+
if (firstLoadingTreePosition === null) return route.layouts.length;
|
|
39
|
+
const firstSuspendedLayoutIndex = (route.layoutTreePositions ?? []).findIndex((position) => position > firstLoadingTreePosition);
|
|
40
|
+
return firstSuspendedLayoutIndex === -1 ? route.layouts.length : firstSuspendedLayoutIndex;
|
|
41
|
+
}
|
|
26
42
|
function resolveAppPageRouteBoundaryModule(route, statusCode) {
|
|
27
43
|
if (statusCode === 403) return route.forbidden ?? null;
|
|
28
44
|
if (statusCode === 401) return route.unauthorized ?? null;
|
|
@@ -110,7 +126,7 @@ function hasSearchParams(searchParams) {
|
|
|
110
126
|
}
|
|
111
127
|
async function runAppPageRevalidationContext(options, renderFn) {
|
|
112
128
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
113
|
-
|
|
129
|
+
const requestContext = createRequestContext({
|
|
114
130
|
headersContext: createStaticGenerationHeadersContext({
|
|
115
131
|
draftModeEnabled: false,
|
|
116
132
|
draftModeSecret: options.draftModeSecret,
|
|
@@ -122,7 +138,8 @@ async function runAppPageRevalidationContext(options, renderFn) {
|
|
|
122
138
|
currentForceDynamicFetchDefault: options.dynamicConfig === "force-dynamic",
|
|
123
139
|
executionContext: getRequestExecutionContext(),
|
|
124
140
|
unstableCacheRevalidation: "foreground"
|
|
125
|
-
})
|
|
141
|
+
});
|
|
142
|
+
const revalidation = runWithRequestContext(requestContext, async () => {
|
|
126
143
|
ensureFetchPatch();
|
|
127
144
|
setRefreshStaleFetchesInForeground(process.env.VINEXT_PRERENDER === "1");
|
|
128
145
|
setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], options.routeSegments));
|
|
@@ -133,6 +150,11 @@ async function runAppPageRevalidationContext(options, renderFn) {
|
|
|
133
150
|
});
|
|
134
151
|
return await runWithFetchDedupe(renderFn);
|
|
135
152
|
});
|
|
153
|
+
try {
|
|
154
|
+
return await revalidation;
|
|
155
|
+
} finally {
|
|
156
|
+
await closeAfterResponse(requestContext);
|
|
157
|
+
}
|
|
136
158
|
}
|
|
137
159
|
function toInterceptOptions(interceptionContext, intercept) {
|
|
138
160
|
return {
|
|
@@ -140,6 +162,8 @@ function toInterceptOptions(interceptionContext, intercept) {
|
|
|
140
162
|
interceptLayouts: intercept.interceptLayouts,
|
|
141
163
|
interceptLayoutSegments: intercept.interceptLayoutSegments,
|
|
142
164
|
interceptBranchSegments: intercept.interceptBranchSegments,
|
|
165
|
+
interceptLoadings: intercept.interceptLoadings,
|
|
166
|
+
interceptLoadingTreePositions: intercept.interceptLoadingTreePositions,
|
|
143
167
|
interceptNotFoundBranchSegments: intercept.interceptNotFoundBranchSegments,
|
|
144
168
|
interceptNotFound: intercept.notFound,
|
|
145
169
|
interceptNotFoundTreePosition: intercept.notFoundTreePosition,
|
|
@@ -173,7 +197,8 @@ async function dispatchAppPageInner(options) {
|
|
|
173
197
|
const hasRequestSearchParams = !shouldUseEmptySearchParams && hasSearchParams(options.searchParams);
|
|
174
198
|
const pageSearchParams = shouldUseEmptySearchParams ? new URLSearchParams() : options.searchParams;
|
|
175
199
|
const layoutParamAccess = createAppLayoutParamAccessTracker();
|
|
176
|
-
const
|
|
200
|
+
const activeLoadingTreePositions = getActiveLoadingTreePositions(route);
|
|
201
|
+
const hasActiveLoadingBoundary = activeLoadingTreePositions.length > 0;
|
|
177
202
|
setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
|
|
178
203
|
setCurrentFetchCacheMode(options.fetchCache ?? null);
|
|
179
204
|
setCurrentForceDynamicFetchDefault(isForceDynamic);
|
|
@@ -323,13 +348,17 @@ async function dispatchAppPageInner(options) {
|
|
|
323
348
|
}
|
|
324
349
|
if (options.skipStaticParamsValidation !== true && !(options.isProduction && isForceDynamic)) {
|
|
325
350
|
const dynamicParamsResponse = await validateAppPageDynamicParams({
|
|
326
|
-
clearRequestContext: options.clearRequestContext,
|
|
327
351
|
enforceStaticParamsOnly: options.dynamicParamsConfig === false,
|
|
328
352
|
generateStaticParams: options.generateStaticParams,
|
|
329
353
|
isDynamicRoute: route.isDynamic,
|
|
330
354
|
params: options.staticParamsValidationParams ?? options.params
|
|
331
355
|
});
|
|
332
|
-
if (dynamicParamsResponse)
|
|
356
|
+
if (dynamicParamsResponse) {
|
|
357
|
+
const renderedNotFound = await options.renderHttpAccessFallbackPage(404, { matchedParams: options.params }, options.middlewareContext);
|
|
358
|
+
if (renderedNotFound) return renderedNotFound;
|
|
359
|
+
options.clearRequestContext();
|
|
360
|
+
return dynamicParamsResponse;
|
|
361
|
+
}
|
|
333
362
|
}
|
|
334
363
|
const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
|
|
335
364
|
if (fallbackShellResponse) return fallbackShellResponse;
|
|
@@ -410,7 +439,7 @@ async function dispatchAppPageInner(options) {
|
|
|
410
439
|
});
|
|
411
440
|
},
|
|
412
441
|
async probePageSpecialError() {
|
|
413
|
-
if (
|
|
442
|
+
if (hasActiveLoadingBoundary) return null;
|
|
414
443
|
return resolveAppPageSpecialError(await probeAppPageThrownError({
|
|
415
444
|
probePage: () => options.probePage(pageSearchParams),
|
|
416
445
|
runWithSuppressedHookWarning(probe) {
|
|
@@ -500,7 +529,7 @@ async function dispatchAppPageInner(options) {
|
|
|
500
529
|
isrSet: options.isrSet,
|
|
501
530
|
interceptionContext: options.interceptionContext,
|
|
502
531
|
expireSeconds: options.expireSeconds,
|
|
503
|
-
layoutCount: route
|
|
532
|
+
layoutCount: getAppPageLayoutProbeCount(route, activeLoadingTreePositions),
|
|
504
533
|
loadSsrHandler: options.loadSsrHandler,
|
|
505
534
|
middlewareContext: options.middlewareContext,
|
|
506
535
|
navigationParams,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
2
|
import { AppElements } from "./app-elements-wire.js";
|
|
3
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
3
4
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
4
5
|
import { ApplyAppPageFileBasedMetadata } from "./app-page-head.js";
|
|
5
6
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
6
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
7
7
|
import { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute } from "./app-page-route-wiring.js";
|
|
8
8
|
|
|
9
9
|
//#region src/server/app-page-element-builder.d.ts
|
|
@@ -22,6 +22,8 @@ type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {
|
|
|
22
22
|
interceptLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
23
23
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
24
24
|
interceptBranchSegments?: readonly string[] | null;
|
|
25
|
+
interceptLoadings?: readonly (TModule | null | undefined)[] | null;
|
|
26
|
+
interceptLoadingTreePositions?: readonly number[] | null;
|
|
25
27
|
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
26
28
|
interceptNotFound?: TModule | null;
|
|
27
29
|
interceptNotFoundTreePosition?: number | null;
|
|
@@ -64,6 +66,7 @@ type BuildPageElementsOptions<TModule extends AppPageModule = AppPageModule, TEr
|
|
|
64
66
|
basePath?: string; /** Configured next.config `trailingSlash`, threaded into canonical URL rendering. */
|
|
65
67
|
trailingSlash?: boolean; /** Serialized next.config `htmlLimitedBots` regexp source. */
|
|
66
68
|
htmlLimitedBots?: string;
|
|
69
|
+
scriptNonce?: string;
|
|
67
70
|
};
|
|
68
71
|
type AppPageNavigationParamModule = {
|
|
69
72
|
default?: unknown;
|
|
@@ -15,7 +15,7 @@ import { resolveAppPageParentHttpAccessBoundary } from "./app-page-boundary.js";
|
|
|
15
15
|
import { sanitizeErrorForClient } from "./app-rsc-errors.js";
|
|
16
16
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
17
17
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
18
|
-
import { createElement } from "react";
|
|
18
|
+
import { Suspense, createElement } from "react";
|
|
19
19
|
//#region src/server/app-page-element-builder.ts
|
|
20
20
|
function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
|
|
21
21
|
return resolveAppPageBranchParams(branchSegments, layoutSegments.length, params, layoutSegments);
|
|
@@ -111,7 +111,7 @@ async function buildPageElements(options) {
|
|
|
111
111
|
} : {},
|
|
112
112
|
ownerTreePosition: route.routeSegments?.length ?? 0
|
|
113
113
|
} : null;
|
|
114
|
-
const parallelRoutes = [...activeParallelRouteHeadInputs.map((input) => input.head)
|
|
114
|
+
const parallelRoutes = [...primaryParallelRouteHeadInput ? [primaryParallelRouteHeadInput.head] : [], ...activeParallelRouteHeadInputs.map((input) => input.head)];
|
|
115
115
|
const metadataSearchParamsObserver = observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0;
|
|
116
116
|
const preparedHead = prepareAppPageHead({
|
|
117
117
|
applyFileBasedMetadata: options.applyFileBasedMetadata,
|
|
@@ -210,11 +210,35 @@ async function buildPageElements(options) {
|
|
|
210
210
|
const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
|
|
211
211
|
const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
|
|
212
212
|
let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null;
|
|
213
|
-
if (isSiblingIntercept && siblingInterceptElement !== null
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
if (isSiblingIntercept && siblingInterceptElement !== null) {
|
|
214
|
+
const layoutIndexesByTreePosition = /* @__PURE__ */ new Map();
|
|
215
|
+
for (const [index, layoutModule] of (opts?.interceptLayouts ?? []).entries()) {
|
|
216
|
+
if (!layoutModule?.default) continue;
|
|
217
|
+
const treePosition = opts?.interceptLayoutSegments?.[index]?.length ?? 0;
|
|
218
|
+
const indexes = layoutIndexesByTreePosition.get(treePosition) ?? [];
|
|
219
|
+
indexes.push(index);
|
|
220
|
+
layoutIndexesByTreePosition.set(treePosition, indexes);
|
|
221
|
+
}
|
|
222
|
+
const loadingIndexesByTreePosition = /* @__PURE__ */ new Map();
|
|
223
|
+
for (const [index, loadingModule] of (opts?.interceptLoadings ?? []).entries()) {
|
|
224
|
+
if (!loadingModule?.default) continue;
|
|
225
|
+
const treePosition = opts?.interceptLoadingTreePositions?.[index];
|
|
226
|
+
if (treePosition !== void 0) loadingIndexesByTreePosition.set(treePosition, index);
|
|
227
|
+
}
|
|
228
|
+
const treePositions = Array.from(/* @__PURE__ */ new Set([...layoutIndexesByTreePosition.keys(), ...loadingIndexesByTreePosition.keys()])).sort((left, right) => left - right);
|
|
229
|
+
for (let index = treePositions.length - 1; index >= 0; index--) {
|
|
230
|
+
const treePosition = treePositions[index];
|
|
231
|
+
const loadingIndex = loadingIndexesByTreePosition.get(treePosition);
|
|
232
|
+
const LoadingComponent = loadingIndex === void 0 ? null : opts?.interceptLoadings?.[loadingIndex]?.default;
|
|
233
|
+
if (LoadingComponent) siblingInterceptElement = createElement(Suspense, { fallback: createElement(LoadingComponent) }, siblingInterceptElement);
|
|
234
|
+
const layoutIndexes = layoutIndexesByTreePosition.get(treePosition) ?? [];
|
|
235
|
+
for (let layoutOffset = layoutIndexes.length - 1; layoutOffset >= 0; layoutOffset--) {
|
|
236
|
+
const layoutIndex = layoutIndexes[layoutOffset];
|
|
237
|
+
const LayoutComponent = opts?.interceptLayouts?.[layoutIndex]?.default;
|
|
238
|
+
if (!LayoutComponent) continue;
|
|
239
|
+
const interceptLayoutSegments = opts?.interceptLayoutSegments?.[layoutIndex] ?? [];
|
|
240
|
+
siblingInterceptElement = createElement(LayoutComponent, { params: makeThenableParams(resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams)) }, siblingInterceptElement);
|
|
241
|
+
}
|
|
218
242
|
}
|
|
219
243
|
}
|
|
220
244
|
return buildAppPageElements({
|
|
@@ -230,6 +254,7 @@ async function buildPageElements(options) {
|
|
|
230
254
|
resolvedMetadata,
|
|
231
255
|
resolvedMetadataPathname: routePath,
|
|
232
256
|
resolvedViewport,
|
|
257
|
+
scriptNonce: options.scriptNonce,
|
|
233
258
|
streamingMetadata,
|
|
234
259
|
streamingMetadataOutlet,
|
|
235
260
|
streamingMetadataOutletSuspended: streamGeneratedHead,
|
|
@@ -267,6 +292,8 @@ function buildSlotOverrides(route, routeParams, routePath, opts) {
|
|
|
267
292
|
branchSegments: opts.interceptBranchSegments ?? null,
|
|
268
293
|
layoutModules: opts.interceptLayouts || null,
|
|
269
294
|
layoutSegments: opts.interceptLayoutSegments ?? null,
|
|
295
|
+
loadingModules: opts.interceptLoadings || null,
|
|
296
|
+
loadingTreePositions: opts.interceptLoadingTreePositions ?? null,
|
|
270
297
|
pageModule: opts.interceptPage,
|
|
271
298
|
params: opts.interceptParams || routeParams,
|
|
272
299
|
routeSegments: resolveInterceptedSlotSegments(opts.interceptSourcePageSegments, opts.interceptSlotKey)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
2
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
3
3
|
import { ThenableParamsObserver } from "../shims/thenable-params.js";
|
|
4
|
-
import { Metadata,
|
|
4
|
+
import { Metadata, ResolvedViewport } from "../shims/metadata.js";
|
|
5
5
|
import { applyFileBasedMetadata } from "./file-based-metadata.js";
|
|
6
6
|
|
|
7
7
|
//#region src/server/app-page-head.d.ts
|
|
@@ -96,11 +96,11 @@ type ResolveAppPageHeadResult = {
|
|
|
96
96
|
hasSearchParams: boolean;
|
|
97
97
|
metadata: Metadata | null;
|
|
98
98
|
pageSearchParams: AppPageSearchParams;
|
|
99
|
-
viewport:
|
|
99
|
+
viewport: ResolvedViewport;
|
|
100
100
|
};
|
|
101
101
|
type PreparedAppPageHead = Omit<ResolveAppPageHeadResult, "metadata" | "viewport"> & {
|
|
102
102
|
metadata: Promise<Metadata | null>;
|
|
103
|
-
viewport: Promise<
|
|
103
|
+
viewport: Promise<ResolvedViewport>;
|
|
104
104
|
};
|
|
105
105
|
type AppPageSearchParamsCollection = {
|
|
106
106
|
hasSearchParams: boolean;
|
|
@@ -79,7 +79,7 @@ function resolveActiveParallelRouteHeadInputs(options) {
|
|
|
79
79
|
} : {},
|
|
80
80
|
ownerTreePosition
|
|
81
81
|
};
|
|
82
|
-
});
|
|
82
|
+
}).sort((left, right) => right.ownerTreePosition - left.ownerTreePosition);
|
|
83
83
|
}
|
|
84
84
|
function isPresent(value) {
|
|
85
85
|
return value !== null && value !== void 0;
|
|
@@ -165,11 +165,25 @@ async function resolveLayoutMetadata(layoutInputs, params, routeSegments) {
|
|
|
165
165
|
}
|
|
166
166
|
return Promise.all(layoutMetadataPromises);
|
|
167
167
|
}
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
function resolveLayoutViewport(layoutInputs, params, routeSegments) {
|
|
169
|
+
const viewportPromises = [];
|
|
170
|
+
let accumulatedViewport = Promise.resolve(mergeViewport([]));
|
|
171
|
+
for (const layoutInput of layoutInputs) {
|
|
172
|
+
const parentForLayout = accumulatedViewport;
|
|
170
173
|
const layoutParams = resolveAppPageSegmentParams(routeSegments, layoutInput.treePosition, params);
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
const viewportPromise = resolveModuleViewport(layoutInput.module, layoutParams, void 0, parentForLayout);
|
|
175
|
+
viewportPromises.push(viewportPromise);
|
|
176
|
+
viewportPromise.catch(() => null);
|
|
177
|
+
accumulatedViewport = mergeResolvedViewport(parentForLayout, viewportPromise);
|
|
178
|
+
accumulatedViewport.catch(() => null);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
resolvedViewport: accumulatedViewport,
|
|
182
|
+
viewportResults: Promise.all(viewportPromises)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function mergeResolvedViewport(parent, viewport) {
|
|
186
|
+
return Promise.all([parent, viewport]).then(([resolvedParent, resolvedViewport]) => resolvedViewport ? mergeViewport([resolvedParent, resolvedViewport]) : resolvedParent);
|
|
173
187
|
}
|
|
174
188
|
function getParallelRouteModules(parallelRoute) {
|
|
175
189
|
return [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
@@ -211,16 +225,34 @@ async function resolveParallelRouteMetadata(parallelRoute, fallbackParams, fallb
|
|
|
211
225
|
metadataSources
|
|
212
226
|
};
|
|
213
227
|
}
|
|
214
|
-
|
|
228
|
+
function resolveParallelRouteViewport(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
|
|
215
229
|
const params = parallelRoute.params ?? fallbackParams;
|
|
216
230
|
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
217
231
|
const layoutModules = getParallelRouteModules(parallelRoute);
|
|
218
232
|
const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
|
|
219
233
|
const layoutParams = parallelRoute.layoutParams ?? [];
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
const [
|
|
223
|
-
|
|
234
|
+
const viewportPromises = [];
|
|
235
|
+
let accumulatedViewport = parent;
|
|
236
|
+
for (const [index, layoutModule] of layoutModules.entries()) {
|
|
237
|
+
const parentForLayout = accumulatedViewport;
|
|
238
|
+
const viewportPromise = resolveModuleViewport(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, parentForLayout);
|
|
239
|
+
viewportPromises.push(viewportPromise);
|
|
240
|
+
viewportPromise.catch(() => null);
|
|
241
|
+
accumulatedViewport = mergeResolvedViewport(parentForLayout, viewportPromise);
|
|
242
|
+
accumulatedViewport.catch(() => null);
|
|
243
|
+
}
|
|
244
|
+
if (parallelRoute.pageModule) {
|
|
245
|
+
const parentForPage = accumulatedViewport;
|
|
246
|
+
const viewportPromise = resolveModuleViewport(parallelRoute.pageModule, params, pageSearchParams, parentForPage, searchParamsObserver);
|
|
247
|
+
viewportPromises.push(viewportPromise);
|
|
248
|
+
viewportPromise.catch(() => null);
|
|
249
|
+
accumulatedViewport = mergeResolvedViewport(parentForPage, viewportPromise);
|
|
250
|
+
accumulatedViewport.catch(() => null);
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
resolvedViewport: accumulatedViewport,
|
|
254
|
+
viewportResults: Promise.all(viewportPromises)
|
|
255
|
+
};
|
|
224
256
|
}
|
|
225
257
|
/**
|
|
226
258
|
* Resolve an explicit metadata-source sequence.
|
|
@@ -279,16 +311,29 @@ function prepareAppPageHeadInner(options) {
|
|
|
279
311
|
const primaryHasDynamicMetadata = layoutInputs.some((input) => hasGenerateMetadata(input.module)) || hasGenerateMetadata(options.pageModule);
|
|
280
312
|
const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);
|
|
281
313
|
const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);
|
|
282
|
-
const
|
|
314
|
+
const layoutViewport = resolveLayoutViewport(layoutInputs, options.params, routeSegments);
|
|
315
|
+
const layoutViewportPromise = layoutViewport.viewportResults;
|
|
283
316
|
const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) => metadataResults.filter(isPresent));
|
|
284
317
|
layoutMetadataResultsForParent.catch(() => null);
|
|
285
318
|
const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) => metadataResults.length > 0 ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata }))) : {});
|
|
286
319
|
pageParentPromise.catch(() => null);
|
|
287
320
|
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise, options.searchParamsObserver) : Promise.resolve(null);
|
|
288
|
-
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, options.searchParamsObserver) : Promise.resolve(null);
|
|
289
321
|
const parallelRoutes = options.parallelRoutes ?? [];
|
|
290
322
|
const parallelRouteMetadataPromise = Promise.all(parallelRoutes.map((parallelRoute) => resolveParallelRouteMetadata(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise, options.searchParamsObserver)));
|
|
291
|
-
const
|
|
323
|
+
const parallelRouteViewportPromises = [];
|
|
324
|
+
let accumulatedViewport = layoutViewport.resolvedViewport;
|
|
325
|
+
const pageParentViewport = accumulatedViewport;
|
|
326
|
+
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, pageParentViewport, options.searchParamsObserver) : Promise.resolve(null);
|
|
327
|
+
if (options.pageModule) {
|
|
328
|
+
accumulatedViewport = mergeResolvedViewport(pageParentViewport, pageViewportPromise);
|
|
329
|
+
accumulatedViewport.catch(() => null);
|
|
330
|
+
}
|
|
331
|
+
for (const parallelRoute of parallelRoutes) {
|
|
332
|
+
const parallelViewport = resolveParallelRouteViewport(parallelRoute, options.params, routeSegments, pageSearchParams, accumulatedViewport, options.searchParamsObserver);
|
|
333
|
+
parallelRouteViewportPromises.push(parallelViewport.viewportResults);
|
|
334
|
+
accumulatedViewport = parallelViewport.resolvedViewport;
|
|
335
|
+
}
|
|
336
|
+
const parallelRouteViewportPromise = Promise.all(parallelRouteViewportPromises);
|
|
292
337
|
const hasDynamicMetadata = primaryHasDynamicMetadata || parallelRoutes.some(parallelRouteHasDynamicMetadata);
|
|
293
338
|
const metadata = Promise.all([
|
|
294
339
|
layoutMetadataPromise,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
2
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
3
|
-
import { Metadata,
|
|
3
|
+
import { Metadata, ResolvedViewport } from "../shims/metadata.js";
|
|
4
4
|
import { ActiveParallelRouteHeadInput, AppPageHeadModule, ApplyAppPageFileBasedMetadata, OrderedAppPageMetadataSource } from "./app-page-head.js";
|
|
5
5
|
|
|
6
6
|
//#region src/server/app-page-http-access-fallback-metadata.d.ts
|
|
@@ -24,6 +24,6 @@ type ResolveHttpAccessFallbackMetadataOptions<TModule extends AppPageHeadModule
|
|
|
24
24
|
};
|
|
25
25
|
declare function createHttpAccessFallbackMetadataPlan<TModule extends AppPageHeadModule>(options: HttpAccessFallbackMetadataPlanOptions<TModule>): OrderedAppPageMetadataSource<TModule>[];
|
|
26
26
|
declare function resolveHttpAccessFallbackMetadata<TModule extends AppPageHeadModule>(options: ResolveHttpAccessFallbackMetadataOptions<TModule>): Promise<Metadata | null>;
|
|
27
|
-
declare function resolveHttpAccessFallbackViewport<TModule extends AppPageHeadModule>(options: HttpAccessFallbackMetadataPlanOptions<TModule>): Promise<
|
|
27
|
+
declare function resolveHttpAccessFallbackViewport<TModule extends AppPageHeadModule>(options: HttpAccessFallbackMetadataPlanOptions<TModule>): Promise<ResolvedViewport>;
|
|
28
28
|
//#endregion
|
|
29
29
|
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|
|
@@ -100,7 +100,15 @@ function resolveHttpAccessFallbackMetadata(options) {
|
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
102
|
async function resolveHttpAccessFallbackViewport(options) {
|
|
103
|
-
|
|
103
|
+
let accumulatedViewport = Promise.resolve(mergeViewport([]));
|
|
104
|
+
for (const source of createHttpAccessFallbackPlan(options, "snapshot")) {
|
|
105
|
+
const parentForSource = accumulatedViewport;
|
|
106
|
+
const viewportPromise = resolveModuleViewport(source.module, source.params, void 0, parentForSource);
|
|
107
|
+
viewportPromise.catch(() => null);
|
|
108
|
+
accumulatedViewport = Promise.all([parentForSource, viewportPromise]).then(([parent, viewport]) => viewport ? mergeViewport([parent, viewport]) : parent);
|
|
109
|
+
accumulatedViewport.catch(() => null);
|
|
110
|
+
}
|
|
111
|
+
return accumulatedViewport;
|
|
104
112
|
}
|
|
105
113
|
//#endregion
|
|
106
114
|
export { createHttpAccessFallbackMetadataPlan, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport };
|
|
@@ -40,12 +40,16 @@ type AppPageProbeModule = Readonly<{
|
|
|
40
40
|
}> | null | undefined;
|
|
41
41
|
type AppPageProbeSlot = Readonly<{
|
|
42
42
|
page?: AppPageProbeModule;
|
|
43
|
+
loading?: AppPageProbeModule;
|
|
44
|
+
loadings?: readonly AppPageProbeModule[] | null;
|
|
45
|
+
loadingTreePositions?: readonly number[] | null;
|
|
43
46
|
}> | null | undefined;
|
|
44
47
|
type AppPageProbeRoute = Readonly<{
|
|
45
48
|
slots?: Readonly<Record<string, AppPageProbeSlot>> | null;
|
|
46
49
|
}>;
|
|
47
50
|
type AppPageProbeIntercept = Readonly<{
|
|
48
51
|
page?: AppPageProbeModule;
|
|
52
|
+
interceptLoadings?: readonly AppPageProbeModule[] | null;
|
|
49
53
|
matchedParams?: unknown;
|
|
50
54
|
/**
|
|
51
55
|
* Key of the parallel-route slot this interception overrides. At render
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { markAppPagePropsForUseCache } from "../shims/internal/app-page-props-cache-key.js";
|
|
2
1
|
import { isNextRouterError } from "../shims/navigation-errors.js";
|
|
3
2
|
import "../shims/navigation-server.js";
|
|
3
|
+
import { markAppPagePropsForUseCache } from "../shims/internal/app-page-props-cache-key.js";
|
|
4
4
|
import { isPromiseLike } from "../utils/promise.js";
|
|
5
5
|
import { probeAppPageComponent, probeAppPageLayouts } from "./app-page-execution.js";
|
|
6
6
|
import { collectAppPageSearchParams } from "./app-page-head.js";
|
|
@@ -218,13 +218,17 @@ function buildAppPageProbes(options) {
|
|
|
218
218
|
const overriddenSlotKey = intercept?.slotKey ?? null;
|
|
219
219
|
for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {
|
|
220
220
|
if (overriddenSlotKey !== null && slotKey === overriddenSlotKey) continue;
|
|
221
|
+
if (slot?.loading?.default || slot?.loadings?.some((loading) => loading?.default)) continue;
|
|
221
222
|
probes.push(probeAppPage({
|
|
222
223
|
pageComponent: slot?.page?.default,
|
|
223
224
|
asyncRouteParams,
|
|
224
225
|
searchParams
|
|
225
226
|
}));
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
+
const interceptedSlot = intercept?.slotKey ? route.slots?.[intercept.slotKey] : null;
|
|
229
|
+
const interceptedSlotHasRootLoading = Boolean(interceptedSlot?.loading?.default || interceptedSlot?.loadings?.some((loading, index) => loading?.default && interceptedSlot.loadingTreePositions?.[index] === 0));
|
|
230
|
+
const interceptHasLoadingBoundary = Boolean(intercept?.interceptLoadings?.some((loading) => loading?.default) || interceptedSlotHasRootLoading);
|
|
231
|
+
if (intercept && !interceptHasLoadingBoundary) probes.push(probeAppPage({
|
|
228
232
|
pageComponent: intercept.page?.default,
|
|
229
233
|
asyncRouteParams: options.makeThenableParams(intercept.matchedParams ?? matchedParams),
|
|
230
234
|
searchParams
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ClientReuseManifestParseResult, ClientReuseManifestSkipDisposition } from "./client-reuse-manifest.js";
|
|
2
2
|
import { AppOutgoingElements } from "./app-elements-wire.js";
|
|
3
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
3
4
|
import { NavigationContext } from "../shims/navigation-context-state.js";
|
|
4
5
|
import { AppPageFontPreload, AppPageSpecialError, LayoutClassificationOptions } from "./app-page-execution.js";
|
|
5
6
|
import { AppPageMiddlewareContext } from "./app-page-response.js";
|
|
6
7
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
7
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
8
8
|
import { RootParams } from "../shims/root-params.js";
|
|
9
9
|
import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
10
10
|
import { CachedAppPageValue } from "../shims/cache-handler.js";
|