vinext 0.1.0 → 0.1.2
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 +2 -5
- package/dist/build/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +33 -1
- package/dist/build/client-build-config.js +66 -1
- package/dist/check.js +4 -3
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +11 -2
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +31 -5
- package/dist/config/config-matchers.js +50 -3
- package/dist/config/next-config.d.ts +29 -3
- package/dist/config/next-config.js +32 -2
- package/dist/deploy.js +47 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +61 -5
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +16 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +233 -280
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +35 -2
- package/dist/routing/app-route-graph.js +179 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +155 -215
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +13 -2
- package/dist/server/app-browser-navigation-controller.js +83 -4
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +10 -10
- package/dist/server/app-browser-visible-commit.js +10 -8
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +45 -21
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +14 -0
- package/dist/server/app-page-dispatch.js +21 -6
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +58 -17
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +11 -16
- package/dist/server/app-page-request.d.ts +9 -6
- package/dist/server/app-page-request.js +14 -10
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +10 -8
- package/dist/server/app-page-stream.d.ts +37 -7
- package/dist/server/app-page-stream.js +36 -6
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +15 -3
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +5 -4
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +22 -1
- package/dist/server/app-server-action-execution.js +73 -12
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +19 -3
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +97 -43
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +62 -1
- package/dist/server/navigation-planner.js +193 -3
- package/dist/server/navigation-trace.d.ts +12 -2
- package/dist/server/navigation-trace.js +11 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +5 -11
- package/dist/server/pages-node-compat.js +175 -118
- package/dist/server/pages-page-data.d.ts +38 -7
- package/dist/server/pages-page-data.js +64 -18
- package/dist/server/pages-page-handler.d.ts +10 -2
- package/dist/server/pages-page-handler.js +49 -20
- package/dist/server/pages-page-response.d.ts +55 -2
- package/dist/server/pages-page-response.js +74 -6
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +113 -0
- package/dist/server/pages-request-pipeline.js +230 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +45 -3
- package/dist/server/prod-server.js +182 -234
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +39 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +17 -7
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +28 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +9 -18
- package/dist/shims/navigation.js +96 -23
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +156 -22
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +41 -6
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +6 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/server/app-browser-rsc-redirect.d.ts
|
|
2
|
-
declare const MAX_RSC_REDIRECT_DEPTH = 10;
|
|
3
2
|
type RscRedirectHistoryUpdateMode = "push" | "replace" | undefined;
|
|
4
3
|
type RscRedirectLifecycleDecision = {
|
|
4
|
+
href: string;
|
|
5
5
|
kind: "no-redirect";
|
|
6
6
|
} | {
|
|
7
7
|
href: string;
|
|
@@ -24,5 +24,14 @@ declare function resolveRscRedirectLifecycleHop(options: {
|
|
|
24
24
|
requestPreviousNextUrl: string | null;
|
|
25
25
|
responseUrl: string;
|
|
26
26
|
}): RscRedirectLifecycleDecision;
|
|
27
|
+
declare function resolveStreamedRscRedirectLifecycleHop(options: {
|
|
28
|
+
currentHref: string;
|
|
29
|
+
historyUpdateMode: Exclude<RscRedirectHistoryUpdateMode, undefined>;
|
|
30
|
+
maxRedirectDepth?: number;
|
|
31
|
+
origin: string;
|
|
32
|
+
redirectDepth: number;
|
|
33
|
+
requestPreviousNextUrl: string | null;
|
|
34
|
+
streamedRedirectTarget: string;
|
|
35
|
+
}): RscRedirectLifecycleDecision;
|
|
27
36
|
//#endregion
|
|
28
|
-
export {
|
|
37
|
+
export { resolveRscRedirectLifecycleHop, resolveStreamedRscRedirectLifecycleHop };
|
|
@@ -6,17 +6,23 @@ function toVisibleAppHref(href, origin) {
|
|
|
6
6
|
stripRscCacheBustingSearchParam(url);
|
|
7
7
|
return `${stripRscSuffix(url.pathname)}${url.search}${url.hash}`;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
function toStreamedRedirectVisibleAppHref(href, origin) {
|
|
10
|
+
const url = new URL(href, origin);
|
|
11
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
12
|
+
}
|
|
13
|
+
function resolveRedirectLifecycleHopFromTarget(options) {
|
|
14
|
+
if (options.targetUrl.origin !== options.origin) return {
|
|
15
|
+
href: options.targetUrl.href,
|
|
13
16
|
kind: "terminal-hard-navigation",
|
|
14
17
|
reason: "externalRedirect",
|
|
15
18
|
redirectDepth: options.redirectDepth
|
|
16
19
|
};
|
|
17
|
-
const redirectedHref =
|
|
18
|
-
if (redirectedHref === toVisibleAppHref(options.currentHref, options.origin)) return {
|
|
19
|
-
|
|
20
|
+
const redirectedHref = options.redirectedHref;
|
|
21
|
+
if (redirectedHref === toVisibleAppHref(options.currentHref, options.origin)) return {
|
|
22
|
+
href: redirectedHref,
|
|
23
|
+
kind: "no-redirect"
|
|
24
|
+
};
|
|
25
|
+
const maxRedirectDepth = options.maxRedirectDepth ?? MAX_RSC_REDIRECT_DEPTH;
|
|
20
26
|
if (options.redirectDepth >= maxRedirectDepth) return {
|
|
21
27
|
href: redirectedHref,
|
|
22
28
|
kind: "terminal-hard-navigation",
|
|
@@ -31,5 +37,21 @@ function resolveRscRedirectLifecycleHop(options) {
|
|
|
31
37
|
redirectDepth: options.redirectDepth + 1
|
|
32
38
|
};
|
|
33
39
|
}
|
|
40
|
+
function resolveRscRedirectLifecycleHop(options) {
|
|
41
|
+
const responseUrl = new URL(options.responseUrl, options.origin);
|
|
42
|
+
return resolveRedirectLifecycleHopFromTarget({
|
|
43
|
+
...options,
|
|
44
|
+
redirectedHref: resolveHardNavigationTargetFromRscResponse(responseUrl.href, options.currentHref, options.origin),
|
|
45
|
+
targetUrl: responseUrl
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function resolveStreamedRscRedirectLifecycleHop(options) {
|
|
49
|
+
const streamedRedirectUrl = new URL(options.streamedRedirectTarget, options.origin);
|
|
50
|
+
return resolveRedirectLifecycleHopFromTarget({
|
|
51
|
+
...options,
|
|
52
|
+
redirectedHref: toStreamedRedirectVisibleAppHref(options.streamedRedirectTarget, options.origin),
|
|
53
|
+
targetUrl: streamedRedirectUrl
|
|
54
|
+
});
|
|
55
|
+
}
|
|
34
56
|
//#endregion
|
|
35
|
-
export {
|
|
57
|
+
export { resolveRscRedirectLifecycleHop, resolveStreamedRscRedirectLifecycleHop };
|
|
@@ -49,6 +49,7 @@ type AppRouterAction = {
|
|
|
49
49
|
previousNextUrl: string | null;
|
|
50
50
|
renderId: number;
|
|
51
51
|
rootLayoutTreePath: string | null;
|
|
52
|
+
reuseCurrentBfcacheIds: boolean;
|
|
52
53
|
routeId: string;
|
|
53
54
|
skippedLayoutIds: readonly string[];
|
|
54
55
|
slotBindings: readonly AppElementsSlotBinding[];
|
|
@@ -102,6 +103,7 @@ declare function createNextBfcacheIdMap(options: {
|
|
|
102
103
|
elements: AppElements;
|
|
103
104
|
nextPathname: string;
|
|
104
105
|
restored?: BfcacheIdMap | null;
|
|
106
|
+
reuseCurrent?: boolean;
|
|
105
107
|
}): BfcacheIdMap;
|
|
106
108
|
declare function preserveBfcacheIdsForMergedElements(options: {
|
|
107
109
|
elements: AppElements;
|
|
@@ -150,6 +152,7 @@ declare function createPendingNavigationCommit(options: {
|
|
|
150
152
|
previousNextUrl?: string | null;
|
|
151
153
|
renderId: number;
|
|
152
154
|
restoredBfcacheIds?: BfcacheIdMap | null;
|
|
155
|
+
reuseCurrentBfcacheIds?: boolean;
|
|
153
156
|
type: "navigate" | "replace" | "traverse";
|
|
154
157
|
}): Promise<PendingNavigationCommit>;
|
|
155
158
|
//#endregion
|
|
@@ -7,9 +7,10 @@ import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
|
|
|
7
7
|
import "./app-bfcache-id.js";
|
|
8
8
|
import { createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
|
|
9
9
|
import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
|
|
10
|
-
import { createCacheEntryReuseProof } from "./cache-proof.js";
|
|
11
10
|
import { NavigationTraceReasonCodes, createNavigationLifecycleTraceFields, createNavigationTrace } from "./navigation-trace.js";
|
|
12
11
|
import { navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts } from "./navigation-planner.js";
|
|
12
|
+
import { createSnapshotPathAndSearch } from "../shims/navigation.js";
|
|
13
|
+
import { createCacheEntryReuseProof } from "./cache-proof.js";
|
|
13
14
|
//#region src/server/app-browser-state.ts
|
|
14
15
|
const FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "fresh" };
|
|
15
16
|
const VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN = { origin: "visited-cache" };
|
|
@@ -99,7 +100,8 @@ function createBfcacheSegmentStateKeyMap(options) {
|
|
|
99
100
|
return stateKeys;
|
|
100
101
|
}
|
|
101
102
|
function createNextBfcacheIdMap(options) {
|
|
102
|
-
|
|
103
|
+
const current = options.reuseCurrent === false ? {} : options.current;
|
|
104
|
+
for (const value of Object.values(current)) rememberBfcacheId(value);
|
|
103
105
|
for (const value of Object.values(options.restored ?? {})) rememberBfcacheId(value);
|
|
104
106
|
const currentMetadata = readAppElementsMetadata(options.currentElements);
|
|
105
107
|
const nextMetadata = readAppElementsMetadata(options.elements);
|
|
@@ -113,7 +115,7 @@ function createNextBfcacheIdMap(options) {
|
|
|
113
115
|
}) === createBfcacheSegmentIdentity(id, {
|
|
114
116
|
metadata: nextMetadata,
|
|
115
117
|
pathname: nextPathname
|
|
116
|
-
}) ?
|
|
118
|
+
}) ? current[id] : void 0;
|
|
117
119
|
const value = options.restored?.[id] ?? currentValue ?? mintBfcacheId();
|
|
118
120
|
ids[id] = value;
|
|
119
121
|
rememberBfcacheId(value);
|
|
@@ -221,10 +223,6 @@ function createPendingNavigationTraceFields(options) {
|
|
|
221
223
|
...options.targetHref !== void 0 ? { targetHref: options.targetHref } : {}
|
|
222
224
|
};
|
|
223
225
|
}
|
|
224
|
-
function createNavigationSnapshotUrl(snapshot) {
|
|
225
|
-
const query = snapshot.searchParams.toString();
|
|
226
|
-
return query === "" ? snapshot.pathname : `${snapshot.pathname}?${query}`;
|
|
227
|
-
}
|
|
228
226
|
function createMountedParallelSlotSnapshots(elements) {
|
|
229
227
|
const snapshots = [];
|
|
230
228
|
for (const slotId of getMountedSlotIds(elements)) {
|
|
@@ -238,7 +236,7 @@ function createMountedParallelSlotSnapshots(elements) {
|
|
|
238
236
|
return snapshots;
|
|
239
237
|
}
|
|
240
238
|
function createVisibleRouteSnapshot(state) {
|
|
241
|
-
const displayUrl =
|
|
239
|
+
const displayUrl = createSnapshotPathAndSearch(state.navigationSnapshot);
|
|
242
240
|
const matchedUrl = normalizeNavigationSnapshotMatchedUrl(state.navigationSnapshot.pathname);
|
|
243
241
|
return {
|
|
244
242
|
displayUrl,
|
|
@@ -256,7 +254,7 @@ function createVisibleRouteSnapshot(state) {
|
|
|
256
254
|
};
|
|
257
255
|
}
|
|
258
256
|
function createPendingRouteSnapshot(pending) {
|
|
259
|
-
const displayUrl =
|
|
257
|
+
const displayUrl = createSnapshotPathAndSearch(pending.action.navigationSnapshot);
|
|
260
258
|
const matchedUrl = normalizeNavigationSnapshotMatchedUrl(pending.action.navigationSnapshot.pathname);
|
|
261
259
|
return {
|
|
262
260
|
displayUrl,
|
|
@@ -396,7 +394,8 @@ async function createPendingNavigationCommit(options) {
|
|
|
396
394
|
currentPathname: options.currentState.navigationSnapshot.pathname,
|
|
397
395
|
elements,
|
|
398
396
|
nextPathname: options.navigationSnapshot.pathname,
|
|
399
|
-
restored: options.restoredBfcacheIds
|
|
397
|
+
restored: options.restoredBfcacheIds,
|
|
398
|
+
reuseCurrent: options.reuseCurrentBfcacheIds
|
|
400
399
|
}),
|
|
401
400
|
...cacheEntryReuseProof ? { cacheEntryReuseProof } : {},
|
|
402
401
|
elements,
|
|
@@ -414,6 +413,7 @@ async function createPendingNavigationCommit(options) {
|
|
|
414
413
|
previousNextUrl,
|
|
415
414
|
renderId: options.renderId,
|
|
416
415
|
rootLayoutTreePath: metadata.rootLayoutTreePath,
|
|
416
|
+
reuseCurrentBfcacheIds: options.reuseCurrentBfcacheIds ?? true,
|
|
417
417
|
routeId: metadata.routeId,
|
|
418
418
|
skippedLayoutIds: metadata.skippedLayoutIds,
|
|
419
419
|
type: options.type
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
2
2
|
import "./app-elements.js";
|
|
3
|
-
import { mergeElements } from "../shims/slot.js";
|
|
4
3
|
import { NavigationTraceReasonCodes, NavigationTraceTransactionCodes, createNavigationTrace, prependNavigationTraceEntry } from "./navigation-trace.js";
|
|
4
|
+
import { mergeElements } from "../shims/slot.js";
|
|
5
5
|
import { createPendingNavigationCommit, preserveBfcacheIdsForMergedElements, resolvePendingNavigationCommitDispositionDecision } from "./app-browser-state.js";
|
|
6
6
|
//#region src/server/app-browser-visible-commit.ts
|
|
7
7
|
const approvedVisibleCommitBrand = Symbol("ApprovedVisibleCommit");
|
|
@@ -56,29 +56,31 @@ function reduceApprovedVisibleCommitState(state, commit) {
|
|
|
56
56
|
switch (action.type) {
|
|
57
57
|
case "traverse":
|
|
58
58
|
case "navigate": {
|
|
59
|
+
const preserveElementIds = action.reuseCurrentBfcacheIds ? commit.decision.preserveElementIds : [];
|
|
60
|
+
const preservePreviousSlotIds = action.reuseCurrentBfcacheIds ? commit.decision.preservePreviousSlotIds : [];
|
|
59
61
|
const mergedElements = mergeElements(state.elements, action.elements, {
|
|
60
|
-
clearAbsentSlots: action.type === "traverse",
|
|
61
|
-
preserveAbsentSlots: commit.decision.preserveAbsentSlots,
|
|
62
|
-
preserveElementIds
|
|
63
|
-
preservePreviousSlotIds
|
|
62
|
+
clearAbsentSlots: action.type === "traverse" || !action.reuseCurrentBfcacheIds,
|
|
63
|
+
preserveAbsentSlots: action.reuseCurrentBfcacheIds && commit.decision.preserveAbsentSlots,
|
|
64
|
+
preserveElementIds,
|
|
65
|
+
preservePreviousSlotIds
|
|
64
66
|
});
|
|
65
67
|
return commitVisibleRouterState(state, {
|
|
66
68
|
bfcacheIds: preserveBfcacheIdsForMergedElements({
|
|
67
69
|
elements: mergedElements,
|
|
68
70
|
next: action.bfcacheIds,
|
|
69
|
-
previous: state.bfcacheIds
|
|
71
|
+
previous: action.reuseCurrentBfcacheIds ? state.bfcacheIds : {}
|
|
70
72
|
}),
|
|
71
73
|
elements: mergedElements,
|
|
72
74
|
interception: action.interception,
|
|
73
75
|
interceptionContext: action.interceptionContext,
|
|
74
|
-
layoutFlags: mergeLayoutFlags(state.layoutFlags, action.layoutFlags,
|
|
76
|
+
layoutFlags: mergeLayoutFlags(state.layoutFlags, action.layoutFlags, preserveElementIds),
|
|
75
77
|
layoutIds: action.layoutIds,
|
|
76
78
|
navigationSnapshot: action.navigationSnapshot,
|
|
77
79
|
previousNextUrl: action.previousNextUrl,
|
|
78
80
|
renderId: action.renderId,
|
|
79
81
|
rootLayoutTreePath: action.rootLayoutTreePath,
|
|
80
82
|
routeId: action.routeId,
|
|
81
|
-
slotBindings: mergeSlotBindings(state.slotBindings, action.slotBindings, action.layoutIds,
|
|
83
|
+
slotBindings: mergeSlotBindings(state.slotBindings, action.slotBindings, action.layoutIds, preservePreviousSlotIds)
|
|
82
84
|
}, action.operation);
|
|
83
85
|
}
|
|
84
86
|
case "replace": return commitVisibleRouterState(state, {
|
|
@@ -52,7 +52,8 @@ type AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> =
|
|
|
52
52
|
loadGlobalNotFoundModule?: (() => Promise<TModule | null | undefined>) | null;
|
|
53
53
|
makeThenableParams: (params: AppPageParams) => unknown;
|
|
54
54
|
metadataRoutes: MetadataFileRoute[]; /** Configured next.config `basePath`, threaded into file-based metadata href emission. */
|
|
55
|
-
basePath?: string;
|
|
55
|
+
basePath?: string; /** Configured next.config `trailingSlash`, threaded into canonical URL rendering. */
|
|
56
|
+
trailingSlash?: boolean;
|
|
56
57
|
resolveChildSegments: (routeSegments: readonly string[], treePosition: number, params: AppPageParams) => string[];
|
|
57
58
|
rootBoundaries: AppFallbackRendererRootBoundaries<TModule>;
|
|
58
59
|
rscRenderer: (element: ReactNode | AppElements, options: {
|
|
@@ -7,7 +7,7 @@ const EMPTY_MW_CTX = {
|
|
|
7
7
|
status: null
|
|
8
8
|
};
|
|
9
9
|
function createAppFallbackRenderer(options) {
|
|
10
|
-
const { basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader } = options;
|
|
10
|
+
const { basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader, trailingSlash } = options;
|
|
11
11
|
const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } = rootBoundaries;
|
|
12
12
|
const effectiveGlobalErrorModule = globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE;
|
|
13
13
|
const effectiveRootNotFoundModule = rootNotFoundModule ?? DEFAULT_NOT_FOUND_MODULE;
|
|
@@ -58,6 +58,7 @@ function createAppFallbackRenderer(options) {
|
|
|
58
58
|
}
|
|
59
59
|
return renderAppPageHttpAccessFallback({
|
|
60
60
|
basePath,
|
|
61
|
+
trailingSlash,
|
|
61
62
|
boundaryComponent: opts?.boundaryComponent ?? null,
|
|
62
63
|
boundaryModule: opts?.boundaryModule ?? null,
|
|
63
64
|
buildFontLinkHeader: fontProviders.buildFontLinkHeader,
|
|
@@ -96,6 +97,7 @@ function createAppFallbackRenderer(options) {
|
|
|
96
97
|
renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext) {
|
|
97
98
|
return renderAppPageErrorBoundary({
|
|
98
99
|
basePath,
|
|
100
|
+
trailingSlash,
|
|
99
101
|
buildFontLinkHeader: fontProviders.buildFontLinkHeader,
|
|
100
102
|
clearRequestContext,
|
|
101
103
|
createRscOnErrorHandler(pathname, routePath) {
|
|
@@ -10,6 +10,50 @@ type HistoryTraversalIntent = {
|
|
|
10
10
|
historyState: unknown;
|
|
11
11
|
targetHistoryIndex: number | null;
|
|
12
12
|
};
|
|
13
|
+
type HistoryStateSnapshotRestoreDecision<TState> = {
|
|
14
|
+
kind: "restore";
|
|
15
|
+
state: TState;
|
|
16
|
+
targetHistoryIndex: number;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "skip";
|
|
19
|
+
reason: "guarded" | "missing-history-index" | "missing-snapshot" | "stale-bfcache-version";
|
|
20
|
+
targetHistoryIndex: number | null;
|
|
21
|
+
};
|
|
22
|
+
declare class HistoryStateSnapshotCache<TState> {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(options: {
|
|
25
|
+
maxEntries: number;
|
|
26
|
+
});
|
|
27
|
+
clear(): void;
|
|
28
|
+
remember(options: {
|
|
29
|
+
bfcacheVersion: number;
|
|
30
|
+
historyIndex: number | null;
|
|
31
|
+
state: TState;
|
|
32
|
+
}): void;
|
|
33
|
+
resolveRestore(options: {
|
|
34
|
+
currentBfcacheVersion: number;
|
|
35
|
+
guarded: boolean;
|
|
36
|
+
historyState: unknown;
|
|
37
|
+
}): HistoryStateSnapshotRestoreDecision<TState>;
|
|
38
|
+
}
|
|
39
|
+
declare class RestorableClientStateController<TState> {
|
|
40
|
+
#private;
|
|
41
|
+
constructor(options: {
|
|
42
|
+
initialHistoryState: unknown;
|
|
43
|
+
maxHistoryStateSnapshots: number;
|
|
44
|
+
});
|
|
45
|
+
get currentBfcacheVersion(): number;
|
|
46
|
+
beginCacheInvalidationGuard(): () => void;
|
|
47
|
+
isCacheInvalidationGuarded(): boolean;
|
|
48
|
+
isCurrentBfcacheVersion(historyState: unknown): boolean;
|
|
49
|
+
readCurrentBfcacheVersionHistoryIds(historyState: unknown): BfcacheIdMap | null;
|
|
50
|
+
invalidateClientState(): void;
|
|
51
|
+
rememberHistoryStateSnapshot(options: {
|
|
52
|
+
historyIndex: number | null;
|
|
53
|
+
state: TState;
|
|
54
|
+
}): void;
|
|
55
|
+
resolveHistoryStateSnapshotRestore(historyState: unknown): HistoryStateSnapshotRestoreDecision<TState>;
|
|
56
|
+
}
|
|
13
57
|
declare function createHistoryStateWithPreviousNextUrl(state: unknown, previousNextUrl: string | null): HistoryStateRecord | null;
|
|
14
58
|
declare function createHistoryStateWithNavigationMetadata(state: unknown, metadata: {
|
|
15
59
|
bfcacheIds?: BfcacheIdMap | null;
|
|
@@ -39,4 +83,4 @@ declare function resolveHistoryTraversalIntent(options: {
|
|
|
39
83
|
historyState: unknown;
|
|
40
84
|
}): HistoryTraversalIntent;
|
|
41
85
|
//#endregion
|
|
42
|
-
export { BfcacheIdMap, HistoryTraversalIntent, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
86
|
+
export { BfcacheIdMap, HistoryStateSnapshotCache, HistoryTraversalIntent, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
@@ -6,6 +6,114 @@ const VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY = "__vinext_previousNextUrl";
|
|
|
6
6
|
const VINEXT_HISTORY_INDEX_HISTORY_STATE_KEY = "__vinext_historyIndex";
|
|
7
7
|
const VINEXT_BFCACHE_IDS_HISTORY_STATE_KEY = "__vinext_bfcacheIds";
|
|
8
8
|
const VINEXT_BFCACHE_VERSION_HISTORY_STATE_KEY = "__vinext_bfcacheVersion";
|
|
9
|
+
var HistoryStateSnapshotCache = class {
|
|
10
|
+
#maxEntries;
|
|
11
|
+
#snapshots = /* @__PURE__ */ new Map();
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.#maxEntries = options.maxEntries;
|
|
14
|
+
}
|
|
15
|
+
clear() {
|
|
16
|
+
this.#snapshots.clear();
|
|
17
|
+
}
|
|
18
|
+
remember(options) {
|
|
19
|
+
if (options.historyIndex === null) return;
|
|
20
|
+
this.#snapshots.delete(options.historyIndex);
|
|
21
|
+
this.#snapshots.set(options.historyIndex, {
|
|
22
|
+
bfcacheVersion: options.bfcacheVersion,
|
|
23
|
+
state: options.state
|
|
24
|
+
});
|
|
25
|
+
if (this.#snapshots.size <= this.#maxEntries) return;
|
|
26
|
+
const oldestIndex = this.#snapshots.keys().next().value;
|
|
27
|
+
if (typeof oldestIndex === "number") this.#snapshots.delete(oldestIndex);
|
|
28
|
+
}
|
|
29
|
+
resolveRestore(options) {
|
|
30
|
+
const targetHistoryIndex = readHistoryStateTraversalIndex(options.historyState);
|
|
31
|
+
if (targetHistoryIndex === null) return {
|
|
32
|
+
kind: "skip",
|
|
33
|
+
reason: "missing-history-index",
|
|
34
|
+
targetHistoryIndex
|
|
35
|
+
};
|
|
36
|
+
const snapshot = this.#snapshots.get(targetHistoryIndex);
|
|
37
|
+
if (!snapshot) return {
|
|
38
|
+
kind: "skip",
|
|
39
|
+
reason: "missing-snapshot",
|
|
40
|
+
targetHistoryIndex
|
|
41
|
+
};
|
|
42
|
+
if (options.guarded) return {
|
|
43
|
+
kind: "skip",
|
|
44
|
+
reason: "guarded",
|
|
45
|
+
targetHistoryIndex
|
|
46
|
+
};
|
|
47
|
+
if (snapshot.bfcacheVersion !== options.currentBfcacheVersion) {
|
|
48
|
+
this.#snapshots.delete(targetHistoryIndex);
|
|
49
|
+
return {
|
|
50
|
+
kind: "skip",
|
|
51
|
+
reason: "stale-bfcache-version",
|
|
52
|
+
targetHistoryIndex
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
kind: "restore",
|
|
57
|
+
state: snapshot.state,
|
|
58
|
+
targetHistoryIndex
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var RestorableClientStateController = class {
|
|
63
|
+
#currentBfcacheVersion;
|
|
64
|
+
#pendingCacheInvalidationGuards = 0;
|
|
65
|
+
#snapshots;
|
|
66
|
+
constructor(options) {
|
|
67
|
+
const initialHistoryBfcacheVersion = readHistoryStateBfcacheVersion(options.initialHistoryState);
|
|
68
|
+
this.#currentBfcacheVersion = initialHistoryBfcacheVersion === null ? 0 : initialHistoryBfcacheVersion + 1;
|
|
69
|
+
this.#snapshots = new HistoryStateSnapshotCache({ maxEntries: options.maxHistoryStateSnapshots });
|
|
70
|
+
}
|
|
71
|
+
get currentBfcacheVersion() {
|
|
72
|
+
return this.#currentBfcacheVersion;
|
|
73
|
+
}
|
|
74
|
+
beginCacheInvalidationGuard() {
|
|
75
|
+
this.#pendingCacheInvalidationGuards += 1;
|
|
76
|
+
let released = false;
|
|
77
|
+
return () => {
|
|
78
|
+
if (released) return;
|
|
79
|
+
released = true;
|
|
80
|
+
this.#pendingCacheInvalidationGuards = Math.max(0, this.#pendingCacheInvalidationGuards - 1);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
isCacheInvalidationGuarded() {
|
|
84
|
+
return this.#pendingCacheInvalidationGuards > 0;
|
|
85
|
+
}
|
|
86
|
+
isCurrentBfcacheVersion(historyState) {
|
|
87
|
+
return isHistoryStateBfcacheVersionCurrent(historyState, this.#currentBfcacheVersion);
|
|
88
|
+
}
|
|
89
|
+
readCurrentBfcacheVersionHistoryIds(historyState) {
|
|
90
|
+
if (this.isCacheInvalidationGuarded()) return null;
|
|
91
|
+
const ids = readHistoryStateBfcacheIds(historyState);
|
|
92
|
+
if (ids === null) return null;
|
|
93
|
+
return this.isCurrentBfcacheVersion(historyState) ? ids : null;
|
|
94
|
+
}
|
|
95
|
+
#invalidateBfcacheIds() {
|
|
96
|
+
this.#currentBfcacheVersion += 1;
|
|
97
|
+
}
|
|
98
|
+
invalidateClientState() {
|
|
99
|
+
this.#snapshots.clear();
|
|
100
|
+
this.#invalidateBfcacheIds();
|
|
101
|
+
}
|
|
102
|
+
rememberHistoryStateSnapshot(options) {
|
|
103
|
+
this.#snapshots.remember({
|
|
104
|
+
bfcacheVersion: this.#currentBfcacheVersion,
|
|
105
|
+
historyIndex: options.historyIndex,
|
|
106
|
+
state: options.state
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
resolveHistoryStateSnapshotRestore(historyState) {
|
|
110
|
+
return this.#snapshots.resolveRestore({
|
|
111
|
+
currentBfcacheVersion: this.#currentBfcacheVersion,
|
|
112
|
+
guarded: this.isCacheInvalidationGuarded(),
|
|
113
|
+
historyState
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
9
117
|
function cloneHistoryState(state) {
|
|
10
118
|
if (!state || typeof state !== "object") return {};
|
|
11
119
|
const nextState = {};
|
|
@@ -112,4 +220,4 @@ function resolveHistoryTraversalIntent(options) {
|
|
|
112
220
|
};
|
|
113
221
|
}
|
|
114
222
|
//#endregion
|
|
115
|
-
export { createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
223
|
+
export { HistoryStateSnapshotCache, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
@@ -115,6 +115,7 @@ async function applyAppMiddleware(options) {
|
|
|
115
115
|
if (!forwarded.applied) {
|
|
116
116
|
const result = await executeMiddleware({
|
|
117
117
|
basePath: options.basePath,
|
|
118
|
+
hadBasePath: true,
|
|
118
119
|
i18nConfig: options.i18nConfig,
|
|
119
120
|
isDataRequest: options.isDataRequest,
|
|
120
121
|
isProxy: options.isProxy,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildParams, decodeMatchedParams, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
2
|
import { stripBasePath } from "../utils/base-path.js";
|
|
3
|
+
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
3
4
|
import { isUnknownRecord } from "../utils/record.js";
|
|
4
5
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
6
|
import "./app-elements.js";
|
|
@@ -135,6 +136,20 @@ function matchOptimisticRouteManifestRoute(options) {
|
|
|
135
136
|
decodeMatchedParams(match.params);
|
|
136
137
|
return match;
|
|
137
138
|
}
|
|
139
|
+
function mergeParams(target, source) {
|
|
140
|
+
for (const [key, value] of Object.entries(source)) target[key] = value;
|
|
141
|
+
}
|
|
142
|
+
function resolveOptimisticNavigationParams(options) {
|
|
143
|
+
const navigationParams = { ...options.match.params };
|
|
144
|
+
for (const binding of options.routeManifest.segmentGraph.slotBindings.values()) {
|
|
145
|
+
if (binding.routeId !== options.match.route.id || binding.state !== "active") continue;
|
|
146
|
+
const patternParts = binding.slotPatternParts;
|
|
147
|
+
if (!patternParts) continue;
|
|
148
|
+
const matched = matchRoutePattern(options.urlParts, patternParts);
|
|
149
|
+
if (matched) mergeParams(navigationParams, matched);
|
|
150
|
+
}
|
|
151
|
+
return navigationParams;
|
|
152
|
+
}
|
|
138
153
|
function elementHasSuspenseFallback(value, depth = 0) {
|
|
139
154
|
if (depth > 100) return false;
|
|
140
155
|
if (Array.isArray(value)) return value.some((entry) => elementHasSuspenseFallback(entry, depth + 1));
|
|
@@ -183,6 +198,8 @@ function createOptimisticRouteElements(template) {
|
|
|
183
198
|
}
|
|
184
199
|
function resolveOptimisticNavigationPayload(options) {
|
|
185
200
|
if (options.interceptionContext !== null) return null;
|
|
201
|
+
const urlParts = hrefToRouteParts(options.href, options.basePath);
|
|
202
|
+
if (urlParts === null) return null;
|
|
186
203
|
const match = matchOptimisticRouteManifestRoute({
|
|
187
204
|
basePath: options.basePath,
|
|
188
205
|
href: options.href,
|
|
@@ -198,7 +215,11 @@ function resolveOptimisticNavigationPayload(options) {
|
|
|
198
215
|
if (template.mountedSlotsHeader !== options.mountedSlotsHeader) return null;
|
|
199
216
|
return {
|
|
200
217
|
elements: createOptimisticRouteElements(template),
|
|
201
|
-
params:
|
|
218
|
+
params: resolveOptimisticNavigationParams({
|
|
219
|
+
match,
|
|
220
|
+
routeManifest: options.routeManifest,
|
|
221
|
+
urlParts
|
|
222
|
+
}),
|
|
202
223
|
template
|
|
203
224
|
};
|
|
204
225
|
}
|
|
@@ -41,7 +41,8 @@ type AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageM
|
|
|
41
41
|
makeThenableParams: (params: AppPageParams) => unknown;
|
|
42
42
|
middlewareContext: AppPageMiddlewareContext;
|
|
43
43
|
metadataRoutes: MetadataFileRoute[]; /** Configured next.config `basePath`, threaded into file-based metadata href emission. */
|
|
44
|
-
basePath?: string;
|
|
44
|
+
basePath?: string; /** Configured next.config `trailingSlash`, threaded into canonical URL rendering. */
|
|
45
|
+
trailingSlash?: boolean;
|
|
45
46
|
renderToReadableStream: (element: ReactNode | AppElements, options: {
|
|
46
47
|
onError: AppPageBoundaryOnError;
|
|
47
48
|
}) => ReadableStream<Uint8Array>;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
2
2
|
import "./app-elements.js";
|
|
3
|
-
import {
|
|
3
|
+
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
4
|
+
import { ErrorBoundary, GlobalErrorBoundary } from "../shims/error-boundary.js";
|
|
4
5
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
5
6
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
7
|
+
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
6
8
|
import { resolveAppPageHead } from "./app-page-head.js";
|
|
7
9
|
import { createAppPageLayoutEntries } from "./app-page-route-wiring.js";
|
|
8
10
|
import { buildClientHookErrorMessage } from "../shims/client-hook-error.js";
|
|
11
|
+
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
9
12
|
import { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryModule, wrapAppPageBoundaryElement } from "./app-page-boundary.js";
|
|
10
13
|
import { createAppPageFontData, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
11
14
|
import { Fragment, createElement } from "react";
|
|
12
15
|
//#region src/server/app-page-boundary-render.ts
|
|
16
|
+
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
13
17
|
function getDefaultExport(module) {
|
|
14
18
|
return module?.default ?? null;
|
|
15
19
|
}
|
|
@@ -25,9 +29,12 @@ function wrapRenderedBoundaryElement(options) {
|
|
|
25
29
|
makeThenableParams: options.makeThenableParams,
|
|
26
30
|
matchedParams: options.matchedParams,
|
|
27
31
|
renderErrorBoundary(GlobalErrorComponent, children) {
|
|
28
|
-
return createElement(
|
|
29
|
-
fallback:
|
|
30
|
-
children
|
|
32
|
+
return createElement(GlobalErrorBoundary, {
|
|
33
|
+
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
34
|
+
children: createElement(ErrorBoundary, {
|
|
35
|
+
fallback: GlobalErrorComponent,
|
|
36
|
+
children
|
|
37
|
+
})
|
|
31
38
|
});
|
|
32
39
|
},
|
|
33
40
|
renderLayout(LayoutComponent, children, asyncParams) {
|
|
@@ -161,7 +168,8 @@ async function renderAppPageHttpAccessFallback(options) {
|
|
|
161
168
|
if (metadata) headElements.push(createElement(MetadataHead, {
|
|
162
169
|
key: "metadata",
|
|
163
170
|
metadata,
|
|
164
|
-
pathname
|
|
171
|
+
pathname,
|
|
172
|
+
trailingSlash: options.trailingSlash
|
|
165
173
|
}));
|
|
166
174
|
headElements.push(createElement(ViewportHead, {
|
|
167
175
|
key: "viewport",
|
|
@@ -224,7 +232,8 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
224
232
|
if (metadata) headElements.push(createElement(MetadataHead, {
|
|
225
233
|
key: "metadata",
|
|
226
234
|
metadata,
|
|
227
|
-
pathname
|
|
235
|
+
pathname,
|
|
236
|
+
trailingSlash: options.trailingSlash
|
|
228
237
|
}));
|
|
229
238
|
headElements.push(createElement(ViewportHead, {
|
|
230
239
|
key: "viewport",
|
|
@@ -233,22 +242,28 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
233
242
|
} catch (error) {
|
|
234
243
|
console.error(`[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`, error);
|
|
235
244
|
}
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
const buildElement = (BoundaryComponent) => {
|
|
246
|
+
const boundaryElement = createElement(BoundaryComponent, { error: errorObject });
|
|
247
|
+
return wrapRenderedBoundaryElement({
|
|
248
|
+
element: createElement(Fragment, null, ...headElements, errorBoundary.isGlobalError ? createElement(GlobalErrorBoundary, {
|
|
249
|
+
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
250
|
+
children: boundaryElement
|
|
251
|
+
}) : boundaryElement),
|
|
252
|
+
globalErrorModule: options.globalErrorModule,
|
|
253
|
+
includeGlobalErrorBoundary: !errorBoundary.isGlobalError,
|
|
254
|
+
isRscRequest: options.isRscRequest,
|
|
255
|
+
layoutModules,
|
|
256
|
+
layoutTreePositions: options.route?.layoutTreePositions,
|
|
257
|
+
makeThenableParams: options.makeThenableParams,
|
|
258
|
+
matchedParams,
|
|
259
|
+
resolveChildSegments: options.resolveChildSegments,
|
|
260
|
+
routeSegments: options.route?.routeSegments,
|
|
261
|
+
skipLayoutWrapping: errorBoundary.isGlobalError
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
const renderWith = (BoundaryComponent) => renderAppPageBoundaryElementResponse({
|
|
250
265
|
...options,
|
|
251
|
-
element,
|
|
266
|
+
element: buildElement(BoundaryComponent),
|
|
252
267
|
initialDevServerError: rawError,
|
|
253
268
|
layoutModules,
|
|
254
269
|
navigationParams: matchedParams,
|
|
@@ -256,6 +271,15 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
256
271
|
routePattern: options.route?.pattern,
|
|
257
272
|
status: 200
|
|
258
273
|
});
|
|
274
|
+
try {
|
|
275
|
+
return await renderWith(errorBoundary.component);
|
|
276
|
+
} catch (renderError) {
|
|
277
|
+
if (errorBoundary.isGlobalError && !isNavigationSignalError(renderError) && !resolveAppPageSpecialError(renderError)) {
|
|
278
|
+
console.error(`[vinext] global-error.tsx threw while rendering for ${options.route?.pattern ?? pathname}; falling back to the built-in default global-error:`, renderError);
|
|
279
|
+
return renderWith(DEFAULT_GLOBAL_ERROR_COMPONENT);
|
|
280
|
+
}
|
|
281
|
+
throw renderError;
|
|
282
|
+
}
|
|
259
283
|
}
|
|
260
284
|
const _clientHookPattern = /\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\b.*is not a function/;
|
|
261
285
|
function rewriteClientHookError(error) {
|