next
Version:
The React Framework
164 lines (163 loc) • 7.07 kB
JavaScript
import { FetchStrategy } from './types';
import { Fallback } from './cache-map';
import { HEAD_REQUEST_KEY } from '../../../shared/lib/segment-cache/segment-value-encoding';
export function getRouteVaryPath(pathname, search, nextUrl) {
// requestKey -> searchParams -> nextUrl
const varyPath = {
value: pathname,
parent: {
value: search,
parent: {
value: nextUrl,
parent: null
}
}
};
return varyPath;
}
export function getFulfilledRouteVaryPath(pathname, search, nextUrl, couldBeIntercepted) {
// This is called when a route's data is fulfilled. The cache entry will be
// re-keyed based on which inputs the response varies by.
// requestKey -> searchParams -> nextUrl
const varyPath = {
value: pathname,
parent: {
value: search,
parent: {
value: couldBeIntercepted ? nextUrl : Fallback,
parent: null
}
}
};
return varyPath;
}
export function appendLayoutVaryPath(parentPath, cacheKey) {
const varyPathPart = {
value: cacheKey,
parent: parentPath
};
return varyPathPart;
}
export function finalizeLayoutVaryPath(requestKey, varyPath) {
const layoutVaryPath = {
value: requestKey,
parent: varyPath
};
return layoutVaryPath;
}
export function finalizePageVaryPath(requestKey, renderedSearch, varyPath) {
// Unlike layouts, a page segment's vary path also includes the search string.
// requestKey -> searchParams -> pathParams
const pageVaryPath = {
value: requestKey,
parent: {
value: renderedSearch,
parent: varyPath
}
};
return pageVaryPath;
}
export function finalizeMetadataVaryPath(pageRequestKey, renderedSearch, varyPath) {
// The metadata "segment" is not a real segment because it doesn't exist in
// the normal structure of the route tree, but in terms of caching, it
// behaves like a page segment because it varies by all the same params as
// a page.
//
// To keep the protocol for querying the server simple, the request key for
// the metadata does not include any path information. It's unnecessary from
// the server's perspective, because unlike page segments, there's only one
// metadata response per URL, i.e. there's no need to distinguish multiple
// parallel pages.
//
// However, this means the metadata request key is insufficient for
// caching the the metadata in the client cache, because on the client we
// use the request key to distinguish the metadata entry from all other
// page's metadata entries.
//
// So instead we create a simulated request key based on the page segment.
// Conceptually this is equivalent to the request key the server would have
// assigned the metadata segment if it treated it as part of the actual
// route structure.
// If there are multiple parallel pages, we use whichever is the first one.
// This is fine because the only difference between request keys for
// different parallel pages are things like route groups and parallel
// route slots. As long as it's always the same one, it doesn't matter.
const pageVaryPath = {
// Append the actual metadata request key to the page request key. Note
// that we're not using a separate vary path part; it's unnecessary because
// these are not conceptually separate inputs.
value: pageRequestKey + HEAD_REQUEST_KEY,
parent: {
value: renderedSearch,
parent: varyPath
}
};
return pageVaryPath;
}
export function getSegmentVaryPathForRequest(fetchStrategy, tree) {
// This is used for storing pending requests in the cache. We want to choose
// the most generic vary path based on the strategy used to fetch it, i.e.
// static/PPR versus runtime prefetching, so that it can be reused as much
// as possible.
//
// We may be able to re-key the response to something even more generic once
// we receive it — for example, if the server tells us that the response
// doesn't vary on a particular param — but even before we send the request,
// we know some params are reusable based on the fetch strategy alone. For
// example, a static prefetch will never vary on search params.
//
// The original vary path with all the params filled in is stored on the
// route tree object. We will clone this one to create a new vary path
// where certain params are replaced with Fallback.
//
// This result of this function is not stored anywhere. It's only used to
// access the cache a single time.
//
// TODO: Rather than create a new list object just to access the cache, the
// plan is to add the concept of a "vary mask". This will represent all the
// params that can be treated as Fallback. (Or perhaps the inverse.)
const originalVaryPath = tree.varyPath;
// Only page segments (and the special "metadata" segment, which is treated
// like a page segment for the purposes of caching) may contain search
// params. There's no reason to include them in the vary path otherwise.
if (tree.isPage) {
// Only a runtime prefetch will include search params in the vary path.
// Static prefetches never include search params, so they can be reused
// across all possible search param values.
const doesVaryOnSearchParams = fetchStrategy === FetchStrategy.Full || fetchStrategy === FetchStrategy.PPRRuntime;
if (!doesVaryOnSearchParams) {
// The response from the the server will not vary on search params. Clone
// the end of the original vary path to replace the search params
// with Fallback.
//
// requestKey -> searchParams -> pathParams
// ^ This part gets replaced with Fallback
const searchParamsVaryPath = originalVaryPath.parent;
const pathParamsVaryPath = searchParamsVaryPath.parent;
const patchedVaryPath = {
value: originalVaryPath.value,
parent: {
value: Fallback,
parent: pathParamsVaryPath
}
};
return patchedVaryPath;
}
}
// The request does vary on search params. We don't need to modify anything.
return originalVaryPath;
}
export function clonePageVaryPathWithNewSearchParams(originalVaryPath, newSearch) {
// requestKey -> searchParams -> pathParams
// ^ This part gets replaced with newSearch
const searchParamsVaryPath = originalVaryPath.parent;
const clonedVaryPath = {
value: originalVaryPath.value,
parent: {
value: newSearch,
parent: searchParamsVaryPath.parent
}
};
return clonedVaryPath;
}
//# sourceMappingURL=vary-path.js.map