next
Version:
The React Framework
336 lines (335 loc) • 12.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
accumulateRootVaryParam: null,
accumulateVaryParam: null,
createResponseVaryParamsAccumulator: null,
createVaryParamsAccumulator: null,
createVaryingParams: null,
createVaryingSearchParams: null,
emptyVaryParamsAccumulator: null,
finishAccumulatingVaryParams: null,
getMetadataVaryParamsAccumulator: null,
getMetadataVaryParamsThenable: null,
getRootParamsVaryParamsAccumulator: null,
getVaryParamsThenable: null,
getViewportVaryParamsAccumulator: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
accumulateRootVaryParam: function() {
return accumulateRootVaryParam;
},
accumulateVaryParam: function() {
return accumulateVaryParam;
},
createResponseVaryParamsAccumulator: function() {
return createResponseVaryParamsAccumulator;
},
createVaryParamsAccumulator: function() {
return createVaryParamsAccumulator;
},
createVaryingParams: function() {
return createVaryingParams;
},
createVaryingSearchParams: function() {
return createVaryingSearchParams;
},
emptyVaryParamsAccumulator: function() {
return emptyVaryParamsAccumulator;
},
finishAccumulatingVaryParams: function() {
return finishAccumulatingVaryParams;
},
getMetadataVaryParamsAccumulator: function() {
return getMetadataVaryParamsAccumulator;
},
getMetadataVaryParamsThenable: function() {
return getMetadataVaryParamsThenable;
},
getRootParamsVaryParamsAccumulator: function() {
return getRootParamsVaryParamsAccumulator;
},
getVaryParamsThenable: function() {
return getVaryParamsThenable;
},
getViewportVaryParamsAccumulator: function() {
return getViewportVaryParamsAccumulator;
}
});
const _workunitasyncstorageexternal = require("./work-unit-async-storage.external");
function createSegmentVaryParamsAccumulator() {
const accumulator = {
varyParams: new Set(),
status: 'pending',
value: new Set(),
then (onfulfilled) {
if (onfulfilled) {
if (accumulator.status === 'pending') {
accumulator.resolvers.push(onfulfilled);
} else {
onfulfilled(accumulator.value);
}
}
},
resolvers: []
};
return accumulator;
}
/**
* A singleton accumulator that's already resolved to an empty Set. Use this for
* segments where we know upfront that no params will be accessed, such as
* client components or segments without user code.
*
* Benefits:
* - No need to accumulate or resolve later
* - Resilient: resolves correctly even if other tracking fails
* - Memory efficient: reuses the same object
*/ const emptySet = new Set();
const emptyVaryParamsAccumulator = {
varyParams: emptySet,
status: 'fulfilled',
value: emptySet,
then (onfulfilled) {
if (onfulfilled) {
onfulfilled(emptySet);
}
},
resolvers: []
};
function createResponseVaryParamsAccumulator() {
// Create the head and rootParams accumulators as top-level fields.
// Segment accumulators are added to the segments set as they are created.
const head = createSegmentVaryParamsAccumulator();
const rootParams = createSegmentVaryParamsAccumulator();
const segments = new Set();
return {
head,
rootParams,
segments
};
}
function createVaryParamsAccumulator() {
const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();
if (workUnitStore) {
switch(workUnitStore.type){
case 'prerender':
case 'prerender-runtime':
{
const responseAccumulator = workUnitStore.varyParamsAccumulator;
if (responseAccumulator !== null) {
const accumulator = createSegmentVaryParamsAccumulator();
responseAccumulator.segments.add(accumulator);
return accumulator;
}
return null;
}
case 'prerender-ppr':
case 'prerender-legacy':
case 'request':
case 'cache':
case 'private-cache':
case 'prerender-client':
case 'validation-client':
case 'unstable-cache':
case 'generate-static-params':
break;
default:
workUnitStore;
}
}
return null;
}
function getMetadataVaryParamsAccumulator() {
const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();
if (workUnitStore) {
switch(workUnitStore.type){
case 'prerender':
case 'prerender-runtime':
{
const responseAccumulator = workUnitStore.varyParamsAccumulator;
if (responseAccumulator !== null) {
return responseAccumulator.head;
}
return null;
}
case 'prerender-ppr':
case 'prerender-legacy':
case 'request':
case 'cache':
case 'private-cache':
case 'prerender-client':
case 'validation-client':
case 'unstable-cache':
case 'generate-static-params':
return null;
default:
workUnitStore;
}
}
return null;
}
function getVaryParamsThenable(accumulator) {
return accumulator;
}
function getMetadataVaryParamsThenable() {
const accumulator = getMetadataVaryParamsAccumulator();
if (accumulator !== null) {
return getVaryParamsThenable(accumulator);
}
return null;
}
const getViewportVaryParamsAccumulator = getMetadataVaryParamsAccumulator;
function getRootParamsVaryParamsAccumulator() {
const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();
if (workUnitStore) {
switch(workUnitStore.type){
case 'prerender':
case 'prerender-runtime':
{
const responseAccumulator = workUnitStore.varyParamsAccumulator;
if (responseAccumulator !== null) {
return responseAccumulator.rootParams;
}
return null;
}
case 'prerender-ppr':
case 'prerender-legacy':
case 'request':
case 'cache':
case 'private-cache':
case 'prerender-client':
case 'validation-client':
case 'unstable-cache':
case 'generate-static-params':
return null;
default:
workUnitStore;
}
}
return null;
}
function accumulateVaryParam(accumulator, paramName) {
accumulator.varyParams.add(paramName);
}
function accumulateRootVaryParam(paramName) {
const rootParamsAccumulator = getRootParamsVaryParamsAccumulator();
if (rootParamsAccumulator !== null) {
accumulateVaryParam(rootParamsAccumulator, paramName);
}
}
function createVaryingParams(accumulator, originalParamsObject, optionalCatchAllParamName) {
if (optionalCatchAllParamName !== null) {
// When there's an optional catch-all param with no value (e.g.,
// [[...slug]] at /), the param doesn't exist as a property on the params
// object. Use a Proxy to track all param access — both existing params
// and the missing optional param — including enumeration patterns like
// Object.keys(), spread, for...in, and `in` checks.
return new Proxy(originalParamsObject, {
get (target, prop, receiver) {
if (typeof prop === 'string') {
if (prop === optionalCatchAllParamName || Object.prototype.hasOwnProperty.call(target, prop)) {
accumulateVaryParam(accumulator, prop);
}
}
return Reflect.get(target, prop, receiver);
},
has (target, prop) {
if (prop === optionalCatchAllParamName) {
accumulateVaryParam(accumulator, optionalCatchAllParamName);
}
return Reflect.has(target, prop);
},
ownKeys (target) {
// Enumerating the params object means the user's code may depend on
// which params are present, so conservatively track the optional
// param as accessed.
accumulateVaryParam(accumulator, optionalCatchAllParamName);
return Reflect.ownKeys(target);
}
});
}
// When there's no optional catch-all, all params exist as properties on the
// object, so we can use defineProperty getters instead of a Proxy. This is
// faster because the engine can optimize property access on regular objects
// more aggressively than Proxy trap calls.
const underlyingParamsWithVarying = {};
for(const paramName in originalParamsObject){
Object.defineProperty(underlyingParamsWithVarying, paramName, {
get () {
accumulateVaryParam(accumulator, paramName);
return originalParamsObject[paramName];
},
enumerable: true
});
}
return underlyingParamsWithVarying;
}
function createVaryingSearchParams(accumulator, originalSearchParamsObject) {
const underlyingSearchParamsWithVarying = {};
for(const searchParamName in originalSearchParamsObject){
Object.defineProperty(underlyingSearchParamsWithVarying, searchParamName, {
get () {
// TODO: Unlike path params, we don't vary track each search param
// individually. The entire search string is treated as a single param.
// This may change in the future.
accumulateVaryParam(accumulator, '?');
return originalSearchParamsObject[searchParamName];
},
enumerable: true
});
}
return underlyingSearchParamsWithVarying;
}
async function finishAccumulatingVaryParams(responseAccumulator) {
const rootVaryParams = responseAccumulator.rootParams.varyParams;
// Resolve head
finishSegmentAccumulator(responseAccumulator.head, rootVaryParams);
// Resolve each segment
for (const segmentAccumulator of responseAccumulator.segments){
finishSegmentAccumulator(segmentAccumulator, rootVaryParams);
}
// Now that the thenables are resolved, Flight should be able to flush the
// vary params into the response stream. This work gets scheduled internally
// by Flight using a microtask as soon as we notify the thenable listeners.
//
// We need to ensure that Flight's pending queues are emptied before this
// function returns; the caller will abort the prerender immediately after.
// We can't use a macrotask, because that would allow dynamic IO to sneak
// into the response. So we use microtasks instead.
//
// The exact number of awaits here isn't important (indeed, one seems to be
// sufficient, at the time of writing), as long as we wait enough ticks for
// Flight to finish writing the response.
//
// Anything that remains in Flight's internal queue after these awaits must
// be actual dynamic IO, not caused by pending vary params tasks. In other
// words, failing to do this would cause us to treat a fully static prerender
// as if it were partially dynamic.
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
}
function finishSegmentAccumulator(accumulator, rootVaryParams) {
if (accumulator.status !== 'pending') {
return;
}
const merged = new Set(accumulator.varyParams);
for (const param of rootVaryParams){
merged.add(param);
}
accumulator.value = merged;
accumulator.status = 'fulfilled';
for (const resolver of accumulator.resolvers){
resolver(merged);
}
accumulator.resolvers = [];
}
//# sourceMappingURL=vary-params.js.map