vinext 0.1.0 → 0.1.1
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/dist/build/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +27 -1
- package/dist/build/client-build-config.js +58 -1
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +8 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/config/config-matchers.d.ts +20 -1
- package/dist/config/config-matchers.js +35 -1
- package/dist/config/next-config.d.ts +16 -3
- package/dist/config/next-config.js +30 -2
- package/dist/deploy.js +40 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +54 -4
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-server-entry.js +9 -1
- package/dist/index.js +162 -217
- 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/routing/app-route-graph.d.ts +12 -1
- package/dist/routing/app-route-graph.js +137 -5
- 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 +84 -39
- 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 +11 -1
- package/dist/server/app-browser-navigation-controller.js +77 -1
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- package/dist/server/app-browser-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +6 -3
- package/dist/server/app-browser-visible-commit.js +9 -7
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-page-boundary-render.js +41 -19
- package/dist/server/app-page-dispatch.d.ts +6 -0
- package/dist/server/app-page-dispatch.js +3 -1
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +22 -10
- package/dist/server/app-page-render.d.ts +6 -0
- package/dist/server/app-page-render.js +5 -3
- package/dist/server/app-page-request.d.ts +8 -6
- package/dist/server/app-page-request.js +12 -9
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.js +2 -1
- package/dist/server/app-page-stream.d.ts +37 -2
- package/dist/server/app-page-stream.js +36 -3
- 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-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +3 -2
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +4 -3
- 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 +11 -1
- package/dist/server/app-server-action-execution.js +68 -10
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +17 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +54 -31
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- package/dist/server/navigation-planner.js +5 -3
- package/dist/server/navigation-trace.d.ts +1 -1
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +4 -0
- package/dist/server/pages-page-data.d.ts +10 -7
- package/dist/server/pages-page-data.js +4 -2
- package/dist/server/pages-page-handler.d.ts +9 -2
- package/dist/server/pages-page-handler.js +29 -16
- package/dist/server/pages-page-response.d.ts +11 -2
- package/dist/server/pages-page-response.js +8 -1
- 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 +99 -0
- package/dist/server/pages-request-pipeline.js +209 -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 +6 -2
- package/dist/server/prod-server.js +101 -217
- 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 +31 -1
- package/dist/shims/error-boundary.d.ts +21 -11
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/fetch-cache.d.ts +14 -1
- package/dist/shims/fetch-cache.js +18 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- 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/navigation.d.ts +2 -2
- package/dist/shims/navigation.js +63 -7
- 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 +128 -21
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +30 -5
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/package.json +5 -1
|
@@ -9,8 +9,8 @@ import { installWindowNext } from "../client/window-next.js";
|
|
|
9
9
|
import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
|
|
10
10
|
import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
|
|
11
11
|
import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
|
|
12
|
-
import { resolveManifestNavigationInterceptionContext } from "./app-browser-interception-context.js";
|
|
13
|
-
import {
|
|
12
|
+
import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
|
|
13
|
+
import { RestorableClientStateController, createHistoryStateWithNavigationMetadata, readHistoryStateBfcacheIds, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
|
|
14
14
|
import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, resolveHardNavigationTargetFromRscResponse, resolveRscCompatibilityNavigationDecision } from "./app-rsc-cache-busting.js";
|
|
15
15
|
import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
|
|
16
16
|
import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
@@ -23,10 +23,10 @@ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiati
|
|
|
23
23
|
import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
|
|
24
24
|
import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
|
|
25
25
|
import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
|
|
26
|
-
import { clearHardNavigationLoopGuard, createAppBrowserNavigationController } from "./app-browser-navigation-controller.js";
|
|
26
|
+
import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, createSnapshotPathAndSearch } from "./app-browser-navigation-controller.js";
|
|
27
27
|
import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition } from "./app-browser-hydration.js";
|
|
28
28
|
import { createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
|
|
29
|
-
import { createPopstateRestoreHandler } from "./app-browser-popstate.js";
|
|
29
|
+
import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition } from "./app-browser-popstate.js";
|
|
30
30
|
import { createOnUncaughtError } from "./app-browser-error.js";
|
|
31
31
|
import { dismissOverlay } from "./dev-error-overlay-store.js";
|
|
32
32
|
import { devOnCaughtError, devOnUncaughtError, installDevErrorOverlay, installViteHmrErrorHandler, reportInitialDevServerErrors } from "./dev-error-overlay.js";
|
|
@@ -35,6 +35,7 @@ import { resolveRscRedirectLifecycleHop } from "./app-browser-rsc-redirect.js";
|
|
|
35
35
|
import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
|
|
36
36
|
import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
|
|
37
37
|
import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
38
|
+
import { flushSync } from "react-dom";
|
|
38
39
|
import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
|
|
39
40
|
import { hydrateRoot } from "react-dom/client";
|
|
40
41
|
//#region src/server/app-browser-entry.ts
|
|
@@ -58,6 +59,7 @@ function getBrowserRouteManifest() {
|
|
|
58
59
|
return getNavigationRuntime()?.bootstrap.routeManifest ?? null;
|
|
59
60
|
}
|
|
60
61
|
const browserNavigationController = createAppBrowserNavigationController({
|
|
62
|
+
basePath: __basePath,
|
|
61
63
|
getRouteManifest: getBrowserRouteManifest,
|
|
62
64
|
syncHistoryStatePreviousNextUrl: syncCurrentHistoryStatePreviousNextUrl
|
|
63
65
|
});
|
|
@@ -96,26 +98,18 @@ const mpaNavigationScheduler = new AppBrowserMpaNavigationScheduler();
|
|
|
96
98
|
const unresolvedMpaNavigation = new Promise(() => {});
|
|
97
99
|
const RSC_HMR_SETTLE_DELAY_MS = 150;
|
|
98
100
|
let latestRscHmrUpdateId = 0;
|
|
99
|
-
const initialHistoryBfcacheVersion = readHistoryStateBfcacheVersion(window.history.state);
|
|
100
|
-
let currentBfcacheVersion = initialHistoryBfcacheVersion === null ? 0 : initialHistoryBfcacheVersion + 1;
|
|
101
101
|
let currentHistoryTraversalIndex = readHistoryStateTraversalIndex(window.history.state) ?? 0;
|
|
102
102
|
let nextHistoryTraversalIndex = currentHistoryTraversalIndex;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
let synchronousPopstateScrollRestoreNavigationId = null;
|
|
104
|
+
const restorableClientState = new RestorableClientStateController({
|
|
105
|
+
initialHistoryState: window.history.state,
|
|
106
|
+
maxHistoryStateSnapshots: 50
|
|
107
|
+
});
|
|
106
108
|
function waitForRscHmrSettle(delayMs = RSC_HMR_SETTLE_DELAY_MS) {
|
|
107
109
|
return new Promise((resolve) => {
|
|
108
110
|
window.setTimeout(resolve, delayMs);
|
|
109
111
|
});
|
|
110
112
|
}
|
|
111
|
-
function readCurrentBfcacheVersionHistoryIds(state) {
|
|
112
|
-
const ids = readHistoryStateBfcacheIds(state);
|
|
113
|
-
if (ids === null) return null;
|
|
114
|
-
return isCurrentBfcacheVersion(state) ? ids : null;
|
|
115
|
-
}
|
|
116
|
-
function invalidateRestorableBfcacheIds() {
|
|
117
|
-
currentBfcacheVersion += 1;
|
|
118
|
-
}
|
|
119
113
|
function allocateNavigationHistoryTraversalIndex(historyUpdateMode) {
|
|
120
114
|
switch (historyUpdateMode) {
|
|
121
115
|
case "push": return nextHistoryTraversalIndex + 1;
|
|
@@ -131,10 +125,10 @@ function commitHistoryTraversalIndex(index) {
|
|
|
131
125
|
function commitHashOnlyNavigation(href, historyUpdateMode, scroll) {
|
|
132
126
|
const navigationHistoryIndex = allocateNavigationHistoryTraversalIndex(historyUpdateMode);
|
|
133
127
|
const previousNextUrl = hasBrowserRouterState() ? getBrowserRouterState().previousNextUrl : readHistoryStatePreviousNextUrl(window.history.state);
|
|
134
|
-
const bfcacheIds = hasBrowserRouterState() ? getBrowserRouterState().bfcacheIds : readCurrentBfcacheVersionHistoryIds(window.history.state);
|
|
128
|
+
const bfcacheIds = hasBrowserRouterState() ? getBrowserRouterState().bfcacheIds : restorableClientState.readCurrentBfcacheVersionHistoryIds(window.history.state);
|
|
135
129
|
const historyState = createHistoryStateWithNavigationMetadata(createHashOnlyNavigationBaseHistoryState(historyUpdateMode, scroll), {
|
|
136
130
|
bfcacheIds,
|
|
137
|
-
bfcacheVersion: bfcacheIds === null ? void 0 : currentBfcacheVersion,
|
|
131
|
+
bfcacheVersion: bfcacheIds === null ? void 0 : restorableClientState.currentBfcacheVersion,
|
|
138
132
|
previousNextUrl,
|
|
139
133
|
traversalIndex: navigationHistoryIndex
|
|
140
134
|
});
|
|
@@ -158,6 +152,26 @@ function stripVinextScrollState(state) {
|
|
|
158
152
|
function commitTraversalIndexFromHistoryState(historyState) {
|
|
159
153
|
commitHistoryTraversalIndex(readHistoryStateTraversalIndex(historyState));
|
|
160
154
|
}
|
|
155
|
+
function restoreHistoryStateSnapshot(historyState) {
|
|
156
|
+
const decision = restorableClientState.resolveHistoryStateSnapshotRestore(historyState);
|
|
157
|
+
if (decision.kind === "skip") return false;
|
|
158
|
+
const navId = browserNavigationController.getActiveNavigationId();
|
|
159
|
+
let restored = false;
|
|
160
|
+
flushSync(() => {
|
|
161
|
+
restored = browserNavigationController.restoreHistorySnapshotVisibleState({
|
|
162
|
+
beforeCommit: () => {
|
|
163
|
+
commitHistoryTraversalIndex(decision.targetHistoryIndex);
|
|
164
|
+
stageClientParams(decision.state.navigationSnapshot.params);
|
|
165
|
+
},
|
|
166
|
+
navId,
|
|
167
|
+
state: decision.state,
|
|
168
|
+
targetHref: window.location.href
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
if (!restored) return false;
|
|
172
|
+
commitClientNavigationState();
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
161
175
|
function getBrowserRouterState() {
|
|
162
176
|
return browserNavigationController.getBrowserRouterState();
|
|
163
177
|
}
|
|
@@ -190,7 +204,7 @@ function clearPrefetchState() {
|
|
|
190
204
|
function clearClientNavigationCaches() {
|
|
191
205
|
clearVisitedResponseCache();
|
|
192
206
|
clearPrefetchState();
|
|
193
|
-
|
|
207
|
+
restorableClientState.invalidateClientState();
|
|
194
208
|
}
|
|
195
209
|
function isSettledPrefetchCacheEntry(entry) {
|
|
196
210
|
return entry.outcome === "cache-seeded" && entry.pending === void 0 && entry.snapshot !== void 0;
|
|
@@ -267,18 +281,18 @@ function areBfcacheIdMapsEqual(a, b) {
|
|
|
267
281
|
return aEntries.every(([key, value]) => b[key] === value);
|
|
268
282
|
}
|
|
269
283
|
function isHistoryStateNavigationMetadataInSync(state, previousNextUrl, bfcacheIds) {
|
|
270
|
-
return readHistoryStatePreviousNextUrl(state) === previousNextUrl && (bfcacheIds === void 0 || areBfcacheIdMapsEqual(readHistoryStateBfcacheIds(state), bfcacheIds) && isCurrentBfcacheVersion(state));
|
|
284
|
+
return readHistoryStatePreviousNextUrl(state) === previousNextUrl && (bfcacheIds === void 0 || areBfcacheIdMapsEqual(readHistoryStateBfcacheIds(state), bfcacheIds) && restorableClientState.isCurrentBfcacheVersion(state));
|
|
271
285
|
}
|
|
272
286
|
function syncCurrentHistoryStatePreviousNextUrl(previousNextUrl, bfcacheIds) {
|
|
273
287
|
if (isHistoryStateNavigationMetadataInSync(window.history.state, previousNextUrl, bfcacheIds)) return;
|
|
274
288
|
const nextHistoryState = createHistoryStateWithNavigationMetadata(window.history.state, {
|
|
275
289
|
bfcacheIds,
|
|
276
|
-
bfcacheVersion: bfcacheIds === void 0 ? void 0 : currentBfcacheVersion,
|
|
290
|
+
bfcacheVersion: bfcacheIds === void 0 ? void 0 : restorableClientState.currentBfcacheVersion,
|
|
277
291
|
previousNextUrl
|
|
278
292
|
});
|
|
279
293
|
replaceHistoryStateWithoutNotify(nextHistoryState, "", window.location.href);
|
|
280
294
|
if (isHistoryStateNavigationMetadataInSync(window.history.state, previousNextUrl, bfcacheIds)) return;
|
|
281
|
-
|
|
295
|
+
replaceHistoryStateWithoutNotify(nextHistoryState, "", window.location.href);
|
|
282
296
|
}
|
|
283
297
|
function createActionInitiationSnapshot() {
|
|
284
298
|
const routerState = getBrowserRouterState();
|
|
@@ -300,7 +314,7 @@ function createNavigationCommitEffect(options) {
|
|
|
300
314
|
const navigationHistoryIndex = targetHistoryIndex !== void 0 ? targetHistoryIndex : allocateNavigationHistoryTraversalIndex(historyUpdateMode);
|
|
301
315
|
const historyState = createHistoryStateWithNavigationMetadata(preserveExistingState ? window.history.state : null, {
|
|
302
316
|
bfcacheIds,
|
|
303
|
-
bfcacheVersion: currentBfcacheVersion,
|
|
317
|
+
bfcacheVersion: restorableClientState.currentBfcacheVersion,
|
|
304
318
|
previousNextUrl,
|
|
305
319
|
traversalIndex: navigationHistoryIndex
|
|
306
320
|
});
|
|
@@ -325,7 +339,7 @@ function createNavigationCommitEffect(options) {
|
|
|
325
339
|
commitClientNavigationState(navId);
|
|
326
340
|
};
|
|
327
341
|
}
|
|
328
|
-
async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, payloadOrigin, actionType = "navigate", operationLane = "navigation", traversalIntent = null, scrollIntent = null, restoredBfcacheIds = null) {
|
|
342
|
+
async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, payloadOrigin, actionType = "navigate", operationLane = "navigation", traversalIntent = null, scrollIntent = null, restoredBfcacheIds = null, reuseCurrentBfcacheIds = true) {
|
|
329
343
|
syncServerActionHttpFallbackHead(null);
|
|
330
344
|
try {
|
|
331
345
|
return await browserNavigationController.renderNavigationPayload({
|
|
@@ -344,6 +358,7 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
|
|
|
344
358
|
previousNextUrl,
|
|
345
359
|
scrollIntent,
|
|
346
360
|
restoredBfcacheIds,
|
|
361
|
+
reuseCurrentBfcacheIds,
|
|
347
362
|
targetHistoryIndex: traversalIntent === null ? void 0 : traversalIntent.targetHistoryIndex,
|
|
348
363
|
targetHref,
|
|
349
364
|
navId
|
|
@@ -476,6 +491,16 @@ function getRequestState(navigationKind, targetPathname, previousNextUrlOverride
|
|
|
476
491
|
interceptionContext: manifestInterceptionContext,
|
|
477
492
|
previousNextUrl: window.location.pathname + window.location.search
|
|
478
493
|
};
|
|
494
|
+
const middlewareRewriteInterceptionContext = resolveMiddlewareRewriteNavigationInterceptionContext({
|
|
495
|
+
basePath: __basePath,
|
|
496
|
+
currentPathname: window.location.pathname,
|
|
497
|
+
routeManifest: getBrowserRouteManifest(),
|
|
498
|
+
targetPathname
|
|
499
|
+
});
|
|
500
|
+
if (middlewareRewriteInterceptionContext !== null) return {
|
|
501
|
+
interceptionContext: middlewareRewriteInterceptionContext,
|
|
502
|
+
previousNextUrl: window.location.pathname + window.location.search
|
|
503
|
+
};
|
|
479
504
|
return {
|
|
480
505
|
interceptionContext: null,
|
|
481
506
|
previousNextUrl: null
|
|
@@ -584,6 +609,12 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
|
|
|
584
609
|
setMountedSlotsHeader(null);
|
|
585
610
|
};
|
|
586
611
|
}, [setTreeStateValue]);
|
|
612
|
+
useLayoutEffect(() => {
|
|
613
|
+
restorableClientState.rememberHistoryStateSnapshot({
|
|
614
|
+
historyIndex: currentHistoryTraversalIndex,
|
|
615
|
+
state: treeState
|
|
616
|
+
});
|
|
617
|
+
}, [treeState]);
|
|
587
618
|
useLayoutEffect(() => {
|
|
588
619
|
setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
|
|
589
620
|
removeStylesheetLinksCoveredByInlineCss();
|
|
@@ -593,7 +624,7 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
|
|
|
593
624
|
if (treeState.renderId !== 0) return;
|
|
594
625
|
replaceHistoryStateWithoutNotify(createHistoryStateWithNavigationMetadata(window.history.state, {
|
|
595
626
|
bfcacheIds: treeState.bfcacheIds,
|
|
596
|
-
bfcacheVersion: currentBfcacheVersion,
|
|
627
|
+
bfcacheVersion: restorableClientState.currentBfcacheVersion,
|
|
597
628
|
previousNextUrl: treeState.previousNextUrl,
|
|
598
629
|
traversalIndex: currentHistoryTraversalIndex
|
|
599
630
|
}), "", window.location.href);
|
|
@@ -634,16 +665,16 @@ function restorePopstateScrollPosition(state, options) {
|
|
|
634
665
|
return;
|
|
635
666
|
}
|
|
636
667
|
const y = Number(state.__vinext_scrollY);
|
|
637
|
-
retryScrollTo("__vinext_scrollX" in state ? Number(state.__vinext_scrollX) : 0, y, {
|
|
668
|
+
retryScrollTo("__vinext_scrollX" in state ? Number(state.__vinext_scrollX) : 0, y, {
|
|
669
|
+
minFrames: 1,
|
|
670
|
+
shouldContinue
|
|
671
|
+
});
|
|
638
672
|
}
|
|
639
673
|
function isSameAppRoutePopstateTarget(href) {
|
|
640
674
|
if (!hasBrowserRouterState()) return false;
|
|
641
675
|
const target = new URL(href, window.location.origin);
|
|
642
676
|
const routerState = getBrowserRouterState();
|
|
643
|
-
|
|
644
|
-
const targetSearch = new URLSearchParams(target.search).toString();
|
|
645
|
-
const currentSearch = routerState.navigationSnapshot.searchParams.toString();
|
|
646
|
-
return targetPathname === routerState.navigationSnapshot.pathname && targetSearch === currentSearch;
|
|
677
|
+
return createBasePathStrippedPathAndSearch(target, __basePath) === createSnapshotPathAndSearch(routerState.navigationSnapshot);
|
|
647
678
|
}
|
|
648
679
|
let isPageUnloading = false;
|
|
649
680
|
const RSC_RELOAD_KEY = "__vinext_rsc_initial_reload__";
|
|
@@ -724,7 +755,7 @@ function applyRuntimeRscBootstrap(rsc) {
|
|
|
724
755
|
if (rsc.nav) restoreHydrationNavigationContext(rsc.nav.pathname, rsc.nav.searchParams, params);
|
|
725
756
|
}
|
|
726
757
|
function registerServerActionCallback() {
|
|
727
|
-
|
|
758
|
+
const serverActionCallback = async (id, args) => {
|
|
728
759
|
syncServerActionHttpFallbackHead(null);
|
|
729
760
|
const temporaryReferences = createTemporaryReferenceSet();
|
|
730
761
|
const actionInitiation = createActionInitiationSnapshot();
|
|
@@ -766,6 +797,7 @@ function registerServerActionCallback() {
|
|
|
766
797
|
return;
|
|
767
798
|
}
|
|
768
799
|
const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
|
|
800
|
+
if (revalidation !== "none") clearClientNavigationCaches();
|
|
769
801
|
const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
|
|
770
802
|
if (invalidResponseError) throw invalidResponseError;
|
|
771
803
|
if (actionRedirectTarget && !shouldCheckRscCompatibilityForServerActionResponse(fetchResponse)) {
|
|
@@ -778,7 +810,7 @@ function registerServerActionCallback() {
|
|
|
778
810
|
statusText: "OK"
|
|
779
811
|
}) : fetchResponse;
|
|
780
812
|
const result = await createFromFetch(Promise.resolve(flightResponse), { temporaryReferences });
|
|
781
|
-
if (shouldClearClientNavigationCachesForServerActionResult(result, revalidation)) clearClientNavigationCaches();
|
|
813
|
+
if (revalidation === "none" && shouldClearClientNavigationCachesForServerActionResult(result, revalidation)) clearClientNavigationCaches();
|
|
782
814
|
if (actionRedirectTarget) {
|
|
783
815
|
if (isServerActionResult(result) && result.root !== void 0) {
|
|
784
816
|
const decoded = AppElementsWire.decode(result.root);
|
|
@@ -809,6 +841,10 @@ function registerServerActionCallback() {
|
|
|
809
841
|
return;
|
|
810
842
|
}
|
|
811
843
|
return commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result)), actionInitiation, void 0, revalidation);
|
|
844
|
+
};
|
|
845
|
+
setServerCallback((id, args) => {
|
|
846
|
+
const releaseCacheInvalidationGuard = restorableClientState.beginCacheInvalidationGuard();
|
|
847
|
+
return Promise.resolve().then(() => serverActionCallback(id, args)).finally(releaseCacheInvalidationGuard);
|
|
812
848
|
});
|
|
813
849
|
}
|
|
814
850
|
async function main() {
|
|
@@ -869,7 +905,8 @@ function bootstrapHydration(rscStream) {
|
|
|
869
905
|
consumeAppRouterScrollIntent(scrollIntent ?? null);
|
|
870
906
|
return browserNavigationController.performHardNavigation(targetHref);
|
|
871
907
|
};
|
|
872
|
-
let restoredBfcacheIds = navigationKind === "traverse" ? readCurrentBfcacheVersionHistoryIds(activeTraversalIntent?.historyState ?? window.history.state) : null;
|
|
908
|
+
let restoredBfcacheIds = navigationKind === "traverse" ? restorableClientState.readCurrentBfcacheVersionHistoryIds(activeTraversalIntent?.historyState ?? window.history.state) : null;
|
|
909
|
+
const reuseCurrentBfcacheIds = navigationKind !== "traverse" || !restorableClientState.isCacheInvalidationGuarded() && restorableClientState.isCurrentBfcacheVersion(activeTraversalIntent?.historyState ?? window.history.state);
|
|
873
910
|
try {
|
|
874
911
|
const shouldUsePendingRouterState = programmaticTransition;
|
|
875
912
|
if (shouldUsePendingRouterState && hasBrowserRouterState()) pendingRouterState = beginPendingBrowserRouterState();
|
|
@@ -934,7 +971,7 @@ function bootstrapHydration(rscStream) {
|
|
|
934
971
|
const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, cachedParams);
|
|
935
972
|
const cachedPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
|
|
936
973
|
if (!browserNavigationController.isCurrentNavigation(navId)) return;
|
|
937
|
-
if (await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds) === "no-commit") {
|
|
974
|
+
if (await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds, reuseCurrentBfcacheIds) === "no-commit") {
|
|
938
975
|
deleteVisitedResponse(rscUrl, requestInterceptionContext);
|
|
939
976
|
continue;
|
|
940
977
|
}
|
|
@@ -972,7 +1009,7 @@ function bootstrapHydration(rscStream) {
|
|
|
972
1009
|
if (optimisticPayload !== null) {
|
|
973
1010
|
detachedNavigationCommits = true;
|
|
974
1011
|
const optimisticNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, optimisticPayload.params);
|
|
975
|
-
renderNavigationPayload(Promise.resolve(optimisticPayload.elements), optimisticNavigationSnapshot, currentHref, navId, currentHistoryMode, optimisticPayload.params, requestPreviousNextUrl, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds).catch((error) => {
|
|
1012
|
+
renderNavigationPayload(Promise.resolve(optimisticPayload.elements), optimisticNavigationSnapshot, currentHref, navId, currentHistoryMode, optimisticPayload.params, requestPreviousNextUrl, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds, reuseCurrentBfcacheIds).catch((error) => {
|
|
976
1013
|
if (browserNavigationController.isCurrentNavigation(navId)) console.error("[vinext] Optimistic RSC navigation error:", error);
|
|
977
1014
|
});
|
|
978
1015
|
}
|
|
@@ -1059,7 +1096,7 @@ function bootstrapHydration(rscStream) {
|
|
|
1059
1096
|
if (!browserNavigationController.isCurrentNavigation(navId)) return;
|
|
1060
1097
|
const rscPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(reactResponse)));
|
|
1061
1098
|
if (!browserNavigationController.isCurrentNavigation(navId)) return;
|
|
1062
|
-
if (await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds) !== "committed") return;
|
|
1099
|
+
if (await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, detachedNavigationCommits ? null : pendingRouterState, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, toActionType(navigationKind), toOperationLane(navigationKind), activeTraversalIntent, scrollIntent, restoredBfcacheIds, reuseCurrentBfcacheIds) !== "committed") return;
|
|
1063
1100
|
if (!browserNavigationController.isCurrentNavigation(navId)) return;
|
|
1064
1101
|
try {
|
|
1065
1102
|
const renderedElements = await rscPayload;
|
|
@@ -1087,7 +1124,6 @@ function bootstrapHydration(rscStream) {
|
|
|
1087
1124
|
}
|
|
1088
1125
|
}
|
|
1089
1126
|
});
|
|
1090
|
-
if ("scrollRestoration" in history) history.scrollRestoration = "manual";
|
|
1091
1127
|
const handlePopstate = createPopstateRestoreHandler({
|
|
1092
1128
|
getActiveNavigationId: browserNavigationController.getActiveNavigationId.bind(browserNavigationController),
|
|
1093
1129
|
getPendingNavigation: () => window.__VINEXT_RSC_PENDING__,
|
|
@@ -1099,7 +1135,8 @@ function bootstrapHydration(rscStream) {
|
|
|
1099
1135
|
restorePopstateScrollPosition,
|
|
1100
1136
|
setPendingNavigation: (pendingNavigation) => {
|
|
1101
1137
|
window.__VINEXT_RSC_PENDING__ = pendingNavigation;
|
|
1102
|
-
}
|
|
1138
|
+
},
|
|
1139
|
+
shouldSkipScrollRestore: (navId) => synchronousPopstateScrollRestoreNavigationId === navId
|
|
1103
1140
|
});
|
|
1104
1141
|
window.addEventListener("popstate", (event) => {
|
|
1105
1142
|
const href = window.location.href;
|
|
@@ -1110,6 +1147,14 @@ function bootstrapHydration(rscStream) {
|
|
|
1110
1147
|
return;
|
|
1111
1148
|
}
|
|
1112
1149
|
handlePopstate(event);
|
|
1150
|
+
if (restoreHistoryStateSnapshot(event.state)) restoreSynchronousPopstateScrollPosition({
|
|
1151
|
+
getActiveNavigationId: () => browserNavigationController.getActiveNavigationId(),
|
|
1152
|
+
isCurrentNavigation: (navId) => browserNavigationController.isCurrentNavigation(navId),
|
|
1153
|
+
markScrollRestoreConsumed: (navId) => {
|
|
1154
|
+
synchronousPopstateScrollRestoreNavigationId = navId;
|
|
1155
|
+
},
|
|
1156
|
+
restorePopstateScrollPosition
|
|
1157
|
+
}, event.state);
|
|
1113
1158
|
});
|
|
1114
1159
|
if (import.meta.hot) {
|
|
1115
1160
|
const applyRscHmrUpdate = async (updateId) => {
|
|
@@ -19,5 +19,6 @@ type ResolveManifestNavigationInterceptionContextOptions = {
|
|
|
19
19
|
* is owned by the deterministic route graph builder.
|
|
20
20
|
*/
|
|
21
21
|
declare function resolveManifestNavigationInterceptionContext(options: ResolveManifestNavigationInterceptionContextOptions): string | null;
|
|
22
|
+
declare function resolveMiddlewareRewriteNavigationInterceptionContext(options: ResolveManifestNavigationInterceptionContextOptions): string | null;
|
|
22
23
|
//#endregion
|
|
23
|
-
export { resolveManifestNavigationInterceptionContext };
|
|
24
|
+
export { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
2
|
import { stripBasePath } from "../utils/base-path.js";
|
|
3
|
-
import { matchRoutePattern, matchRoutePatternPrefix } from "../routing/route-pattern.js";
|
|
3
|
+
import { matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternWithOptionalDynamicSegments } from "../routing/route-pattern.js";
|
|
4
4
|
//#region src/server/app-browser-interception-context.ts
|
|
5
5
|
/**
|
|
6
6
|
* Resolve the first-hop interception context from declared route topology.
|
|
@@ -26,5 +26,18 @@ function resolveManifestNavigationInterceptionContext(options) {
|
|
|
26
26
|
}
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
|
+
function resolveMiddlewareRewriteNavigationInterceptionContext(options) {
|
|
30
|
+
if (options.routeManifest === null) return null;
|
|
31
|
+
const currentPathname = stripBasePath(options.currentPathname, options.basePath);
|
|
32
|
+
const targetPathname = stripBasePath(options.targetPathname, options.basePath);
|
|
33
|
+
const sourceParts = splitPathnameForRouteMatch(currentPathname);
|
|
34
|
+
const targetParts = splitPathnameForRouteMatch(targetPathname);
|
|
35
|
+
for (const interception of options.routeManifest.segmentGraph.interceptions.values()) {
|
|
36
|
+
if (!matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) continue;
|
|
37
|
+
if (!matchRoutePatternWithOptionalDynamicSegments(targetParts, interception.targetPatternParts)) continue;
|
|
38
|
+
return currentPathname;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
29
42
|
//#endregion
|
|
30
|
-
export { resolveManifestNavigationInterceptionContext };
|
|
43
|
+
export { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext };
|
|
@@ -35,6 +35,7 @@ type SameUrlServerActionLifecycleOptions = {
|
|
|
35
35
|
targetHref?: string;
|
|
36
36
|
};
|
|
37
37
|
type BrowserNavigationControllerDeps = {
|
|
38
|
+
basePath?: string;
|
|
38
39
|
commitClientNavigationState?: typeof commitClientNavigationState;
|
|
39
40
|
performHardNavigation?: (href: string, mode?: HardNavigationMode) => boolean;
|
|
40
41
|
getRouteManifest?: () => RouteManifest | null;
|
|
@@ -51,6 +52,12 @@ type BrowserNavigationController = {
|
|
|
51
52
|
attachBrowserRouterState(setter: Dispatch<AppRouterState | Promise<AppRouterState>>, stateRef: BrowserRouterStateRef): () => void;
|
|
52
53
|
beginPendingBrowserRouterState(): PendingBrowserRouterState;
|
|
53
54
|
finalizeNavigation(navId: number, pending: PendingBrowserRouterState | null | undefined): void;
|
|
55
|
+
restoreHistorySnapshotVisibleState(options: {
|
|
56
|
+
beforeCommit?: () => void;
|
|
57
|
+
navId: number;
|
|
58
|
+
state: AppRouterState;
|
|
59
|
+
targetHref: string;
|
|
60
|
+
}): boolean;
|
|
54
61
|
renderNavigationPayload(options: {
|
|
55
62
|
actionType: "navigate" | "replace" | "traverse";
|
|
56
63
|
createNavigationCommitEffect: BrowserNavigationCommitEffectFactory;
|
|
@@ -64,6 +71,7 @@ type BrowserNavigationController = {
|
|
|
64
71
|
previousNextUrl: string | null;
|
|
65
72
|
scrollIntent?: AppRouterScrollIntent | null;
|
|
66
73
|
restoredBfcacheIds?: Readonly<Record<string, string>> | null;
|
|
74
|
+
reuseCurrentBfcacheIds?: boolean;
|
|
67
75
|
targetHistoryIndex?: number | null;
|
|
68
76
|
targetHref: string;
|
|
69
77
|
navId: number;
|
|
@@ -91,6 +99,8 @@ type BrowserNavigationController = {
|
|
|
91
99
|
}): ReactNode;
|
|
92
100
|
};
|
|
93
101
|
declare function clearHardNavigationLoopGuard(): void;
|
|
102
|
+
declare function createSnapshotPathAndSearch(snapshot: ClientNavigationRenderSnapshot): string;
|
|
103
|
+
declare function createBasePathStrippedPathAndSearch(url: URL, basePath: string): string;
|
|
94
104
|
declare function createAppBrowserNavigationController(deps?: BrowserNavigationControllerDeps): BrowserNavigationController;
|
|
95
105
|
//#endregion
|
|
96
|
-
export { HistoryUpdateMode, NavigationPayloadOutcome, PendingBrowserRouterState, clearHardNavigationLoopGuard, createAppBrowserNavigationController };
|
|
106
|
+
export { HistoryUpdateMode, NavigationPayloadOutcome, PendingBrowserRouterState, clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, createSnapshotPathAndSearch };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripBasePath } from "../utils/base-path.js";
|
|
1
2
|
import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
2
3
|
import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState } from "../shims/navigation.js";
|
|
3
4
|
import { shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
|
|
@@ -49,7 +50,25 @@ function performHardNavigationWithLoopGuard(href, mode = "assign") {
|
|
|
49
50
|
else window.location.assign(href);
|
|
50
51
|
return true;
|
|
51
52
|
}
|
|
53
|
+
function createSnapshotPathAndSearch(snapshot) {
|
|
54
|
+
const query = snapshot.searchParams.toString();
|
|
55
|
+
return query === "" ? snapshot.pathname : `${snapshot.pathname}?${query}`;
|
|
56
|
+
}
|
|
57
|
+
function createBasePathStrippedPathAndSearch(url, basePath) {
|
|
58
|
+
const pathname = stripBasePath(url.pathname, basePath);
|
|
59
|
+
const query = new URLSearchParams(url.search).toString();
|
|
60
|
+
return query === "" ? pathname : `${pathname}?${query}`;
|
|
61
|
+
}
|
|
62
|
+
function isSnapshotTargetHref(basePath, snapshot, targetHref) {
|
|
63
|
+
try {
|
|
64
|
+
const baseHref = typeof window === "undefined" ? "http://localhost" : window.location.href;
|
|
65
|
+
return createBasePathStrippedPathAndSearch(new URL(targetHref, baseHref), basePath) === createSnapshotPathAndSearch(snapshot);
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
52
70
|
function createAppBrowserNavigationController(deps = {}) {
|
|
71
|
+
const basePath = deps.basePath ?? "";
|
|
53
72
|
const commitClientNavigationStateImpl = deps.commitClientNavigationState ?? commitClientNavigationState;
|
|
54
73
|
const performHardNavigation = deps.performHardNavigation ?? performHardNavigationWithLoopGuard;
|
|
55
74
|
const getRouteManifest = deps.getRouteManifest ?? (() => null);
|
|
@@ -215,6 +234,61 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
215
234
|
function dispatchSynchronousVisibleCommit(commit) {
|
|
216
235
|
getBrowserRouterStateSetter()(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
|
|
217
236
|
}
|
|
237
|
+
function createRestoredHistorySnapshotCommit(options) {
|
|
238
|
+
const operation = {
|
|
239
|
+
id: options.renderId,
|
|
240
|
+
lane: "traverse",
|
|
241
|
+
startedVisibleCommitVersion: options.currentState.visibleCommitVersion,
|
|
242
|
+
state: "pending"
|
|
243
|
+
};
|
|
244
|
+
return {
|
|
245
|
+
action: {
|
|
246
|
+
bfcacheIds: options.restoredState.bfcacheIds,
|
|
247
|
+
elements: options.restoredState.elements,
|
|
248
|
+
interception: options.restoredState.interception,
|
|
249
|
+
interceptionContext: options.restoredState.interceptionContext,
|
|
250
|
+
layoutFlags: options.restoredState.layoutFlags,
|
|
251
|
+
layoutIds: options.restoredState.layoutIds,
|
|
252
|
+
navigationSnapshot: options.restoredState.navigationSnapshot,
|
|
253
|
+
operation,
|
|
254
|
+
previousNextUrl: options.restoredState.previousNextUrl,
|
|
255
|
+
renderId: options.renderId,
|
|
256
|
+
rootLayoutTreePath: options.restoredState.rootLayoutTreePath,
|
|
257
|
+
reuseCurrentBfcacheIds: false,
|
|
258
|
+
routeId: options.restoredState.routeId,
|
|
259
|
+
skippedLayoutIds: [],
|
|
260
|
+
slotBindings: options.restoredState.slotBindings,
|
|
261
|
+
type: "traverse"
|
|
262
|
+
},
|
|
263
|
+
interception: options.restoredState.interception,
|
|
264
|
+
interceptionContext: options.restoredState.interceptionContext,
|
|
265
|
+
previousNextUrl: options.restoredState.previousNextUrl,
|
|
266
|
+
rootLayoutTreePath: options.restoredState.rootLayoutTreePath,
|
|
267
|
+
routeId: options.restoredState.routeId,
|
|
268
|
+
skippedLayoutIds: []
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function restoreHistorySnapshotVisibleState(options) {
|
|
272
|
+
if (!isSnapshotTargetHref(basePath, options.state.navigationSnapshot, options.targetHref)) return false;
|
|
273
|
+
const currentState = getBrowserRouterState();
|
|
274
|
+
const pending = createRestoredHistorySnapshotCommit({
|
|
275
|
+
currentState,
|
|
276
|
+
renderId: allocateRenderId(),
|
|
277
|
+
restoredState: options.state
|
|
278
|
+
});
|
|
279
|
+
const approval = approvePendingNavigationCommit({
|
|
280
|
+
activeNavigationId,
|
|
281
|
+
currentState,
|
|
282
|
+
pending,
|
|
283
|
+
routeManifest: getRouteManifest(),
|
|
284
|
+
startedNavigationId: options.navId,
|
|
285
|
+
targetHref: options.targetHref
|
|
286
|
+
});
|
|
287
|
+
if (approval.approvedCommit === null) return false;
|
|
288
|
+
options.beforeCommit?.();
|
|
289
|
+
dispatchSynchronousVisibleCommit(approval.approvedCommit);
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
218
292
|
function notifyDiscardedServerActionRevalidation(lifecycleOptions) {
|
|
219
293
|
if (!shouldScheduleRefreshForDiscardedServerAction(lifecycleOptions?.revalidation ?? "none")) return;
|
|
220
294
|
lifecycleOptions?.onDiscardedRevalidation?.();
|
|
@@ -237,6 +311,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
237
311
|
previousNextUrl: options.previousNextUrl,
|
|
238
312
|
renderId,
|
|
239
313
|
restoredBfcacheIds: options.restoredBfcacheIds,
|
|
314
|
+
reuseCurrentBfcacheIds: options.reuseCurrentBfcacheIds,
|
|
240
315
|
type: options.actionType
|
|
241
316
|
});
|
|
242
317
|
const approval = approvePendingNavigationCommit({
|
|
@@ -354,6 +429,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
354
429
|
attachBrowserRouterState,
|
|
355
430
|
beginPendingBrowserRouterState,
|
|
356
431
|
finalizeNavigation,
|
|
432
|
+
restoreHistorySnapshotVisibleState,
|
|
357
433
|
renderNavigationPayload,
|
|
358
434
|
commitSameUrlNavigatePayload,
|
|
359
435
|
hmrReplaceTree,
|
|
@@ -362,4 +438,4 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
362
438
|
};
|
|
363
439
|
}
|
|
364
440
|
//#endregion
|
|
365
|
-
export { clearHardNavigationLoopGuard, createAppBrowserNavigationController };
|
|
441
|
+
export { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, createSnapshotPathAndSearch };
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
import { NavigationRuntimeNavigate } from "../client/navigation-runtime.js";
|
|
2
|
+
|
|
1
3
|
//#region src/server/app-browser-popstate.d.ts
|
|
2
4
|
type RestoreScrollPosition = (state: unknown, options?: {
|
|
3
5
|
shouldContinue?: () => boolean;
|
|
4
6
|
}) => void;
|
|
5
|
-
type NavigateRsc = (href: string, redirectDepth?: number, navigationKind?: "navigate" | "traverse" | "refresh") => Promise<void>;
|
|
6
7
|
type BrowserPopstateRestoreDeps = {
|
|
7
8
|
getActiveNavigationId: () => number;
|
|
8
9
|
getPendingNavigation: () => Promise<void> | null | undefined;
|
|
9
|
-
getNavigate: () =>
|
|
10
|
+
getNavigate: () => NavigationRuntimeNavigate | undefined;
|
|
10
11
|
isCurrentNavigation: (navId: number) => boolean;
|
|
11
12
|
notifyAppRouterTransitionStart: (href: string) => void;
|
|
12
13
|
restorePopstateScrollPosition: RestoreScrollPosition;
|
|
13
14
|
setPendingNavigation: (pendingNavigation: Promise<void> | null) => void;
|
|
15
|
+
shouldSkipScrollRestore: (navId: number) => boolean;
|
|
14
16
|
};
|
|
17
|
+
type SynchronousPopstateScrollRestoreDeps = {
|
|
18
|
+
getActiveNavigationId: () => number;
|
|
19
|
+
isCurrentNavigation: (navId: number) => boolean;
|
|
20
|
+
markScrollRestoreConsumed: (navId: number) => void;
|
|
21
|
+
restorePopstateScrollPosition: RestoreScrollPosition;
|
|
22
|
+
};
|
|
23
|
+
declare function restoreSynchronousPopstateScrollPosition(deps: SynchronousPopstateScrollRestoreDeps, state: unknown): void;
|
|
15
24
|
declare function createPopstateRestoreHandler(deps: BrowserPopstateRestoreDeps): (event: PopStateEvent) => void;
|
|
16
25
|
//#endregion
|
|
17
|
-
export { createPopstateRestoreHandler };
|
|
26
|
+
export { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import { readHistoryStateTraversalIndex } from "./app-history-state.js";
|
|
2
|
+
import "./app-browser-state.js";
|
|
1
3
|
//#region src/server/app-browser-popstate.ts
|
|
2
4
|
function hasSavedScrollPosition(state) {
|
|
3
5
|
return Boolean(state && typeof state === "object" && "__vinext_scrollY" in state);
|
|
4
6
|
}
|
|
7
|
+
function restoreSynchronousPopstateScrollPosition(deps, state) {
|
|
8
|
+
const navId = deps.getActiveNavigationId();
|
|
9
|
+
deps.markScrollRestoreConsumed(navId);
|
|
10
|
+
deps.restorePopstateScrollPosition(state, { shouldContinue: () => deps.isCurrentNavigation(navId) });
|
|
11
|
+
}
|
|
5
12
|
function scheduleAfterFrame(callback) {
|
|
6
13
|
if (typeof window !== "undefined" && typeof window.requestAnimationFrame === "function") {
|
|
7
14
|
window.requestAnimationFrame(callback);
|
|
@@ -9,21 +16,29 @@ function scheduleAfterFrame(callback) {
|
|
|
9
16
|
}
|
|
10
17
|
queueMicrotask(callback);
|
|
11
18
|
}
|
|
19
|
+
function createPopstateTraversalIntent(historyState) {
|
|
20
|
+
return {
|
|
21
|
+
direction: "unknown",
|
|
22
|
+
historyState,
|
|
23
|
+
targetHistoryIndex: readHistoryStateTraversalIndex(historyState)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
12
26
|
function createPopstateRestoreHandler(deps) {
|
|
13
27
|
return (event) => {
|
|
14
28
|
deps.notifyAppRouterTransitionStart(window.location.href);
|
|
15
|
-
const pendingNavigation = deps.getNavigate()?.(window.location.href, 0, "traverse") ?? Promise.resolve();
|
|
29
|
+
const pendingNavigation = deps.getNavigate()?.(window.location.href, 0, "traverse", void 0, void 0, false, createPopstateTraversalIntent(event.state)) ?? Promise.resolve();
|
|
16
30
|
const popstateNavId = deps.getActiveNavigationId();
|
|
17
31
|
deps.setPendingNavigation(pendingNavigation);
|
|
18
32
|
const shouldRestoreSavedScroll = hasSavedScrollPosition(event.state);
|
|
33
|
+
const shouldRestoreScrollForNavigation = () => deps.isCurrentNavigation(popstateNavId) && !deps.shouldSkipScrollRestore(popstateNavId);
|
|
19
34
|
if (shouldRestoreSavedScroll) scheduleAfterFrame(() => {
|
|
20
|
-
if (
|
|
35
|
+
if (shouldRestoreScrollForNavigation()) deps.restorePopstateScrollPosition(event.state, { shouldContinue: shouldRestoreScrollForNavigation });
|
|
21
36
|
});
|
|
22
37
|
pendingNavigation.finally(() => {
|
|
23
|
-
if (
|
|
38
|
+
if (shouldRestoreScrollForNavigation() && !shouldRestoreSavedScroll) deps.restorePopstateScrollPosition(event.state);
|
|
24
39
|
if (deps.getPendingNavigation() === pendingNavigation) deps.setPendingNavigation(null);
|
|
25
40
|
});
|
|
26
41
|
};
|
|
27
42
|
}
|
|
28
43
|
//#endregion
|
|
29
|
-
export { createPopstateRestoreHandler };
|
|
44
|
+
export { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition };
|
|
@@ -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
|