vinext 0.0.42 → 0.0.44
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/client/vinext-next-data.d.ts +1 -3
- package/dist/deploy.js +21 -4
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +39 -9
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -1
- package/dist/routing/app-router.js +28 -5
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-browser-entry.js +219 -96
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +1 -0
- package/dist/server/app-page-route-wiring.js +12 -2
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-route-handler-policy.js +5 -3
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.js +2 -0
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.js +8 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-ssr-entry.js +2 -1
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/prod-server.js +16 -13
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +33 -1
- package/dist/server/request-pipeline.js +44 -2
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/navigation.d.ts +1 -1
- package/dist/shims/navigation.js +32 -5
- package/dist/shims/navigation.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/entry.d.ts +0 -1
- package/dist/client/entry.js +0 -60
- package/dist/client/entry.js.map +0 -1
|
@@ -7,9 +7,9 @@ import "../client/instrumentation-client.js";
|
|
|
7
7
|
import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
|
|
8
8
|
import { createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl, resolveAndClassifyNavigationCommit, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDisposition, resolveServerActionRequestState, routerReducer } from "./app-browser-state.js";
|
|
9
9
|
import { devOnCaughtError } from "./app-browser-error.js";
|
|
10
|
-
import { createElement, startTransition, use, useLayoutEffect,
|
|
11
|
-
import { hydrateRoot } from "react-dom/client";
|
|
10
|
+
import { createElement, startTransition, use, useLayoutEffect, useRef, useState } from "react";
|
|
12
11
|
import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
|
|
12
|
+
import { hydrateRoot } from "react-dom/client";
|
|
13
13
|
//#region src/server/app-browser-entry.ts
|
|
14
14
|
function toActionType(kind) {
|
|
15
15
|
return kind === "traverse" ? "traverse" : "navigate";
|
|
@@ -21,21 +21,56 @@ let nextNavigationRenderId = 0;
|
|
|
21
21
|
let activeNavigationId = 0;
|
|
22
22
|
const pendingNavigationCommits = /* @__PURE__ */ new Map();
|
|
23
23
|
const pendingNavigationPrePaintEffects = /* @__PURE__ */ new Map();
|
|
24
|
-
|
|
24
|
+
function isRouterStatePromise(value) {
|
|
25
|
+
return value instanceof Promise;
|
|
26
|
+
}
|
|
27
|
+
let setBrowserRouterState = null;
|
|
25
28
|
let browserRouterStateRef = null;
|
|
29
|
+
let activePendingBrowserRouterState = null;
|
|
26
30
|
let latestClientParams = {};
|
|
27
31
|
const visitedResponseCache = /* @__PURE__ */ new Map();
|
|
28
32
|
function isServerActionResult(value) {
|
|
29
33
|
return !!value && typeof value === "object" && "root" in value;
|
|
30
34
|
}
|
|
31
|
-
function
|
|
32
|
-
if (!
|
|
33
|
-
return
|
|
35
|
+
function getBrowserRouterStateSetter() {
|
|
36
|
+
if (!setBrowserRouterState) throw new Error("[vinext] Browser router state setter is not initialized");
|
|
37
|
+
return setBrowserRouterState;
|
|
34
38
|
}
|
|
35
39
|
function getBrowserRouterState() {
|
|
36
40
|
if (!browserRouterStateRef) throw new Error("[vinext] Browser router state is not initialized");
|
|
37
41
|
return browserRouterStateRef.current;
|
|
38
42
|
}
|
|
43
|
+
function beginPendingBrowserRouterState() {
|
|
44
|
+
const setter = getBrowserRouterStateSetter();
|
|
45
|
+
if (activePendingBrowserRouterState && !activePendingBrowserRouterState.settled) {
|
|
46
|
+
activePendingBrowserRouterState.settled = true;
|
|
47
|
+
activePendingBrowserRouterState.resolve(getBrowserRouterState());
|
|
48
|
+
}
|
|
49
|
+
let resolve;
|
|
50
|
+
const promise = new Promise((resolvePromise) => {
|
|
51
|
+
resolve = resolvePromise;
|
|
52
|
+
});
|
|
53
|
+
const pending = {
|
|
54
|
+
promise,
|
|
55
|
+
resolve,
|
|
56
|
+
settled: false
|
|
57
|
+
};
|
|
58
|
+
activePendingBrowserRouterState = pending;
|
|
59
|
+
setter(promise);
|
|
60
|
+
return pending;
|
|
61
|
+
}
|
|
62
|
+
function settlePendingBrowserRouterState(pending) {
|
|
63
|
+
if (!pending || pending.settled) return;
|
|
64
|
+
pending.settled = true;
|
|
65
|
+
pending.resolve(getBrowserRouterState());
|
|
66
|
+
if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
|
|
67
|
+
}
|
|
68
|
+
function resolvePendingBrowserRouterState(pending, action) {
|
|
69
|
+
if (!pending || pending.settled) return;
|
|
70
|
+
pending.settled = true;
|
|
71
|
+
pending.resolve(routerReducer(getBrowserRouterState(), action));
|
|
72
|
+
if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
|
|
73
|
+
}
|
|
39
74
|
function applyClientParams(params) {
|
|
40
75
|
latestClientParams = params;
|
|
41
76
|
setClientParams(params);
|
|
@@ -213,7 +248,7 @@ async function commitSameUrlNavigatePayload(nextElements, returnValue) {
|
|
|
213
248
|
window.location.assign(window.location.href);
|
|
214
249
|
return;
|
|
215
250
|
}
|
|
216
|
-
if (disposition === "dispatch") dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "navigate", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, false);
|
|
251
|
+
if (disposition === "dispatch") dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "navigate", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, null, false);
|
|
217
252
|
if (returnValue) {
|
|
218
253
|
if (!returnValue.ok) throw returnValue.data;
|
|
219
254
|
return returnValue.data;
|
|
@@ -222,7 +257,7 @@ async function commitSameUrlNavigatePayload(nextElements, returnValue) {
|
|
|
222
257
|
function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
|
|
223
258
|
const resolvedElements = use(initialElements);
|
|
224
259
|
const initialMetadata = readAppElementsMetadata(resolvedElements);
|
|
225
|
-
const [
|
|
260
|
+
const [treeStateValue, setTreeStateValue] = useState({
|
|
226
261
|
elements: resolvedElements,
|
|
227
262
|
interceptionContext: initialMetadata.interceptionContext,
|
|
228
263
|
layoutFlags: initialMetadata.layoutFlags,
|
|
@@ -232,17 +267,18 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
|
|
|
232
267
|
rootLayoutTreePath: initialMetadata.rootLayoutTreePath,
|
|
233
268
|
routeId: initialMetadata.routeId
|
|
234
269
|
});
|
|
270
|
+
const treeState = isRouterStatePromise(treeStateValue) ? use(treeStateValue) : treeStateValue;
|
|
235
271
|
const stateRef = useRef(treeState);
|
|
236
272
|
stateRef.current = treeState;
|
|
237
273
|
useLayoutEffect(() => {
|
|
238
|
-
|
|
274
|
+
setBrowserRouterState = setTreeStateValue;
|
|
239
275
|
browserRouterStateRef = stateRef;
|
|
240
276
|
return () => {
|
|
241
|
-
if (
|
|
277
|
+
if (setBrowserRouterState === setTreeStateValue) setBrowserRouterState = null;
|
|
242
278
|
if (browserRouterStateRef === stateRef) browserRouterStateRef = null;
|
|
243
279
|
setMountedSlotsHeader(null);
|
|
244
280
|
};
|
|
245
|
-
}, [
|
|
281
|
+
}, [setTreeStateValue]);
|
|
246
282
|
useLayoutEffect(() => {
|
|
247
283
|
setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
|
|
248
284
|
}, [treeState.elements]);
|
|
@@ -255,9 +291,9 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
|
|
|
255
291
|
if (!ClientNavigationRenderContext) return committedTree;
|
|
256
292
|
return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, committedTree);
|
|
257
293
|
}
|
|
258
|
-
function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType, interceptionContext, layoutFlags, previousNextUrl, routeId, rootLayoutTreePath, useTransitionMode) {
|
|
259
|
-
const
|
|
260
|
-
const
|
|
294
|
+
function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType, interceptionContext, layoutFlags, previousNextUrl, routeId, rootLayoutTreePath, pendingRouterState, useTransitionMode) {
|
|
295
|
+
const setter = getBrowserRouterStateSetter();
|
|
296
|
+
const action = {
|
|
261
297
|
elements,
|
|
262
298
|
interceptionContext,
|
|
263
299
|
layoutFlags,
|
|
@@ -267,11 +303,18 @@ function dispatchBrowserTree(elements, navigationSnapshot, renderId, actionType,
|
|
|
267
303
|
rootLayoutTreePath,
|
|
268
304
|
routeId,
|
|
269
305
|
type: actionType
|
|
270
|
-
}
|
|
306
|
+
};
|
|
307
|
+
const applyAction = () => {
|
|
308
|
+
if (pendingRouterState) {
|
|
309
|
+
resolvePendingBrowserRouterState(pendingRouterState, action);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
setter(routerReducer(getBrowserRouterState(), action));
|
|
313
|
+
};
|
|
271
314
|
if (useTransitionMode) startTransition(applyAction);
|
|
272
315
|
else applyAction();
|
|
273
316
|
}
|
|
274
|
-
async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, useTransition = true, actionType = "navigate") {
|
|
317
|
+
async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, useTransition = true, actionType = "navigate") {
|
|
275
318
|
const renderId = ++nextNavigationRenderId;
|
|
276
319
|
const committed = new Promise((resolve) => {
|
|
277
320
|
pendingNavigationCommits.set(renderId, resolve);
|
|
@@ -294,12 +337,14 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
|
|
|
294
337
|
startedNavigationId: navId
|
|
295
338
|
});
|
|
296
339
|
if (disposition === "skip") {
|
|
340
|
+
settlePendingBrowserRouterState(pendingRouterState);
|
|
297
341
|
const resolve = pendingNavigationCommits.get(renderId);
|
|
298
342
|
pendingNavigationCommits.delete(renderId);
|
|
299
343
|
resolve?.();
|
|
300
344
|
return;
|
|
301
345
|
}
|
|
302
346
|
if (disposition === "hard-navigate") {
|
|
347
|
+
settlePendingBrowserRouterState(pendingRouterState);
|
|
303
348
|
pendingNavigationCommits.delete(renderId);
|
|
304
349
|
window.location.assign(targetHref);
|
|
305
350
|
return;
|
|
@@ -307,12 +352,13 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
|
|
|
307
352
|
queuePrePaintNavigationEffect(renderId, createNavigationCommitEffect(targetHref, historyUpdateMode, navId, params, pending.previousNextUrl));
|
|
308
353
|
activateNavigationSnapshot();
|
|
309
354
|
snapshotActivated = true;
|
|
310
|
-
dispatchBrowserTree(pending.action.elements, navigationSnapshot, renderId, actionType, pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, useTransition);
|
|
355
|
+
dispatchBrowserTree(pending.action.elements, navigationSnapshot, renderId, actionType, pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, pendingRouterState, useTransition);
|
|
311
356
|
} catch (error) {
|
|
312
357
|
pendingNavigationPrePaintEffects.delete(renderId);
|
|
313
358
|
const resolve = pendingNavigationCommits.get(renderId);
|
|
314
359
|
pendingNavigationCommits.delete(renderId);
|
|
315
360
|
if (snapshotActivated) commitClientNavigationState(navId);
|
|
361
|
+
settlePendingBrowserRouterState(pendingRouterState);
|
|
316
362
|
resolve?.();
|
|
317
363
|
throw error;
|
|
318
364
|
}
|
|
@@ -333,9 +379,45 @@ function restorePopstateScrollPosition(state) {
|
|
|
333
379
|
window.scrollTo(x, y);
|
|
334
380
|
});
|
|
335
381
|
}
|
|
382
|
+
let isPageUnloading = false;
|
|
383
|
+
const RSC_RELOAD_KEY = "__vinext_rsc_initial_reload__";
|
|
384
|
+
function readReloadFlag() {
|
|
385
|
+
try {
|
|
386
|
+
return sessionStorage.getItem(RSC_RELOAD_KEY);
|
|
387
|
+
} catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function writeReloadFlag(path) {
|
|
392
|
+
try {
|
|
393
|
+
sessionStorage.setItem(RSC_RELOAD_KEY, path);
|
|
394
|
+
} catch {}
|
|
395
|
+
}
|
|
396
|
+
function clearReloadFlag() {
|
|
397
|
+
try {
|
|
398
|
+
sessionStorage.removeItem(RSC_RELOAD_KEY);
|
|
399
|
+
} catch {}
|
|
400
|
+
}
|
|
401
|
+
function recoverFromBadInitialRscResponse(reason) {
|
|
402
|
+
const currentPath = window.location.pathname + window.location.search;
|
|
403
|
+
if (readReloadFlag() === currentPath) {
|
|
404
|
+
clearReloadFlag();
|
|
405
|
+
console.error(`[vinext] Initial RSC fetch ${reason} after reload; aborting hydration. Server-rendered HTML remains visible; client components will not hydrate.`);
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
writeReloadFlag(currentPath);
|
|
409
|
+
if (readReloadFlag() !== currentPath) {
|
|
410
|
+
console.error(`[vinext] Initial RSC fetch ${reason}; sessionStorage unavailable so the reload-loop guard cannot persist — aborting hydration. Server-rendered HTML remains visible; client components will not hydrate.`);
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
console.warn(`[vinext] Initial RSC fetch ${reason}; reloading once to let the server render the HTML error page`);
|
|
414
|
+
window.location.reload();
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
336
417
|
async function readInitialRscStream() {
|
|
337
418
|
const vinext = getVinextBrowserGlobal();
|
|
338
419
|
if (vinext.__VINEXT_RSC__ || vinext.__VINEXT_RSC_CHUNKS__ || vinext.__VINEXT_RSC_DONE__) {
|
|
420
|
+
clearReloadFlag();
|
|
339
421
|
if (vinext.__VINEXT_RSC__) {
|
|
340
422
|
const embedData = vinext.__VINEXT_RSC__;
|
|
341
423
|
delete vinext.__VINEXT_RSC__;
|
|
@@ -350,6 +432,11 @@ async function readInitialRscStream() {
|
|
|
350
432
|
return createProgressiveRscStream();
|
|
351
433
|
}
|
|
352
434
|
const rscResponse = await fetch(toRscUrl(window.location.pathname + window.location.search));
|
|
435
|
+
if (!rscResponse.ok) return recoverFromBadInitialRscResponse(`returned ${rscResponse.status}`);
|
|
436
|
+
const contentType = rscResponse.headers.get("content-type") ?? "";
|
|
437
|
+
if (!contentType.startsWith("text/x-component")) return recoverFromBadInitialRscResponse(`returned non-RSC content-type "${contentType || "(missing)"}"`);
|
|
438
|
+
if (!rscResponse.body) return recoverFromBadInitialRscResponse("returned empty body");
|
|
439
|
+
clearReloadFlag();
|
|
353
440
|
let params = {};
|
|
354
441
|
const paramsHeader = rscResponse.headers.get("X-Vinext-Params");
|
|
355
442
|
if (paramsHeader) try {
|
|
@@ -357,7 +444,6 @@ async function readInitialRscStream() {
|
|
|
357
444
|
applyClientParams(params);
|
|
358
445
|
} catch {}
|
|
359
446
|
restoreHydrationNavigationContext(window.location.pathname, window.location.search, params);
|
|
360
|
-
if (!rscResponse.body) throw new Error("[vinext] Initial RSC response had no body");
|
|
361
447
|
return rscResponse.body;
|
|
362
448
|
}
|
|
363
449
|
function registerServerActionCallback() {
|
|
@@ -396,7 +482,12 @@ function registerServerActionCallback() {
|
|
|
396
482
|
}
|
|
397
483
|
async function main() {
|
|
398
484
|
registerServerActionCallback();
|
|
399
|
-
const
|
|
485
|
+
const rscStream = await readInitialRscStream();
|
|
486
|
+
if (rscStream === null) return;
|
|
487
|
+
bootstrapHydration(rscStream);
|
|
488
|
+
}
|
|
489
|
+
function bootstrapHydration(rscStream) {
|
|
490
|
+
const root = normalizeAppElementsPromise(createFromReadableStream(rscStream));
|
|
400
491
|
const initialNavigationSnapshot = createClientNavigationRenderSnapshot(window.location.href, latestClientParams);
|
|
401
492
|
replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(window.history.state, null), "", window.location.href);
|
|
402
493
|
window.__VINEXT_RSC_ROOT__ = hydrateRoot(document, createElement(BrowserRoot, {
|
|
@@ -404,99 +495,123 @@ async function main() {
|
|
|
404
495
|
initialNavigationSnapshot
|
|
405
496
|
}), import.meta.env.DEV ? { onCaughtError: devOnCaughtError } : void 0);
|
|
406
497
|
window.__VINEXT_HYDRATED_AT = performance.now();
|
|
407
|
-
window.__VINEXT_RSC_NAVIGATE__ = async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride) {
|
|
408
|
-
if (redirectDepth > 10) {
|
|
409
|
-
console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
|
|
410
|
-
window.location.href = href;
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
498
|
+
window.__VINEXT_RSC_NAVIGATE__ = async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false) {
|
|
413
499
|
let _snapshotPending = false;
|
|
500
|
+
let pendingRouterState = null;
|
|
414
501
|
const navId = ++activeNavigationId;
|
|
502
|
+
let currentHref = href;
|
|
503
|
+
let currentHistoryMode = historyUpdateMode;
|
|
504
|
+
let currentPrevNextUrl = previousNextUrlOverride;
|
|
505
|
+
let redirectCount = redirectDepth;
|
|
415
506
|
try {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
507
|
+
if (programmaticTransition) pendingRouterState = beginPendingBrowserRouterState();
|
|
508
|
+
while (true) {
|
|
509
|
+
if (redirectCount > 10) {
|
|
510
|
+
console.error("[vinext] Too many RSC redirects — aborting navigation to prevent infinite loop.");
|
|
511
|
+
window.location.href = currentHref;
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const url = new URL(currentHref, window.location.origin);
|
|
515
|
+
const rscUrl = toRscUrl(url.pathname + url.search);
|
|
516
|
+
const requestState = getRequestState(navigationKind, currentPrevNextUrl);
|
|
517
|
+
const requestInterceptionContext = requestState.interceptionContext;
|
|
518
|
+
const requestPreviousNextUrl = requestState.previousNextUrl;
|
|
519
|
+
const navState = getClientNavigationState();
|
|
520
|
+
const currentPath = navState?.pendingPathname ?? navState?.cachedPathname ?? stripBasePath(window.location.pathname, __basePath);
|
|
521
|
+
const isSameRoute = stripBasePath(url.pathname, __basePath) === currentPath;
|
|
522
|
+
setPendingPathname(url.pathname, navId);
|
|
523
|
+
const elementsAtNavStart = getBrowserRouterState().elements;
|
|
524
|
+
const mountedSlotsHeader = getMountedSlotIdsHeader(elementsAtNavStart);
|
|
525
|
+
const cachedRoute = getVisitedResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader, navigationKind);
|
|
526
|
+
if (cachedRoute) {
|
|
527
|
+
if (navId !== activeNavigationId) return;
|
|
528
|
+
const cachedParams = cachedRoute.params;
|
|
529
|
+
const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(currentHref, cachedParams);
|
|
530
|
+
const cachedPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
|
|
531
|
+
if (navId !== activeNavigationId) return;
|
|
532
|
+
_snapshotPending = true;
|
|
533
|
+
try {
|
|
534
|
+
await renderNavigationPayload(cachedPayload, cachedNavigationSnapshot, currentHref, navId, currentHistoryMode, cachedParams, requestPreviousNextUrl, pendingRouterState, isSameRoute, toActionType(navigationKind));
|
|
535
|
+
} finally {
|
|
536
|
+
_snapshotPending = false;
|
|
537
|
+
}
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
let navResponse;
|
|
541
|
+
let navResponseUrl = null;
|
|
542
|
+
if (navigationKind !== "refresh") {
|
|
543
|
+
const prefetchedResponse = consumePrefetchResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader);
|
|
544
|
+
if (prefetchedResponse) {
|
|
545
|
+
navResponse = restoreRscResponse(prefetchedResponse, false);
|
|
546
|
+
navResponseUrl = prefetchedResponse.url;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (!navResponse) {
|
|
550
|
+
const requestHeaders = createRscRequestHeaders(requestInterceptionContext);
|
|
551
|
+
if (mountedSlotsHeader) requestHeaders.set("X-Vinext-Mounted-Slots", mountedSlotsHeader);
|
|
552
|
+
navResponse = await fetch(rscUrl, {
|
|
553
|
+
headers: requestHeaders,
|
|
554
|
+
credentials: "include"
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
if (navId !== activeNavigationId) return;
|
|
558
|
+
const isRscResponse = (navResponse.headers.get("content-type") ?? "").startsWith("text/x-component");
|
|
559
|
+
if (!navResponse.ok || !isRscResponse || !navResponse.body) {
|
|
560
|
+
const responseUrl = navResponseUrl ?? navResponse.url;
|
|
561
|
+
let hardNavTarget = currentHref;
|
|
562
|
+
if (responseUrl) {
|
|
563
|
+
const parsed = new URL(responseUrl, window.location.origin);
|
|
564
|
+
const origUrl = new URL(currentHref, window.location.origin);
|
|
565
|
+
let pathname = parsed.pathname.replace(/\.rsc$/, "");
|
|
566
|
+
if (origUrl.pathname.length > 1 && origUrl.pathname.endsWith("/") && !pathname.endsWith("/")) pathname += "/";
|
|
567
|
+
hardNavTarget = pathname + parsed.search;
|
|
568
|
+
if (origUrl.hash) hardNavTarget += origUrl.hash;
|
|
569
|
+
}
|
|
570
|
+
window.location.href = hardNavTarget;
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const finalUrl = new URL(navResponseUrl ?? navResponse.url, window.location.origin);
|
|
574
|
+
const requestedUrl = new URL(rscUrl, window.location.origin);
|
|
575
|
+
if (finalUrl.pathname !== requestedUrl.pathname) {
|
|
576
|
+
const destinationPath = finalUrl.pathname.replace(/\.rsc$/, "") + finalUrl.search;
|
|
577
|
+
replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(null, requestPreviousNextUrl), "", destinationPath);
|
|
578
|
+
currentHref = destinationPath;
|
|
579
|
+
currentHistoryMode = void 0;
|
|
580
|
+
currentPrevNextUrl = requestPreviousNextUrl;
|
|
581
|
+
redirectCount += 1;
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
let navParams = {};
|
|
585
|
+
const paramsHeader = navResponse.headers.get("X-Vinext-Params");
|
|
586
|
+
if (paramsHeader) try {
|
|
587
|
+
navParams = JSON.parse(decodeURIComponent(paramsHeader));
|
|
588
|
+
} catch {}
|
|
589
|
+
const navigationSnapshot = createClientNavigationRenderSnapshot(currentHref, navParams);
|
|
590
|
+
const responseSnapshot = await snapshotRscResponse(navResponse);
|
|
429
591
|
if (navId !== activeNavigationId) return;
|
|
430
|
-
const
|
|
431
|
-
const cachedNavigationSnapshot = createClientNavigationRenderSnapshot(href, cachedParams);
|
|
432
|
-
const cachedPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(cachedRoute.response))));
|
|
592
|
+
const rscPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(responseSnapshot))));
|
|
433
593
|
if (navId !== activeNavigationId) return;
|
|
434
594
|
_snapshotPending = true;
|
|
435
595
|
try {
|
|
436
|
-
await renderNavigationPayload(
|
|
596
|
+
await renderNavigationPayload(rscPayload, navigationSnapshot, currentHref, navId, currentHistoryMode, navParams, requestPreviousNextUrl, pendingRouterState, isSameRoute, toActionType(navigationKind));
|
|
437
597
|
} finally {
|
|
438
598
|
_snapshotPending = false;
|
|
439
599
|
}
|
|
600
|
+
if (navId !== activeNavigationId) return;
|
|
601
|
+
storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, readAppElementsMetadata(await rscPayload).interceptionContext), responseSnapshot, navParams);
|
|
440
602
|
return;
|
|
441
603
|
}
|
|
442
|
-
let navResponse;
|
|
443
|
-
let navResponseUrl = null;
|
|
444
|
-
if (navigationKind !== "refresh") {
|
|
445
|
-
const prefetchedResponse = consumePrefetchResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader);
|
|
446
|
-
if (prefetchedResponse) {
|
|
447
|
-
navResponse = restoreRscResponse(prefetchedResponse, false);
|
|
448
|
-
navResponseUrl = prefetchedResponse.url;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
if (!navResponse) {
|
|
452
|
-
const requestHeaders = createRscRequestHeaders(requestInterceptionContext);
|
|
453
|
-
if (mountedSlotsHeader) requestHeaders.set("X-Vinext-Mounted-Slots", mountedSlotsHeader);
|
|
454
|
-
navResponse = await fetch(rscUrl, {
|
|
455
|
-
headers: requestHeaders,
|
|
456
|
-
credentials: "include"
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
if (navId !== activeNavigationId) return;
|
|
460
|
-
const finalUrl = new URL(navResponseUrl ?? navResponse.url, window.location.origin);
|
|
461
|
-
const requestedUrl = new URL(rscUrl, window.location.origin);
|
|
462
|
-
if (finalUrl.pathname !== requestedUrl.pathname) {
|
|
463
|
-
const destinationPath = finalUrl.pathname.replace(/\.rsc$/, "") + finalUrl.search;
|
|
464
|
-
replaceHistoryStateWithoutNotify(createHistoryStateWithPreviousNextUrl(null, requestPreviousNextUrl), "", destinationPath);
|
|
465
|
-
const navigate = window.__VINEXT_RSC_NAVIGATE__;
|
|
466
|
-
if (!navigate) {
|
|
467
|
-
window.location.href = destinationPath;
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
return navigate(destinationPath, redirectDepth + 1, navigationKind, void 0, requestPreviousNextUrl);
|
|
471
|
-
}
|
|
472
|
-
let navParams = {};
|
|
473
|
-
const paramsHeader = navResponse.headers.get("X-Vinext-Params");
|
|
474
|
-
if (paramsHeader) try {
|
|
475
|
-
navParams = JSON.parse(decodeURIComponent(paramsHeader));
|
|
476
|
-
} catch {}
|
|
477
|
-
const navigationSnapshot = createClientNavigationRenderSnapshot(href, navParams);
|
|
478
|
-
const responseSnapshot = await snapshotRscResponse(navResponse);
|
|
479
|
-
if (navId !== activeNavigationId) return;
|
|
480
|
-
const rscPayload = normalizeAppElementsPromise(createFromFetch(Promise.resolve(restoreRscResponse(responseSnapshot))));
|
|
481
|
-
if (navId !== activeNavigationId) return;
|
|
482
|
-
_snapshotPending = true;
|
|
483
|
-
try {
|
|
484
|
-
await renderNavigationPayload(rscPayload, navigationSnapshot, href, navId, historyUpdateMode, navParams, requestPreviousNextUrl, isSameRoute, toActionType(navigationKind));
|
|
485
|
-
} finally {
|
|
486
|
-
_snapshotPending = false;
|
|
487
|
-
}
|
|
488
|
-
if (navId !== activeNavigationId) return;
|
|
489
|
-
storeVisitedResponseSnapshot(rscUrl, resolveVisitedResponseInterceptionContext(requestInterceptionContext, readAppElementsMetadata(await rscPayload).interceptionContext), responseSnapshot, navParams);
|
|
490
|
-
return;
|
|
491
604
|
} catch (error) {
|
|
492
605
|
if (_snapshotPending) {
|
|
493
606
|
_snapshotPending = false;
|
|
494
607
|
commitClientNavigationState(navId);
|
|
495
608
|
}
|
|
496
|
-
if (navId === activeNavigationId) clearPendingPathname(navId);
|
|
497
609
|
if (navId !== activeNavigationId) return;
|
|
498
|
-
console.error("[vinext] RSC navigation error:", error);
|
|
499
|
-
window.location.href =
|
|
610
|
+
if (!isPageUnloading) console.error("[vinext] RSC navigation error:", error);
|
|
611
|
+
window.location.href = currentHref;
|
|
612
|
+
} finally {
|
|
613
|
+
settlePendingBrowserRouterState(pendingRouterState);
|
|
614
|
+
if (navId === activeNavigationId) clearPendingPathname(navId);
|
|
500
615
|
}
|
|
501
616
|
};
|
|
502
617
|
if ("scrollRestoration" in history) history.scrollRestoration = "manual";
|
|
@@ -520,13 +635,21 @@ async function main() {
|
|
|
520
635
|
renderId: ++nextNavigationRenderId,
|
|
521
636
|
type: "replace"
|
|
522
637
|
});
|
|
523
|
-
dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "replace", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, false);
|
|
638
|
+
dispatchBrowserTree(pending.action.elements, navigationSnapshot, pending.action.renderId, "replace", pending.interceptionContext, pending.action.layoutFlags, pending.previousNextUrl, pending.routeId, pending.rootLayoutTreePath, null, false);
|
|
524
639
|
} catch (error) {
|
|
525
640
|
console.error("[vinext] RSC HMR error:", error);
|
|
526
641
|
}
|
|
527
642
|
});
|
|
528
643
|
}
|
|
529
|
-
if (typeof document !== "undefined")
|
|
644
|
+
if (typeof document !== "undefined") {
|
|
645
|
+
window.addEventListener("pagehide", () => {
|
|
646
|
+
isPageUnloading = true;
|
|
647
|
+
});
|
|
648
|
+
window.addEventListener("pageshow", () => {
|
|
649
|
+
isPageUnloading = false;
|
|
650
|
+
});
|
|
651
|
+
main();
|
|
652
|
+
}
|
|
530
653
|
//#endregion
|
|
531
654
|
export {};
|
|
532
655
|
|