Initial boiler plate project
This commit is contained in:
390
node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js
generated
vendored
Normal file
390
node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js
generated
vendored
Normal file
@ -0,0 +1,390 @@
|
||||
"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 _fetchserverresponse = require("../fetch-server-response");
|
||||
const _createhreffromurl = require("../create-href-from-url");
|
||||
const _invalidatecachebelowflightsegmentpath = require("../invalidate-cache-below-flight-segmentpath");
|
||||
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 _prefetchreducer = require("./prefetch-reducer");
|
||||
const _approuter = require("../../app-router");
|
||||
const _segment = require("../../../../shared/lib/segment");
|
||||
const _pprnavigations = require("../ppr-navigations");
|
||||
const _prefetchcacheutils = require("../prefetch-cache-utils");
|
||||
const _clearcachenodedataforsegmentpath = require("../clear-cache-node-data-for-segment-path");
|
||||
function handleExternalUrl(state, mutable, url, pendingPush) {
|
||||
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 triggerLazyFetchForLeafSegments(newCache, currentCache, flightSegmentPath, treePatch) {
|
||||
let appliedPatch = false;
|
||||
newCache.rsc = currentCache.rsc;
|
||||
newCache.prefetchRsc = currentCache.prefetchRsc;
|
||||
newCache.loading = currentCache.loading;
|
||||
newCache.parallelRoutes = new Map(currentCache.parallelRoutes);
|
||||
const segmentPathsToFill = generateSegmentsFromPatch(treePatch).map((segment)=>[
|
||||
...flightSegmentPath,
|
||||
...segment
|
||||
]);
|
||||
for (const segmentPaths of segmentPathsToFill){
|
||||
(0, _clearcachenodedataforsegmentpath.clearCacheNodeDataForSegmentPath)(newCache, currentCache, segmentPaths);
|
||||
appliedPatch = true;
|
||||
}
|
||||
return appliedPatch;
|
||||
}
|
||||
const navigateReducer = process.env.__NEXT_PPR ? navigateReducer_PPR : navigateReducer_noPPR;
|
||||
// This is the implementation when PPR is disabled. We can assume its behavior
|
||||
// is relatively stable because it's been running in production for a while.
|
||||
function navigateReducer_noPPR(state, action) {
|
||||
const { url, isExternalUrl, navigateType, shouldScroll } = action;
|
||||
const mutable = {};
|
||||
const { 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, _prefetchcacheutils.prunePrefetchCache)(state.prefetchCache);
|
||||
mutable.preserveCustomHistoryState = false;
|
||||
if (isExternalUrl) {
|
||||
return handleExternalUrl(state, mutable, url.toString(), pendingPush);
|
||||
}
|
||||
const prefetchValues = (0, _prefetchcacheutils.getOrCreatePrefetchCacheEntry)({
|
||||
url,
|
||||
nextUrl: state.nextUrl,
|
||||
tree: state.tree,
|
||||
buildId: state.buildId,
|
||||
prefetchCache: state.prefetchCache
|
||||
});
|
||||
const { treeAtTimeOfPrefetch, data } = prefetchValues;
|
||||
_prefetchreducer.prefetchQueue.bump(data);
|
||||
return data.then((param)=>{
|
||||
let [flightData, canonicalUrlOverride] = param;
|
||||
let isFirstRead = false;
|
||||
// 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();
|
||||
isFirstRead = true;
|
||||
}
|
||||
// Handle case when navigating to page in `pages` from `app`
|
||||
if (typeof flightData === "string") {
|
||||
return handleExternalUrl(state, mutable, flightData, pendingPush);
|
||||
}
|
||||
// Handles case where `<meta http-equiv="refresh">` tag is present,
|
||||
// which will trigger an MPA navigation.
|
||||
if (document.getElementById("__next-page-redirect")) {
|
||||
return handleExternalUrl(state, mutable, href, 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, href);
|
||||
// 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, href);
|
||||
}
|
||||
if (newTree !== null) {
|
||||
if ((0, _isnavigatingtonewrootlayout.isNavigatingToNewRootLayout)(currentTree, newTree)) {
|
||||
return handleExternalUrl(state, mutable, href, pendingPush);
|
||||
}
|
||||
const cache = (0, _approuter.createEmptyCacheNode)();
|
||||
let applied = false;
|
||||
if (prefetchValues.status === _routerreducertypes.PrefetchCacheEntryStatus.stale && !isFirstRead) {
|
||||
// When we have a stale prefetch entry, we only want to re-use the loading state of the route we're navigating to, to support instant loading navigations
|
||||
// this will trigger a lazy fetch for the actual page data by nulling the `rsc` and `prefetchRsc` values for page data,
|
||||
// while copying over the `loading` for the segment that contains the page data.
|
||||
// We only do this on subsequent reads, as otherwise there'd be no loading data to re-use.
|
||||
applied = triggerLazyFetchForLeafSegments(cache, currentCache, flightSegmentPath, treePatch);
|
||||
// since we re-used the stale cache's loading state & refreshed the data,
|
||||
// update the `lastUsedTime` so that it can continue to be re-used for the next 30s
|
||||
prefetchValues.lastUsedTime = Date.now();
|
||||
} else {
|
||||
applied = (0, _applyflightdata.applyFlightData)(currentCache, cache, flightDataPath, prefetchValues);
|
||||
}
|
||||
const hardNavigate = (0, _shouldhardnavigate.shouldHardNavigate)(// TODO-APP: remove ''
|
||||
flightSegmentPathWithLeadingEmpty, currentTree);
|
||||
if (hardNavigate) {
|
||||
// Copy rsc for the root node of the cache.
|
||||
cache.rsc = currentCache.rsc;
|
||||
cache.prefetchRsc = currentCache.prefetchRsc;
|
||||
(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;
|
||||
// If we applied the cache, we update the "current cache" value so any other
|
||||
// segments in the FlightDataPath will be able to reference the updated 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] !== _segment.DEFAULT_SEGMENT_KEY) {
|
||||
scrollableSegments.push(scrollableSegmentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}, ()=>state);
|
||||
}
|
||||
// This is the experimental PPR implementation. It's closer to the behavior we
|
||||
// want, but is likelier to include accidental regressions because it rewrites
|
||||
// existing functionality.
|
||||
function navigateReducer_PPR(state, action) {
|
||||
const { url, isExternalUrl, navigateType, shouldScroll } = action;
|
||||
const mutable = {};
|
||||
const { 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, _prefetchcacheutils.prunePrefetchCache)(state.prefetchCache);
|
||||
mutable.preserveCustomHistoryState = false;
|
||||
if (isExternalUrl) {
|
||||
return handleExternalUrl(state, mutable, url.toString(), pendingPush);
|
||||
}
|
||||
const prefetchValues = (0, _prefetchcacheutils.getOrCreatePrefetchCacheEntry)({
|
||||
url,
|
||||
nextUrl: state.nextUrl,
|
||||
tree: state.tree,
|
||||
buildId: state.buildId,
|
||||
prefetchCache: state.prefetchCache
|
||||
});
|
||||
const { treeAtTimeOfPrefetch, data } = prefetchValues;
|
||||
_prefetchreducer.prefetchQueue.bump(data);
|
||||
return data.then((param)=>{
|
||||
let [flightData, canonicalUrlOverride, _postponed] = param;
|
||||
let isFirstRead = false;
|
||||
// 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();
|
||||
isFirstRead = true;
|
||||
}
|
||||
// Handle case when navigating to page in `pages` from `app`
|
||||
if (typeof flightData === "string") {
|
||||
return handleExternalUrl(state, mutable, flightData, pendingPush);
|
||||
}
|
||||
// Handles case where `<meta http-equiv="refresh">` tag is present,
|
||||
// which will trigger an MPA navigation.
|
||||
if (document.getElementById("__next-page-redirect")) {
|
||||
return handleExternalUrl(state, mutable, href, pendingPush);
|
||||
}
|
||||
let currentTree = state.tree;
|
||||
let currentCache = state.cache;
|
||||
let scrollableSegments = [];
|
||||
// TODO: In practice, this is always a single item array. We probably
|
||||
// aren't going to every send multiple segments, at least not in this
|
||||
// format. So we could remove the extra wrapper for now until
|
||||
// that settles.
|
||||
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, href);
|
||||
// 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, href);
|
||||
}
|
||||
if (newTree !== null) {
|
||||
if ((0, _isnavigatingtonewrootlayout.isNavigatingToNewRootLayout)(currentTree, newTree)) {
|
||||
return handleExternalUrl(state, mutable, href, pendingPush);
|
||||
}
|
||||
if (// This is just a paranoid check. When PPR is enabled, the server
|
||||
// will always send back a static response that's rendered from
|
||||
// the root. If for some reason it doesn't, we fall back to the
|
||||
// non-PPR implementation.
|
||||
// TODO: We should get rid of the else branch and do all navigations
|
||||
// via updateCacheNodeOnNavigation. The current structure is just
|
||||
// an incremental step.
|
||||
flightDataPath.length === 3) {
|
||||
const prefetchedTree = flightDataPath[0];
|
||||
const seedData = flightDataPath[1];
|
||||
const head = flightDataPath[2];
|
||||
const task = (0, _pprnavigations.updateCacheNodeOnNavigation)(currentCache, currentTree, prefetchedTree, seedData, head);
|
||||
if (task !== null && task.node !== null) {
|
||||
// We've created a new Cache Node tree that contains a prefetched
|
||||
// version of the next page. This can be rendered instantly.
|
||||
// Use the tree computed by updateCacheNodeOnNavigation instead
|
||||
// of the one computed by applyRouterStatePatchToTree.
|
||||
// TODO: We should remove applyRouterStatePatchToTree
|
||||
// from the PPR path entirely.
|
||||
const patchedRouterState = task.route;
|
||||
newTree = patchedRouterState;
|
||||
const newCache = task.node;
|
||||
// The prefetched tree has dynamic holes in it. We initiate a
|
||||
// dynamic request to fill them in.
|
||||
//
|
||||
// Do not block on the result. We'll immediately render the Cache
|
||||
// Node tree and suspend on the dynamic parts. When the request
|
||||
// comes in, we'll fill in missing data and ping React to
|
||||
// re-render. Unlike the lazy fetching model in the non-PPR
|
||||
// implementation, this is modeled as a single React update +
|
||||
// streaming, rather than multiple top-level updates. (However,
|
||||
// even in the new model, we'll still need to sometimes update the
|
||||
// root multiple times per navigation, like if the server sends us
|
||||
// a different response than we expected. For now, we revert back
|
||||
// to the lazy fetching mechanism in that case.)
|
||||
(0, _pprnavigations.listenForDynamicRequest)(task, (0, _fetchserverresponse.fetchServerResponse)(url, currentTree, state.nextUrl, state.buildId));
|
||||
mutable.cache = newCache;
|
||||
} else {
|
||||
// Nothing changed, so reuse the old cache.
|
||||
// TODO: What if the head changed but not any of the segment data?
|
||||
// Is that possible? If so, we should clone the whole tree and
|
||||
// update the head.
|
||||
newTree = prefetchedTree;
|
||||
}
|
||||
} else {
|
||||
// The static response does not include any dynamic holes, so
|
||||
// there's no need to do a second request.
|
||||
// TODO: As an incremental step this just reverts back to the
|
||||
// non-PPR implementation. We can simplify this branch further,
|
||||
// given that PPR prefetches are always static and return the whole
|
||||
// tree. Or in the meantime we could factor it out into a
|
||||
// separate function.
|
||||
const cache = (0, _approuter.createEmptyCacheNode)();
|
||||
let applied = false;
|
||||
if (prefetchValues.status === _routerreducertypes.PrefetchCacheEntryStatus.stale && !isFirstRead) {
|
||||
// When we have a stale prefetch entry, we only want to re-use the loading state of the route we're navigating to, to support instant loading navigations
|
||||
// this will trigger a lazy fetch for the actual page data by nulling the `rsc` and `prefetchRsc` values for page data,
|
||||
// while copying over the `loading` for the segment that contains the page data.
|
||||
// We only do this on subsequent reads, as otherwise there'd be no loading data to re-use.
|
||||
applied = triggerLazyFetchForLeafSegments(cache, currentCache, flightSegmentPath, treePatch);
|
||||
// since we re-used the stale cache's loading state & refreshed the data,
|
||||
// update the `lastUsedTime` so that it can continue to be re-used for the next 30s
|
||||
prefetchValues.lastUsedTime = Date.now();
|
||||
} else {
|
||||
applied = (0, _applyflightdata.applyFlightData)(currentCache, cache, flightDataPath, prefetchValues);
|
||||
}
|
||||
const hardNavigate = (0, _shouldhardnavigate.shouldHardNavigate)(// TODO-APP: remove ''
|
||||
flightSegmentPathWithLeadingEmpty, currentTree);
|
||||
if (hardNavigate) {
|
||||
// Copy rsc for the root node of the cache.
|
||||
cache.rsc = currentCache.rsc;
|
||||
cache.prefetchRsc = currentCache.prefetchRsc;
|
||||
(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;
|
||||
// If we applied the cache, we update the "current cache" value so any other
|
||||
// segments in the FlightDataPath will be able to reference the updated 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] !== _segment.DEFAULT_SEGMENT_KEY) {
|
||||
scrollableSegments.push(scrollableSegmentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}, ()=>state);
|
||||
}
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user