Files
Webklar.com/node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

265 lines
14 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
handleExternalUrl: null,
navigateReducer: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
handleExternalUrl: function() {
return handleExternalUrl;
},
navigateReducer: function() {
return navigateReducer;
}
});
const _approutercontextsharedruntime = require("../../../../shared/lib/app-router-context.shared-runtime");
const _fetchserverresponse = require("../fetch-server-response");
const _createrecordfromthenable = require("../create-record-from-thenable");
const _readrecordvalue = require("../read-record-value");
const _createhreffromurl = require("../create-href-from-url");
const _invalidatecachebelowflightsegmentpath = require("../invalidate-cache-below-flight-segmentpath");
const _fillcachewithdataproperty = require("../fill-cache-with-data-property");
const _createoptimistictree = require("../create-optimistic-tree");
const _applyrouterstatepatchtotree = require("../apply-router-state-patch-to-tree");
const _shouldhardnavigate = require("../should-hard-navigate");
const _isnavigatingtonewrootlayout = require("../is-navigating-to-new-root-layout");
const _routerreducertypes = require("../router-reducer-types");
const _handlemutable = require("../handle-mutable");
const _applyflightdata = require("../apply-flight-data");
const _getprefetchcacheentrystatus = require("../get-prefetch-cache-entry-status");
const _pruneprefetchcache = require("./prune-prefetch-cache");
const _prefetchreducer = require("./prefetch-reducer");
function handleExternalUrl(state, mutable, url, pendingPush) {
mutable.previousTree = state.tree;
mutable.mpaNavigation = true;
mutable.canonicalUrl = url;
mutable.pendingPush = pendingPush;
mutable.scrollableSegments = undefined;
return (0, _handlemutable.handleMutable)(state, mutable);
}
function generateSegmentsFromPatch(flightRouterPatch) {
const segments = [];
const [segment, parallelRoutes] = flightRouterPatch;
if (Object.keys(parallelRoutes).length === 0) {
return [
[
segment
]
];
}
for (const [parallelRouteKey, parallelRoute] of Object.entries(parallelRoutes)){
for (const childSegment of generateSegmentsFromPatch(parallelRoute)){
// If the segment is empty, it means we are at the root of the tree
if (segment === "") {
segments.push([
parallelRouteKey,
...childSegment
]);
} else {
segments.push([
segment,
parallelRouteKey,
...childSegment
]);
}
}
}
return segments;
}
function addRefetchToLeafSegments(newCache, currentCache, flightSegmentPath, treePatch, data) {
let appliedPatch = false;
newCache.status = _approutercontextsharedruntime.CacheStates.READY;
newCache.subTreeData = currentCache.subTreeData;
newCache.parallelRoutes = new Map(currentCache.parallelRoutes);
const segmentPathsToFill = generateSegmentsFromPatch(treePatch).map((segment)=>[
...flightSegmentPath,
...segment
]);
for (const segmentPaths of segmentPathsToFill){
const res = (0, _fillcachewithdataproperty.fillCacheWithDataProperty)(newCache, currentCache, segmentPaths, data);
if (!(res == null ? void 0 : res.bailOptimistic)) {
appliedPatch = true;
}
}
return appliedPatch;
}
function navigateReducer(state, action) {
const { url, isExternalUrl, navigateType, cache, mutable, forceOptimisticNavigation, shouldScroll } = action;
const { pathname, hash } = url;
const href = (0, _createhreffromurl.createHrefFromUrl)(url);
const pendingPush = navigateType === "push";
// we want to prune the prefetch cache on every navigation to avoid it growing too large
(0, _pruneprefetchcache.prunePrefetchCache)(state.prefetchCache);
const isForCurrentTree = JSON.stringify(mutable.previousTree) === JSON.stringify(state.tree);
if (isForCurrentTree) {
return (0, _handlemutable.handleMutable)(state, mutable);
}
if (isExternalUrl) {
return handleExternalUrl(state, mutable, url.toString(), pendingPush);
}
let prefetchValues = state.prefetchCache.get((0, _createhreffromurl.createHrefFromUrl)(url, false));
if (forceOptimisticNavigation && (prefetchValues == null ? void 0 : prefetchValues.kind) !== _routerreducertypes.PrefetchKind.TEMPORARY) {
const segments = pathname.split("/");
// TODO-APP: figure out something better for index pages
segments.push("__PAGE__");
// Optimistic tree case.
// If the optimistic tree is deeper than the current state leave that deeper part out of the fetch
const optimisticTree = (0, _createoptimistictree.createOptimisticTree)(segments, state.tree, false);
// we need a copy of the cache in case we need to revert to it
const temporaryCacheNode = {
...cache
};
// Copy subTreeData for the root node of the cache.
// Note: didn't do it above because typescript doesn't like it.
temporaryCacheNode.status = _approutercontextsharedruntime.CacheStates.READY;
temporaryCacheNode.subTreeData = state.cache.subTreeData;
temporaryCacheNode.parallelRoutes = new Map(state.cache.parallelRoutes);
let data;
const fetchResponse = ()=>{
if (!data) {
data = (0, _createrecordfromthenable.createRecordFromThenable)((0, _fetchserverresponse.fetchServerResponse)(url, optimisticTree, state.nextUrl, state.buildId));
}
return data;
};
// TODO-APP: segments.slice(1) strips '', we can get rid of '' altogether.
// TODO-APP: re-evaluate if we need to strip the last segment
const optimisticFlightSegmentPath = segments.slice(1).map((segment)=>[
"children",
segment
]).flat();
// Copy existing cache nodes as far as possible and fill in `data` property with the started data fetch.
// The `data` property is used to suspend in layout-router during render if it hasn't resolved yet by the time it renders.
const res = (0, _fillcachewithdataproperty.fillCacheWithDataProperty)(temporaryCacheNode, state.cache, optimisticFlightSegmentPath, fetchResponse, true);
// If optimistic fetch couldn't happen it falls back to the non-optimistic case.
if (!(res == null ? void 0 : res.bailOptimistic)) {
mutable.previousTree = state.tree;
mutable.patchedTree = optimisticTree;
mutable.pendingPush = pendingPush;
mutable.hashFragment = hash;
mutable.shouldScroll = shouldScroll;
mutable.scrollableSegments = [];
mutable.cache = temporaryCacheNode;
mutable.canonicalUrl = href;
state.prefetchCache.set((0, _createhreffromurl.createHrefFromUrl)(url, false), {
data: (0, _createrecordfromthenable.createRecordFromThenable)(Promise.resolve(data)),
// this will make sure that the entry will be discarded after 30s
kind: _routerreducertypes.PrefetchKind.TEMPORARY,
prefetchTime: Date.now(),
treeAtTimeOfPrefetch: state.tree,
lastUsedTime: Date.now()
});
return (0, _handlemutable.handleMutable)(state, mutable);
}
}
// If we don't have a prefetch value, we need to create one
if (!prefetchValues) {
const data = (0, _createrecordfromthenable.createRecordFromThenable)((0, _fetchserverresponse.fetchServerResponse)(url, state.tree, state.nextUrl, state.buildId, // in dev, there's never gonna be a prefetch entry so we want to prefetch here
// in order to simulate the behavior of the prefetch cache
process.env.NODE_ENV === "development" ? _routerreducertypes.PrefetchKind.AUTO : undefined));
const newPrefetchValue = {
data: (0, _createrecordfromthenable.createRecordFromThenable)(Promise.resolve(data)),
// this will make sure that the entry will be discarded after 30s
kind: process.env.NODE_ENV === "development" ? _routerreducertypes.PrefetchKind.AUTO : _routerreducertypes.PrefetchKind.TEMPORARY,
prefetchTime: Date.now(),
treeAtTimeOfPrefetch: state.tree,
lastUsedTime: null
};
state.prefetchCache.set((0, _createhreffromurl.createHrefFromUrl)(url, false), newPrefetchValue);
prefetchValues = newPrefetchValue;
}
const prefetchEntryCacheStatus = (0, _getprefetchcacheentrystatus.getPrefetchEntryCacheStatus)(prefetchValues);
// The one before last item is the router state tree patch
const { treeAtTimeOfPrefetch, data } = prefetchValues;
_prefetchreducer.prefetchQueue.bump(data);
// Unwrap cache data with `use` to suspend here (in the reducer) until the fetch resolves.
const [flightData, canonicalUrlOverride] = (0, _readrecordvalue.readRecordValue)(data);
// we only want to mark this once
if (!prefetchValues.lastUsedTime) {
// important: we should only mark the cache node as dirty after we unsuspend from the call above
prefetchValues.lastUsedTime = Date.now();
}
// Handle case when navigating to page in `pages` from `app`
if (typeof flightData === "string") {
return handleExternalUrl(state, mutable, flightData, pendingPush);
}
let currentTree = state.tree;
let currentCache = state.cache;
let scrollableSegments = [];
for (const flightDataPath of flightData){
const flightSegmentPath = flightDataPath.slice(0, -4);
// The one before last item is the router state tree patch
const treePatch = flightDataPath.slice(-3)[0];
// TODO-APP: remove ''
const flightSegmentPathWithLeadingEmpty = [
"",
...flightSegmentPath
];
// Create new tree based on the flightSegmentPath and router state patch
let newTree = (0, _applyrouterstatepatchtotree.applyRouterStatePatchToTree)(// TODO-APP: remove ''
flightSegmentPathWithLeadingEmpty, currentTree, treePatch);
// If the tree patch can't be applied to the current tree then we use the tree at time of prefetch
// TODO-APP: This should instead fill in the missing pieces in `currentTree` with the data from `treeAtTimeOfPrefetch`, then apply the patch.
if (newTree === null) {
newTree = (0, _applyrouterstatepatchtotree.applyRouterStatePatchToTree)(// TODO-APP: remove ''
flightSegmentPathWithLeadingEmpty, treeAtTimeOfPrefetch, treePatch);
}
if (newTree !== null) {
if ((0, _isnavigatingtonewrootlayout.isNavigatingToNewRootLayout)(currentTree, newTree)) {
return handleExternalUrl(state, mutable, href, pendingPush);
}
let applied = (0, _applyflightdata.applyFlightData)(currentCache, cache, flightDataPath, prefetchValues.kind === "auto" && prefetchEntryCacheStatus === _getprefetchcacheentrystatus.PrefetchCacheEntryStatus.reusable);
if (!applied && prefetchEntryCacheStatus === _getprefetchcacheentrystatus.PrefetchCacheEntryStatus.stale) {
applied = addRefetchToLeafSegments(cache, currentCache, flightSegmentPath, treePatch, // eslint-disable-next-line no-loop-func
()=>(0, _fetchserverresponse.fetchServerResponse)(url, currentTree, state.nextUrl, state.buildId));
}
const hardNavigate = (0, _shouldhardnavigate.shouldHardNavigate)(// TODO-APP: remove ''
flightSegmentPathWithLeadingEmpty, currentTree);
if (hardNavigate) {
cache.status = _approutercontextsharedruntime.CacheStates.READY;
// Copy subTreeData for the root node of the cache.
cache.subTreeData = currentCache.subTreeData;
(0, _invalidatecachebelowflightsegmentpath.invalidateCacheBelowFlightSegmentPath)(cache, currentCache, flightSegmentPath);
// Ensure the existing cache value is used when the cache was not invalidated.
mutable.cache = cache;
} else if (applied) {
mutable.cache = cache;
}
currentCache = cache;
currentTree = newTree;
for (const subSegment of generateSegmentsFromPatch(treePatch)){
const scrollableSegmentPath = [
...flightSegmentPath,
...subSegment
];
// Filter out the __DEFAULT__ paths as they shouldn't be scrolled to in this case.
if (scrollableSegmentPath[scrollableSegmentPath.length - 1] !== "__DEFAULT__") {
scrollableSegments.push(scrollableSegmentPath);
}
}
}
}
mutable.previousTree = state.tree;
mutable.patchedTree = currentTree;
mutable.canonicalUrl = canonicalUrlOverride ? (0, _createhreffromurl.createHrefFromUrl)(canonicalUrlOverride) : href;
mutable.pendingPush = pendingPush;
mutable.scrollableSegments = scrollableSegments;
mutable.hashFragment = hash;
mutable.shouldScroll = shouldScroll;
return (0, _handlemutable.handleMutable)(state, mutable);
}
if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
Object.defineProperty(exports.default, '__esModule', { value: true });
Object.assign(exports.default, exports);
module.exports = exports.default;
}
//# sourceMappingURL=navigate-reducer.js.map