vinext 1.0.0-beta.2 → 1.0.0-beta.3
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/check.js +4 -0
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/next-config.d.ts +12 -3
- package/dist/config/next-config.js +4 -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 +3 -0
- 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 +10 -3
- package/dist/index.js +112 -43
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -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/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 +3 -3
- package/dist/server/app-browser-entry.js +103 -31
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +1 -1
- 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 +8 -0
- package/dist/server/app-page-dispatch.js +31 -6
- package/dist/server/app-page-element-builder.d.ts +2 -0
- package/dist/server/app-page-element-builder.js +33 -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-request.d.ts +3 -0
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +7 -0
- package/dist/server/app-page-route-wiring.js +211 -49
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -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-errors.js +10 -0
- package/dist/server/app-rsc-handler.js +21 -9
- 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-ssr-entry.js +4 -4
- 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 +145 -312
- package/dist/server/headers.d.ts +2 -2
- package/dist/server/headers.js +4 -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 +2 -0
- package/dist/server/pages-api-route.js +4 -1
- package/dist/server/pages-dev-hydration.js +0 -1
- 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 +7 -3
- 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 +5 -1
- package/dist/server/pages-page-handler.js +115 -19
- package/dist/server/pages-page-response.d.ts +5 -3
- package/dist/server/pages-page-response.js +23 -26
- 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/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +37 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +29 -0
- 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/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/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.js +18 -6
- package/dist/shims/metadata.d.ts +7 -17
- package/dist/shims/metadata.js +74 -24
- package/dist/shims/navigation.js +1 -1
- package/dist/shims/request-context.d.ts +4 -1
- 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/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
|
@@ -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,
|
|
@@ -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);
|
|
@@ -410,7 +435,7 @@ async function dispatchAppPageInner(options) {
|
|
|
410
435
|
});
|
|
411
436
|
},
|
|
412
437
|
async probePageSpecialError() {
|
|
413
|
-
if (
|
|
438
|
+
if (hasActiveLoadingBoundary) return null;
|
|
414
439
|
return resolveAppPageSpecialError(await probeAppPageThrownError({
|
|
415
440
|
probePage: () => options.probePage(pageSearchParams),
|
|
416
441
|
runWithSuppressedHookWarning(probe) {
|
|
@@ -500,7 +525,7 @@ async function dispatchAppPageInner(options) {
|
|
|
500
525
|
isrSet: options.isrSet,
|
|
501
526
|
interceptionContext: options.interceptionContext,
|
|
502
527
|
expireSeconds: options.expireSeconds,
|
|
503
|
-
layoutCount: route
|
|
528
|
+
layoutCount: getAppPageLayoutProbeCount(route, activeLoadingTreePositions),
|
|
504
529
|
loadSsrHandler: options.loadSsrHandler,
|
|
505
530
|
middlewareContext: options.middlewareContext,
|
|
506
531
|
navigationParams,
|
|
@@ -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;
|
|
@@ -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({
|
|
@@ -267,6 +291,8 @@ function buildSlotOverrides(route, routeParams, routePath, opts) {
|
|
|
267
291
|
branchSegments: opts.interceptBranchSegments ?? null,
|
|
268
292
|
layoutModules: opts.interceptLayouts || null,
|
|
269
293
|
layoutSegments: opts.interceptLayoutSegments ?? null,
|
|
294
|
+
loadingModules: opts.interceptLoadings || null,
|
|
295
|
+
loadingTreePositions: opts.interceptLoadingTreePositions ?? null,
|
|
270
296
|
pageModule: opts.interceptPage,
|
|
271
297
|
params: opts.interceptParams || routeParams,
|
|
272
298
|
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
|
|
@@ -62,8 +62,11 @@ type AppPageInterceptMatch<TPage = unknown> = {
|
|
|
62
62
|
interceptLayouts?: readonly unknown[] | null;
|
|
63
63
|
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
64
64
|
interceptBranchSegments?: readonly string[] | null;
|
|
65
|
+
interceptLoadings?: readonly unknown[] | null;
|
|
66
|
+
interceptLoadingTreePositions?: readonly number[] | null;
|
|
65
67
|
interceptNotFoundBranchSegments?: readonly string[] | null;
|
|
66
68
|
__loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
|
|
69
|
+
__loadInterceptLoadings?: readonly (() => Promise<unknown>)[] | null;
|
|
67
70
|
matchedParams: AppPageParams;
|
|
68
71
|
sourceMatchedParams?: AppPageParams;
|
|
69
72
|
page: TPage;
|
|
@@ -307,7 +307,7 @@ async function resolveAppPageInterceptState(options) {
|
|
|
307
307
|
if (loadState) loadState.notFoundLoading = loading;
|
|
308
308
|
await loading;
|
|
309
309
|
}
|
|
310
|
-
if (intercept.__loadInterceptLayouts) await loadAppInterceptLayouts(intercept);
|
|
310
|
+
if (intercept.__loadInterceptLayouts || intercept.__loadInterceptLoadings) await loadAppInterceptLayouts(intercept);
|
|
311
311
|
const sourceRoute = await options.getSourceRoute(intercept.sourceRouteIndex);
|
|
312
312
|
if (!sourceRoute) return { kind: "none" };
|
|
313
313
|
if (sourceRoute === options.currentRoute) return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
2
|
-
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
3
2
|
import { NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildRevalidateCacheControl } from "./cache-control.js";
|
|
3
|
+
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
4
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
5
5
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
6
|
//#region src/server/app-page-response.ts
|
|
@@ -37,6 +37,9 @@ type AppPageRouteWiringSlot<TModule extends AppPageModule = AppPageModule, TErro
|
|
|
37
37
|
layout?: TModule | null;
|
|
38
38
|
layoutIndex: number;
|
|
39
39
|
loading?: TModule | null;
|
|
40
|
+
loadings?: readonly (TModule | null | undefined)[] | null;
|
|
41
|
+
loadingTreePositions?: readonly number[] | null;
|
|
42
|
+
ownerTreePosition?: number | null;
|
|
40
43
|
notFound?: TModule | null;
|
|
41
44
|
notFoundTreePosition?: number | null;
|
|
42
45
|
page?: TModule | null;
|
|
@@ -59,6 +62,8 @@ type AppPageRouteWiringRoute<TModule extends AppPageModule = AppPageModule, TErr
|
|
|
59
62
|
layoutTreePositions?: readonly number[] | null;
|
|
60
63
|
layouts: readonly (TModule | null | undefined)[];
|
|
61
64
|
loading?: TModule | null;
|
|
65
|
+
loadings?: readonly (TModule | null | undefined)[] | null;
|
|
66
|
+
loadingTreePositions?: readonly number[] | null;
|
|
62
67
|
notFound?: TModule | null;
|
|
63
68
|
notFounds?: readonly (TModule | null | undefined)[] | null;
|
|
64
69
|
notFoundTreePosition?: number | null;
|
|
@@ -99,6 +104,8 @@ type AppPageSlotOverride<TModule extends AppPageModule = AppPageModule> = {
|
|
|
99
104
|
branchSegments?: readonly string[] | null;
|
|
100
105
|
layoutSegments?: readonly (readonly string[])[] | null;
|
|
101
106
|
layoutModules?: readonly (TModule | null | undefined)[] | null;
|
|
107
|
+
loadingModules?: readonly (TModule | null | undefined)[] | null;
|
|
108
|
+
loadingTreePositions?: readonly number[] | null;
|
|
102
109
|
/**
|
|
103
110
|
* The page module to render for this slot. Optional — when omitted, the
|
|
104
111
|
* slot's existing `page` is used (e.g. when the override only changes the
|