vinext 1.4.0 → 1.4.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 +21 -21
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/build/prerender.js +3 -2
- package/dist/check.js +4 -7
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +19 -3
- package/dist/config/config-matchers.js +4 -2
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +55 -2
- package/dist/config/next-config.d.ts +22 -1
- package/dist/config/next-config.js +49 -4
- package/dist/entries/app-rsc-entry.js +41 -19
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +5 -1
- package/dist/index.js +44 -32
- package/dist/init-cloudflare.js +18 -2
- package/dist/plugins/css-target.d.ts +18 -0
- package/dist/plugins/css-target.js +93 -0
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/routing/app-route-graph.d.ts +10 -0
- package/dist/routing/app-route-graph.js +15 -1
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +5 -6
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +28 -7
- package/dist/server/app-browser-rsc-redirect.js +3 -3
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-visible-commit.js +2 -2
- package/dist/server/app-elements.d.ts +3 -0
- package/dist/server/app-elements.js +14 -1
- package/dist/server/app-fallback-renderer.js +2 -2
- package/dist/server/app-optimistic-routing.d.ts +12 -1
- package/dist/server/app-optimistic-routing.js +40 -19
- package/dist/server/app-page-boundary-render.js +7 -12
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -2
- package/dist/server/app-page-dispatch.js +73 -31
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +40 -52
- package/dist/server/app-page-execution.js +9 -6
- package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
- package/dist/server/app-page-intercept-segment-config.js +90 -0
- package/dist/server/app-page-navigation-params.d.ts +23 -0
- package/dist/server/app-page-navigation-params.js +49 -0
- package/dist/server/app-page-render.d.ts +5 -3
- package/dist/server/app-page-render.js +31 -17
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +34 -13
- package/dist/server/app-page-segment-plan.js +9 -1
- package/dist/server/app-page-segment-state.d.ts +9 -0
- package/dist/server/app-page-segment-state.js +54 -1
- package/dist/server/app-page-stream.d.ts +10 -8
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-response-stage-entry.js +1 -0
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +11 -7
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +10 -10
- package/dist/server/app-rsc-cache-busting.js +27 -68
- package/dist/server/app-rsc-error-handler.js +1 -1
- package/dist/server/app-rsc-errors.js +4 -1
- package/dist/server/app-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +126 -103
- package/dist/server/app-rsc-request-normalization.d.ts +10 -12
- package/dist/server/app-rsc-request-normalization.js +11 -14
- package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
- package/dist/server/app-rsc-response-finalizer.js +11 -1
- package/dist/server/app-rsc-response-stage.js +4 -12
- package/dist/server/app-rsc-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +24 -14
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +13 -8
- package/dist/server/app-worker-stages.d.ts +12 -3
- package/dist/server/app-worker-stages.js +37 -4
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -1
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +2 -1
- package/dist/server/image-local-patterns.d.ts +21 -0
- package/dist/server/image-local-patterns.js +59 -0
- package/dist/server/image-optimization.d.ts +28 -22
- package/dist/server/image-optimization.js +17 -2
- package/dist/server/isr-cache.js +4 -1
- package/dist/server/metadata-route-response.js +25 -7
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +7 -3
- package/dist/server/nitro-public-files-plugin.js +20 -8
- package/dist/server/pages-data-route.d.ts +5 -1
- package/dist/server/pages-data-route.js +14 -6
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +2 -0
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +17 -6
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +25 -4
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +59 -17
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +14 -4
- package/dist/server/request-pipeline.js +33 -15
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-image-optimization.d.ts +2 -2
- package/dist/server/worker-image-optimization.js +18 -3
- package/dist/server/worker-utils.d.ts +8 -0
- package/dist/server/worker-utils.js +19 -2
- package/dist/shims/cache-request-state.d.ts +6 -6
- package/dist/shims/cache-request-state.js +6 -36
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +77 -47
- package/dist/shims/cache.d.ts +10 -5
- package/dist/shims/cache.js +35 -22
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/fetch-cache.js +6 -2
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.js +5 -3
- package/dist/shims/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/link.js +5 -10
- package/dist/shims/navigation.js +2 -3
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/slot.d.ts +9 -2
- package/dist/shims/slot.js +76 -11
- package/dist/shims/unified-request-context.d.ts +6 -0
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/package.json +1 -1
|
@@ -23,11 +23,11 @@ import { navigationPlanner } from "./navigation-planner.js";
|
|
|
23
23
|
import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
|
|
24
24
|
import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
25
25
|
import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
|
|
26
|
-
import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
|
|
26
|
+
import { DYNAMIC_NAVIGATION_CACHE_TTL, PREFETCH_CACHE_TTL, __basePath, activateNavigationSnapshot, appRouterInstance, commitClientNavigationState, consumePrefetchResponse, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, deletePrefetchResponseSnapshot, disableNavigationResponsePrefetchCacheReuse, getClientNavigationRenderContext, getMountedSlotsHeader, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidateDynamicPrefetchCache, invalidatePrefetchCache, invalidateVisitedResponsePrefetches, parseRenderedPathAndSearchHeader, preloadHybridClientRouteOwner, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolveLoadedHybridClientRewriteHref, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, seedPrefetchResponseSnapshot, setClientParams, setMountedSlotsHeader, setPendingPathname, trackAppRouterNavigationInFlight, useRouter } from "../shims/navigation.js";
|
|
27
27
|
import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
|
|
28
28
|
import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
|
|
29
29
|
import { createMountedLayoutsHeader, holdsSkippedLayouts } from "./app-mounted-layouts.js";
|
|
30
|
-
import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, setAppElementsRenderedSearch } from "../shims/slot.js";
|
|
30
|
+
import { BfcacheIdentityMapContext, bindAppElementsRenderedSearch, isBfcacheIdentityRetained, setAppElementsRenderedSearch } from "../shims/slot.js";
|
|
31
31
|
import { COMMITTED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, isCompleteAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl } from "./app-browser-state.js";
|
|
32
32
|
import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, navigateDocumentDirectly } from "./app-browser-navigation-controller.js";
|
|
33
33
|
import { createAppRouteTree } from "./app-route-tree.js";
|
|
@@ -45,7 +45,7 @@ import { createHydrationCachePublication } from "./app-hydration-cache-publicati
|
|
|
45
45
|
import { peekSettledPrefetchResponseForNavigation, prepareConsumedPrefetchResponseForPublication, preserveCommittedPrefetchExpiry, resolvePrefetchNavigationResponseUrl } from "./app-browser-prefetch-response.js";
|
|
46
46
|
import { canCommitOptimisticRouteTemplate, createOptimisticRouteTemplate, createOptimisticRouteTemplateStore, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, keepOptimisticStreamingMetadata, resolveOptimisticNavigationParamsForHref, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
|
|
47
47
|
import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
|
|
48
|
-
import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
48
|
+
import { Fragment, createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
49
49
|
import { createRoot, hydrateRoot } from "react-dom/client";
|
|
50
50
|
import { createFromFetch, createFromReadableStream, setServerCallback } from "@vitejs/plugin-rsc/browser";
|
|
51
51
|
import { flushSync } from "react-dom";
|
|
@@ -195,6 +195,12 @@ const RSC_HMR_SETTLE_DELAY_MS = 150;
|
|
|
195
195
|
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
196
196
|
let latestRscHmrUpdateId = 0;
|
|
197
197
|
let synchronousPopstateScrollRestoreNavigationId = null;
|
|
198
|
+
let pendingHistoryRestoreCommit = null;
|
|
199
|
+
function flushPendingHistoryRestoreCommit() {
|
|
200
|
+
const commit = pendingHistoryRestoreCommit;
|
|
201
|
+
pendingHistoryRestoreCommit = null;
|
|
202
|
+
commit?.();
|
|
203
|
+
}
|
|
198
204
|
function waitForRscHmrSettle(delayMs = RSC_HMR_SETTLE_DELAY_MS) {
|
|
199
205
|
return new Promise((resolve) => {
|
|
200
206
|
window.setTimeout(resolve, delayMs);
|
|
@@ -212,6 +218,10 @@ function restoreHistoryStateSnapshot(historyState, navId, onApprovedBeforeCommit
|
|
|
212
218
|
beforeCommit: () => {
|
|
213
219
|
onApprovedBeforeCommit?.();
|
|
214
220
|
beforeCommit();
|
|
221
|
+
if (!restoreCopiedExternalHistoryEntry) {
|
|
222
|
+
activateNavigationSnapshot();
|
|
223
|
+
pendingHistoryRestoreCommit = () => commitClientNavigationState(navId);
|
|
224
|
+
}
|
|
215
225
|
},
|
|
216
226
|
navId,
|
|
217
227
|
state,
|
|
@@ -223,7 +233,8 @@ function restoreHistoryStateSnapshot(historyState, navId, onApprovedBeforeCommit
|
|
|
223
233
|
clientNavigationCacheGeneration += 1;
|
|
224
234
|
revokeHistoryRestoreNavigationReuse(visitedResponseCache);
|
|
225
235
|
disableNavigationResponsePrefetchCacheReuse();
|
|
226
|
-
commitClientNavigationState(navId, { releaseSnapshot: false });
|
|
236
|
+
if (restoreCopiedExternalHistoryEntry) commitClientNavigationState(navId, { releaseSnapshot: false });
|
|
237
|
+
else flushPendingHistoryRestoreCommit();
|
|
227
238
|
return true;
|
|
228
239
|
}
|
|
229
240
|
function getBrowserRouterState() {
|
|
@@ -1000,6 +1011,10 @@ function registerServerActionCallback() {
|
|
|
1000
1011
|
})).finally(releaseCacheInvalidationGuard);
|
|
1001
1012
|
});
|
|
1002
1013
|
}
|
|
1014
|
+
function ReplayInitialDevServerErrors({ report }) {
|
|
1015
|
+
useEffect(report, [report]);
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1003
1018
|
async function main() {
|
|
1004
1019
|
if (!claimInitialAppRouterBootstrap()) return;
|
|
1005
1020
|
loadNavigationRuntimeRouteManifest();
|
|
@@ -1011,7 +1026,7 @@ async function main() {
|
|
|
1011
1026
|
devErrorOverlay = await import("../client/dev-error-overlay.js");
|
|
1012
1027
|
devErrorOverlay.installDevErrorOverlay();
|
|
1013
1028
|
devErrorOverlay.installViteHmrErrorHandler(import.meta.hot);
|
|
1014
|
-
devErrorOverlay.reportInitialDevServerErrors();
|
|
1029
|
+
if (document.documentElement.id !== "__next_error__") devErrorOverlay.reportInitialDevServerErrors();
|
|
1015
1030
|
}
|
|
1016
1031
|
const initialRscBootstrap = getNavigationRuntime()?.bootstrap.rsc;
|
|
1017
1032
|
const rscStream = await readInitialRscStream();
|
|
@@ -1098,7 +1113,7 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1098
1113
|
for (const style of errorShellStyles) style.remove();
|
|
1099
1114
|
startTransition(() => {
|
|
1100
1115
|
const clientRoot = createRoot(document, createRootOptions);
|
|
1101
|
-
clientRoot.render(children);
|
|
1116
|
+
clientRoot.render(import.meta.env.DEV && devErrorOverlay ? createElement(Fragment, null, children, createElement(ReplayInitialDevServerErrors, { report: devErrorOverlay.reportInitialDevServerErrors })) : children);
|
|
1102
1117
|
window.__VINEXT_RSC_ROOT__ = clientRoot;
|
|
1103
1118
|
});
|
|
1104
1119
|
} else window.__VINEXT_RSC_ROOT__ = hydrateRootInTransition({
|
|
@@ -1389,7 +1404,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1389
1404
|
currentElements: navigationInitiationState.elements,
|
|
1390
1405
|
currentLayoutIds: navigationInitiationState.layoutIds,
|
|
1391
1406
|
currentParams: navigationInitiationState.navigationSnapshot.params,
|
|
1407
|
+
isBfcacheIdentityRetained,
|
|
1392
1408
|
routeManifest,
|
|
1409
|
+
shownElements: getBrowserRouterState().elements,
|
|
1410
|
+
targetElements: optimisticPayload.elements,
|
|
1393
1411
|
targetRouteParams: optimisticPayload.routeParams,
|
|
1394
1412
|
targetUrlParts: optimisticPayload.urlParts,
|
|
1395
1413
|
template: optimisticPayload.template
|
|
@@ -1631,7 +1649,10 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1631
1649
|
discardPendingNavigation: () => {
|
|
1632
1650
|
if (browserNavigationController.discardPendingNavigation(historyController.readCurrentTreeSnapshot())) navigationAbortCoordinator.abortActive();
|
|
1633
1651
|
},
|
|
1634
|
-
flushCommittingNavigationUrl: () =>
|
|
1652
|
+
flushCommittingNavigationUrl: () => {
|
|
1653
|
+
flushPendingHistoryRestoreCommit();
|
|
1654
|
+
browserNavigationController.flushCommittingNavigationUrl();
|
|
1655
|
+
}
|
|
1635
1656
|
});
|
|
1636
1657
|
const handlePopstate = createPopstateRestoreHandler({
|
|
1637
1658
|
getActiveNavigationId: browserNavigationController.getActiveNavigationId.bind(browserNavigationController),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isDangerousScheme, reportBlockedDangerousNavigation } from "../shims/url-safety.js";
|
|
2
|
-
import { resolveHardNavigationTargetFromRscResponse, stripRscCacheBustingSearchParam,
|
|
2
|
+
import { resolveHardNavigationTargetFromRscResponse, stripRscCacheBustingSearchParam, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
|
|
3
3
|
//#region src/server/app-browser-rsc-redirect.ts
|
|
4
4
|
const MAX_RSC_REDIRECT_DEPTH = 10;
|
|
5
5
|
function blockDangerousStreamedRscRedirect(response, streamedRedirectTarget) {
|
|
@@ -11,10 +11,10 @@ function blockDangerousStreamedRscRedirect(response, streamedRedirectTarget) {
|
|
|
11
11
|
function toVisibleAppHref(href, origin) {
|
|
12
12
|
const url = new URL(href, origin);
|
|
13
13
|
stripRscCacheBustingSearchParam(url);
|
|
14
|
-
return `${
|
|
14
|
+
return `${toPathAbsolutePathname(url.pathname)}${url.search}${url.hash}`;
|
|
15
15
|
}
|
|
16
16
|
function toStreamedRedirectVisibleAppHref(url) {
|
|
17
|
-
return `${url.pathname}${url.search}${url.hash}`;
|
|
17
|
+
return `${toPathAbsolutePathname(url.pathname)}${url.search}${url.hash}`;
|
|
18
18
|
}
|
|
19
19
|
function resolveRedirectLifecycleHopFromTarget(options) {
|
|
20
20
|
if (options.targetUrl.origin !== options.origin) return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hasBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
|
|
3
3
|
import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
|
|
4
|
-
import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl } from "./app-rsc-cache-busting.js";
|
|
4
|
+
import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
|
|
5
5
|
import { throwOnServerActionNotFound } from "./server-action-not-found.js";
|
|
6
6
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
7
7
|
import "./app-elements.js";
|
|
@@ -49,7 +49,7 @@ var ServerActionRedirectError = class extends Error {
|
|
|
49
49
|
constructor(target) {
|
|
50
50
|
super("NEXT_REDIRECT");
|
|
51
51
|
const redirectUrl = new URL(target.href, window.location.href);
|
|
52
|
-
const redirectHref = redirectUrl.pathname + redirectUrl.search + redirectUrl.hash;
|
|
52
|
+
const redirectHref = toPathAbsolutePathname(redirectUrl.pathname) + redirectUrl.search + redirectUrl.hash;
|
|
53
53
|
const redirectType = target.type === "push" ? "push" : "replace";
|
|
54
54
|
this.digest = `NEXT_REDIRECT;${redirectType};${redirectHref};${target.status};`;
|
|
55
55
|
}
|
|
@@ -87,11 +87,11 @@ function reduceApprovedVisibleCommitState(state, commit) {
|
|
|
87
87
|
const hmrUniquePreserveElementIds = hmrPreserveElementIds.length > 1 ? [...new Set(hmrPreserveElementIds)] : hmrPreserveElementIds;
|
|
88
88
|
const preserveElementIds = action.operation.lane === "hmr" ? hmrUniquePreserveElementIds : bfcacheCompatiblePreserveElementIds;
|
|
89
89
|
const preserveTemplateIds = action.reuseCurrentBfcacheIds && (action.operation.lane === "navigation" || action.operation.lane === "traverse" || action.operation.lane === "server-action") ? Object.keys(state.elements).filter((id) => Object.hasOwn(action.elements, id) && hasSameServerTemplateSeedIdentity(id, state.navigationSnapshot, action.navigationSnapshot)) : [];
|
|
90
|
-
const mergedPreserveElementIds = preserveTemplateIds.length === 0 ? preserveElementIds : [.../* @__PURE__ */ new Set([...preserveElementIds, ...preserveTemplateIds])];
|
|
91
90
|
const mergedElements = mergeElements(state.elements, action.elements, {
|
|
92
91
|
clearAbsentSlots: action.type === "traverse" || !action.reuseCurrentBfcacheIds,
|
|
93
92
|
preserveAbsentSlots: action.reuseCurrentBfcacheIds && commit.decision.preserveAbsentSlots,
|
|
94
|
-
preserveElementIds
|
|
93
|
+
preserveElementIds,
|
|
94
|
+
preserveElementSeedIds: preserveTemplateIds,
|
|
95
95
|
preservePreviousSlotIds: effectivePreservePreviousSlotIds
|
|
96
96
|
});
|
|
97
97
|
return commitVisibleRouterState(state, {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsBfcacheSegmentIdentities, AppElementsInterception, AppElementsSlotBinding, AppElementsWire, AppOutgoingElements, AppWireElements, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata } from "./app-elements-wire.js";
|
|
2
2
|
//#region src/server/app-elements.d.ts
|
|
3
3
|
export declare const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
|
|
4
|
+
type AppElementsStateKeyRebinder = (stateKey: string) => string;
|
|
5
|
+
export declare function setOptimisticStateKeyRebinder(elements: Record<string, unknown>, rebind: AppElementsStateKeyRebinder): void;
|
|
6
|
+
export declare function readOptimisticStateKeyRebinder(elements: AppElements): AppElementsStateKeyRebinder | null;
|
|
4
7
|
/** Prefix of the element that streams a route's generateMetadata() tags in the body. */
|
|
5
8
|
export declare const APP_STREAMING_METADATA_BODY_ID_PREFIX = "__vinext_streaming_metadata_body:";
|
|
6
9
|
export declare function getMountedSlotIds(elements: AppElements): string[];
|
|
@@ -2,6 +2,19 @@ import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
|
2
2
|
import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata } from "./app-elements-wire.js";
|
|
3
3
|
//#region src/server/app-elements.ts
|
|
4
4
|
const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
|
|
5
|
+
/**
|
|
6
|
+
* An optimistic shell's rebinder from the learned URL's segment state keys to
|
|
7
|
+
* the target's. Only the browser sets it, on the elements it builds a shell
|
|
8
|
+
* from, so it never reaches the wire.
|
|
9
|
+
*/
|
|
10
|
+
const APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY = "__optimisticStateKeyRebinder";
|
|
11
|
+
function setOptimisticStateKeyRebinder(elements, rebind) {
|
|
12
|
+
elements[APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY] = rebind;
|
|
13
|
+
}
|
|
14
|
+
function readOptimisticStateKeyRebinder(elements) {
|
|
15
|
+
const rebind = Reflect.get(elements, APP_OPTIMISTIC_STATE_KEY_REBINDER_KEY);
|
|
16
|
+
return typeof rebind === "function" ? rebind : null;
|
|
17
|
+
}
|
|
5
18
|
/** Prefix of the element that streams a route's generateMetadata() tags in the body. */
|
|
6
19
|
const APP_STREAMING_METADATA_BODY_ID_PREFIX = "__vinext_streaming_metadata_body:";
|
|
7
20
|
function getMountedSlotIds(elements) {
|
|
@@ -18,4 +31,4 @@ function resolveVisitedResponseInterceptionContext(requestInterceptionContext, p
|
|
|
18
31
|
return payloadInterceptionContext ?? requestInterceptionContext;
|
|
19
32
|
}
|
|
20
33
|
//#endregion
|
|
21
|
-
export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext };
|
|
34
|
+
export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_BFCACHE_SEGMENT_IDENTITIES_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_SEGMENTS_KEY, APP_STATIC_SIBLINGS_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, readOptimisticStateKeyRebinder, resolveVisitedResponseInterceptionContext, setOptimisticStateKeyRebinder };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { runOutsideRequestScopes } from "../shims/internal/als-registry.js";
|
|
2
2
|
import { shareIsolatePromise } from "./isolate-shared-promise.js";
|
|
3
|
-
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
4
|
-
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
5
3
|
import { renderAppPageErrorBoundary, renderAppPageHttpAccessFallback } from "./app-page-boundary-render.js";
|
|
4
|
+
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
6
5
|
import { DEFAULT_GLOBAL_NOT_FOUND_MODULE } from "./default-global-not-found-module.js";
|
|
7
6
|
import { DEFAULT_NOT_FOUND_MODULE } from "./default-http-access-fallback-modules.js";
|
|
7
|
+
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
8
8
|
//#region src/server/app-fallback-renderer.ts
|
|
9
9
|
const EMPTY_MW_CTX = {
|
|
10
10
|
headers: null,
|
|
@@ -10,6 +10,8 @@ export type OptimisticRouteTemplate = {
|
|
|
10
10
|
omittedBfcacheSegmentIds: readonly string[];
|
|
11
11
|
omittedLayoutIds: readonly string[];
|
|
12
12
|
pageElementIds: readonly string[];
|
|
13
|
+
/** The navigation params of the URL the template was learned from. */
|
|
14
|
+
params: Readonly<Record<string, string | string[]>>;
|
|
13
15
|
routeId: string;
|
|
14
16
|
};
|
|
15
17
|
type OptimisticNavigationPayload = {
|
|
@@ -48,7 +50,7 @@ export declare function createOptimisticRouteTemplate(options: {
|
|
|
48
50
|
mountedSlotsHeader: string | null;
|
|
49
51
|
routeManifest: BrowserRouteManifest;
|
|
50
52
|
}): OptimisticRouteTemplate | null;
|
|
51
|
-
export declare function createOptimisticRouteElements(template: OptimisticRouteTemplate): AppElements;
|
|
53
|
+
export declare function createOptimisticRouteElements(template: OptimisticRouteTemplate, params?: Readonly<Record<string, string | string[]>>): AppElements;
|
|
52
54
|
/**
|
|
53
55
|
* The optimistic shell reveals the prefetch's streamed metadata, such as its
|
|
54
56
|
* title. React won't hide revealed content again in a transition, so while the
|
|
@@ -77,7 +79,16 @@ export declare function canCommitOptimisticRouteTemplate(options: {
|
|
|
77
79
|
currentElements: AppElements;
|
|
78
80
|
currentLayoutIds: readonly string[];
|
|
79
81
|
currentParams: Readonly<Record<string, string | string[]>>;
|
|
82
|
+
/** Whether a hidden BFCache entry retains a segment identity. */
|
|
83
|
+
isBfcacheIdentityRetained?: (identity: string) => boolean;
|
|
80
84
|
routeManifest: BrowserRouteManifest;
|
|
85
|
+
/**
|
|
86
|
+
* The elements on screen, when a shell earlier in this navigation replaced
|
|
87
|
+
* the current ones. Defaults to `currentElements`.
|
|
88
|
+
*/
|
|
89
|
+
shownElements?: AppElements;
|
|
90
|
+
/** The shell's elements for the target. */
|
|
91
|
+
targetElements?: AppElements;
|
|
81
92
|
targetRouteParams: Readonly<Record<string, string | string[]>>;
|
|
82
93
|
targetUrlParts: readonly string[];
|
|
83
94
|
template: OptimisticRouteTemplate;
|
|
@@ -3,11 +3,11 @@ import { stripBasePath } from "../utils/base-path.js";
|
|
|
3
3
|
import { decodeMatchedParams, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
4
4
|
import { extractRawRoutePatternParams, matchRoutePattern } from "../routing/route-pattern.js";
|
|
5
5
|
import { buildOptimisticRouteTrie, matchOptimisticRouteTrie } from "../routing/optimistic-route-trie.js";
|
|
6
|
-
import { stripRscCacheBustingSearchParam
|
|
7
|
-
import { AppElementsWire } from "./app-elements-wire.js";
|
|
8
|
-
import "./app-elements.js";
|
|
6
|
+
import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
|
|
7
|
+
import { APP_BFCACHE_SEGMENT_IDENTITIES_KEY, AppElementsWire } from "./app-elements-wire.js";
|
|
8
|
+
import { setOptimisticStateKeyRebinder } from "./app-elements.js";
|
|
9
9
|
import { createNestedBfcacheSlotSegmentId, deriveBfcacheSegmentIdentity, isNestedBfcacheSlotSegmentId } from "./bfcache-identity.js";
|
|
10
|
-
import { canonicalizeAppPageParams, resolveAppPagePatternStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
10
|
+
import { APP_PAGE_DEFAULT_SEGMENT_KEY, APP_PAGE_SEGMENT_KEY, canonicalizeAppPageParams, createAppPageSegmentStateKeyRebinder, resolveAppPagePatternStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
11
11
|
import { Suspense, createElement, isValidElement } from "react";
|
|
12
12
|
//#region src/server/app-optimistic-routing.ts
|
|
13
13
|
const routeTrieCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -36,8 +36,7 @@ function hrefToRouteParts(href, basePath) {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
stripRscCacheBustingSearchParam(url);
|
|
39
|
-
const
|
|
40
|
-
const appPathname = stripBasePath(withoutRscSuffix, basePath);
|
|
39
|
+
const appPathname = stripBasePath(url.pathname, basePath);
|
|
41
40
|
const pathname = appPathname === "" ? "/" : appPathname;
|
|
42
41
|
return {
|
|
43
42
|
normalized: splitPathnameForRouteMatch(pathname),
|
|
@@ -115,6 +114,18 @@ function resolveTargetBfcacheSegmentIdentity(options) {
|
|
|
115
114
|
const segmentParams = binding.state === "active" && binding.slotPatternParts !== void 0 && binding.slotPatternParts.length > 0 && !binding.slotParamNames?.every((name) => routeParamNames.has(name)) ? matchRoutePattern(options.targetUrlParts, binding.slotPatternParts) ?? options.targetRouteParams : options.targetRouteParams;
|
|
116
115
|
const ownerLayout = binding.ownerLayoutId ? options.routeManifest.segmentGraph.layouts.get(binding.ownerLayoutId) : void 0;
|
|
117
116
|
const ownerStateKey = ownerLayout ? resolveAppPagePatternStateKey(ownerLayout.patternParts, options.targetRouteParams) : "";
|
|
117
|
+
const deriveLevelIdentity = (segmentKeys) => {
|
|
118
|
+
const identityKey = JSON.stringify(segmentKeys);
|
|
119
|
+
return deriveBfcacheSegmentIdentity({
|
|
120
|
+
activeRouteGraphId: null,
|
|
121
|
+
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, identityKey]) : identityKey,
|
|
122
|
+
interceptionTargetRouteGraphId: null,
|
|
123
|
+
kind: "slot",
|
|
124
|
+
ownerLayoutGraphId: binding.ownerLayoutId,
|
|
125
|
+
slotGraphId: binding.slotId,
|
|
126
|
+
state: binding.state
|
|
127
|
+
});
|
|
128
|
+
};
|
|
118
129
|
const boundSegmentKeys = [];
|
|
119
130
|
let level = 0;
|
|
120
131
|
for (const segment of binding.routeSegments ?? []) {
|
|
@@ -126,17 +137,9 @@ function resolveTargetBfcacheSegmentIdentity(options) {
|
|
|
126
137
|
segment
|
|
127
138
|
}, segmentParams));
|
|
128
139
|
if (createNestedBfcacheSlotSegmentId(binding.slotId, level) !== options.segmentId) continue;
|
|
129
|
-
|
|
130
|
-
return deriveBfcacheSegmentIdentity({
|
|
131
|
-
activeRouteGraphId: null,
|
|
132
|
-
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, identityKey]) : identityKey,
|
|
133
|
-
interceptionTargetRouteGraphId: null,
|
|
134
|
-
kind: "slot",
|
|
135
|
-
ownerLayoutGraphId: binding.ownerLayoutId,
|
|
136
|
-
slotGraphId: binding.slotId,
|
|
137
|
-
state: binding.state
|
|
138
|
-
});
|
|
140
|
+
return deriveLevelIdentity(boundSegmentKeys);
|
|
139
141
|
}
|
|
142
|
+
if (level > 0 && createNestedBfcacheSlotSegmentId(binding.slotId, level + 1) === options.segmentId) return deriveLevelIdentity([...boundSegmentKeys, binding.state === "default" ? APP_PAGE_DEFAULT_SEGMENT_KEY : APP_PAGE_SEGMENT_KEY]);
|
|
140
143
|
if (level === 0 && createNestedBfcacheSlotSegmentId(binding.slotId, 1) === options.segmentId) return deriveBfcacheSegmentIdentity({
|
|
141
144
|
activeRouteGraphId: null,
|
|
142
145
|
boundSegmentKey: ownerStateKey ? JSON.stringify([ownerStateKey, ""]) : "",
|
|
@@ -189,18 +192,31 @@ function createOptimisticRouteTemplate(options) {
|
|
|
189
192
|
if (options.allowLoadingShell && (routeElement === void 0 || routeElement === null)) return null;
|
|
190
193
|
const pageElementIds = getPageElementIds(options.elements, match.route);
|
|
191
194
|
if (pageElementIds.length === 0) return null;
|
|
195
|
+
const urlParts = hrefToRouteParts(options.href, options.basePath);
|
|
196
|
+
if (urlParts === null) return null;
|
|
192
197
|
return {
|
|
193
198
|
elements: options.elements,
|
|
194
199
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
195
200
|
omittedBfcacheSegmentIds: options.elements["__prefetchLoadingShell"] === "LoadingBoundary" ? getOmittedBfcacheSegmentIds(options.elements) : [],
|
|
196
201
|
omittedLayoutIds: options.elements["__prefetchLoadingShell"] === "LoadingBoundary" ? metadata.layoutIds.filter((layoutId) => !Object.hasOwn(options.elements, layoutId)) : [],
|
|
197
202
|
pageElementIds,
|
|
203
|
+
params: resolveOptimisticNavigationParams({
|
|
204
|
+
match,
|
|
205
|
+
rawUrlParts: urlParts.raw,
|
|
206
|
+
routeManifest: options.routeManifest,
|
|
207
|
+
urlParts: urlParts.normalized
|
|
208
|
+
}).navigationParams,
|
|
198
209
|
routeId: match.route.id
|
|
199
210
|
};
|
|
200
211
|
}
|
|
201
|
-
function createOptimisticRouteElements(template) {
|
|
212
|
+
function createOptimisticRouteElements(template, params = template.params) {
|
|
202
213
|
const elements = { ...template.elements };
|
|
203
214
|
for (const pageElementId of template.pageElementIds) elements[pageElementId] = createElement(OptimisticRouteSegment);
|
|
215
|
+
const reify = createAppPageSegmentStateKeyRebinder(template.params, params);
|
|
216
|
+
if (reify === null) return elements;
|
|
217
|
+
setOptimisticStateKeyRebinder(elements, reify);
|
|
218
|
+
const identities = AppElementsWire.readMetadata(template.elements).bfcacheSegmentIdentities;
|
|
219
|
+
if (Object.keys(identities).length > 0) elements[APP_BFCACHE_SEGMENT_IDENTITIES_KEY] = Object.fromEntries(Object.entries(identities).map(([id, identity]) => [id, reify(identity)]));
|
|
204
220
|
return elements;
|
|
205
221
|
}
|
|
206
222
|
function findStreamingMetadataBody(elements) {
|
|
@@ -245,9 +261,14 @@ function keepOptimisticStreamingMetadata(elements, optimisticElements, navigatio
|
|
|
245
261
|
* loading boundary does not re-trigger.
|
|
246
262
|
*/
|
|
247
263
|
function canCommitOptimisticRouteTemplate(options) {
|
|
264
|
+
const currentIdentities = AppElementsWire.readMetadata(options.currentElements).bfcacheSegmentIdentities;
|
|
265
|
+
const { isBfcacheIdentityRetained, targetElements } = options;
|
|
266
|
+
if (isBfcacheIdentityRetained && targetElements) {
|
|
267
|
+
const shownIdentities = new Set(Object.values(options.shownElements ? AppElementsWire.readMetadata(options.shownElements).bfcacheSegmentIdentities : currentIdentities));
|
|
268
|
+
for (const identity of Object.values(AppElementsWire.readMetadata(targetElements).bfcacheSegmentIdentities)) if (!shownIdentities.has(identity) && isBfcacheIdentityRetained(identity)) return false;
|
|
269
|
+
}
|
|
248
270
|
if (options.template.omittedLayoutIds.length === 0 && options.template.omittedBfcacheSegmentIds.length === 0) return true;
|
|
249
271
|
const currentLayoutIds = new Set(options.currentLayoutIds);
|
|
250
|
-
const currentIdentities = AppElementsWire.readMetadata(options.currentElements).bfcacheSegmentIdentities;
|
|
251
272
|
for (const layoutId of options.template.omittedLayoutIds) {
|
|
252
273
|
if (!currentLayoutIds.has(layoutId)) continue;
|
|
253
274
|
if (!Object.hasOwn(options.currentElements, layoutId)) continue;
|
|
@@ -303,7 +324,7 @@ function resolveOptimisticNavigationPayload(options) {
|
|
|
303
324
|
urlParts: urlParts.normalized
|
|
304
325
|
});
|
|
305
326
|
return {
|
|
306
|
-
elements: createOptimisticRouteElements(template),
|
|
327
|
+
elements: createOptimisticRouteElements(template, navigationParams),
|
|
307
328
|
params: navigationParams,
|
|
308
329
|
routeParams,
|
|
309
330
|
template,
|
|
@@ -3,13 +3,12 @@ import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
|
3
3
|
import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
4
|
import { isRenderDynamicLatched, isStaticGenerationAccessError } from "../shims/internal/headers-state.js";
|
|
5
5
|
import { copyLinkHeaderProvenance } from "./app-response-header-provenance.js";
|
|
6
|
-
import { stripRscSuffix } from "./app-rsc-cache-busting.js";
|
|
7
6
|
import { createArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
|
|
8
7
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
9
8
|
import "./app-elements.js";
|
|
10
9
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
11
10
|
import { ErrorBoundary, GlobalErrorBoundary, SerializedErrorBoundary } from "../shims/error-boundary.js";
|
|
12
|
-
import {
|
|
11
|
+
import { rewriteClientHookError } from "../shims/client-hook-error.js";
|
|
13
12
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
14
13
|
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
15
14
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
@@ -21,9 +20,9 @@ import { hasAppPageDynamicMetadata, prepareAppPageHead, resolveActiveParallelRou
|
|
|
21
20
|
import { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryModule, wrapAppPageBoundaryElement } from "./app-page-boundary.js";
|
|
22
21
|
import { createRouteNotFoundHeadPlanOptions, recoverAppPageRouteHead, resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
|
|
23
22
|
import "./app-rsc-route-matching.js";
|
|
24
|
-
import {
|
|
25
|
-
import { resolveSlotParamOverrides } from "./app-page-element-builder.js";
|
|
23
|
+
import { resolveSlotParamOverrides } from "./app-page-navigation-params.js";
|
|
26
24
|
import { createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
25
|
+
import { createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage } from "./app-page-route-wiring.js";
|
|
27
26
|
import { Fragment, Suspense, createElement } from "react";
|
|
28
27
|
//#region src/server/app-page-boundary-render.ts
|
|
29
28
|
async function AppPageBoundaryStreamedMetadata(props) {
|
|
@@ -258,7 +257,7 @@ async function renderAppPageHttpAccessFallback(options) {
|
|
|
258
257
|
if (!boundaryComponent) return null;
|
|
259
258
|
const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;
|
|
260
259
|
const pathname = new URL(options.requestUrl).pathname;
|
|
261
|
-
const routePathname = options.routePathname ??
|
|
260
|
+
const routePathname = options.routePathname ?? stripBasePath(pathname, options.basePath ?? "");
|
|
262
261
|
const headBoundaryModule = options.headBoundaryModule ?? boundaryModule;
|
|
263
262
|
const headLayoutModules = options.headLayoutModules ?? layoutModules;
|
|
264
263
|
const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, headLayoutModules);
|
|
@@ -612,6 +611,7 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
612
611
|
skipLayoutWrapping: errorBoundary.isGlobalError
|
|
613
612
|
});
|
|
614
613
|
};
|
|
614
|
+
const isErrorStatus = errorBoundary.isGlobalError || !options.isRscRequest;
|
|
615
615
|
const renderWith = async (BoundaryComponent) => {
|
|
616
616
|
const response = await renderAppPageBoundaryElementResponse({
|
|
617
617
|
...options,
|
|
@@ -621,9 +621,9 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
621
621
|
navigationParams: matchedParams,
|
|
622
622
|
route: options.route,
|
|
623
623
|
routePattern: options.route?.pattern,
|
|
624
|
-
status:
|
|
624
|
+
status: isErrorStatus ? 500 : 200
|
|
625
625
|
});
|
|
626
|
-
if (
|
|
626
|
+
if (isErrorStatus) applyCdnResponseHeaders(response.headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
627
627
|
return response;
|
|
628
628
|
};
|
|
629
629
|
try {
|
|
@@ -636,10 +636,5 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
636
636
|
throw renderError;
|
|
637
637
|
}
|
|
638
638
|
}
|
|
639
|
-
const _clientHookPattern = /\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\b.*is not a function/;
|
|
640
|
-
function rewriteClientHookError(error) {
|
|
641
|
-
const match = error.message.match(_clientHookPattern);
|
|
642
|
-
if (match) error.message = buildClientHookErrorMessage(`${match[1]}()`);
|
|
643
|
-
}
|
|
644
639
|
//#endregion
|
|
645
640
|
export { renderAppPageErrorBoundary, renderAppPageHttpAccessFallback };
|
|
@@ -4,8 +4,8 @@ import { _consumeRequestScopedCacheLife } from "../shims/cache-request-state.js"
|
|
|
4
4
|
import { getCollectedFetchTags } from "../shims/fetch-cache.js";
|
|
5
5
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
6
6
|
import { buildAppPageFontLinkHeader, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
|
|
7
|
-
import { recordAppPageRenderError, traceAppPageRender } from "./app-page-tracing.js";
|
|
8
7
|
import { buildAppPageLinkHeader, createAppPageSsrErrorHandler, isAppSsrRenderResult } from "./app-page-stream.js";
|
|
8
|
+
import { recordAppPageRenderError, traceAppPageRender } from "./app-page-tracing.js";
|
|
9
9
|
import { consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
|
|
10
10
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
11
11
|
//#region src/server/app-page-cache-render.ts
|
|
@@ -15,7 +15,7 @@ import { FetchCacheMode } from "../shims/fetch-cache-state.js";
|
|
|
15
15
|
import "../shims/fetch-cache.js";
|
|
16
16
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
17
17
|
import { WarmPprFallbackShellCachesOptions } from "./app-ppr-fallback-shell-render.js";
|
|
18
|
-
import { ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
|
|
18
|
+
import { AppPageInterceptState, ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
|
|
19
19
|
import { ReactNode } from "react";
|
|
20
20
|
import { ReactFormState } from "react-dom/client";
|
|
21
21
|
//#region src/server/app-page-dispatch.d.ts
|
|
@@ -96,10 +96,17 @@ type AppPageModule = {
|
|
|
96
96
|
revalidate?: unknown;
|
|
97
97
|
};
|
|
98
98
|
type AppPageDispatchSlot = {
|
|
99
|
+
configLayouts?: readonly (AppPageModule | null | undefined)[] | null;
|
|
100
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
99
101
|
default?: AppPageModule | null;
|
|
102
|
+
layout?: AppPageModule | null;
|
|
103
|
+
layoutIndex?: number;
|
|
100
104
|
loading?: AppPageModule | null;
|
|
101
105
|
loadings?: readonly (AppPageModule | null | undefined)[] | null;
|
|
106
|
+
name?: string;
|
|
107
|
+
ownerTreePosition?: number | null;
|
|
102
108
|
page?: AppPageModule | null;
|
|
109
|
+
routeSegments?: readonly string[] | null;
|
|
103
110
|
slotPatternParts?: readonly string[] | null;
|
|
104
111
|
slotParamNames?: readonly string[] | null;
|
|
105
112
|
};
|
|
@@ -184,6 +191,8 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
184
191
|
ensureRouteLoaded?: (route: TRoute) => unknown;
|
|
185
192
|
fetchCache?: FetchCacheMode | null;
|
|
186
193
|
findIntercept: (pathname: string) => AppPageDispatchIntercept | null;
|
|
194
|
+
/** This request's intercept, which dispatch resolves once before rendering. */
|
|
195
|
+
interceptState?: AppPageInterceptState<TRoute, unknown>;
|
|
187
196
|
formState?: ReactFormState | null;
|
|
188
197
|
actionError?: unknown;
|
|
189
198
|
actionFailed?: boolean;
|
|
@@ -200,7 +209,6 @@ export type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
|
|
|
200
209
|
hasGenerateStaticParams: boolean;
|
|
201
210
|
/** Whether any segment of the route exports `generateStaticParams`. */
|
|
202
211
|
hasAnyGenerateStaticParams: boolean;
|
|
203
|
-
hasCustomGlobalError?: boolean;
|
|
204
212
|
hasPageDefaultExport: boolean;
|
|
205
213
|
hasPageModule: boolean;
|
|
206
214
|
handlerStart: number;
|