UNPKG

next

Version:

The React Framework

336 lines (335 loc) 12.5 kB
"use strict"; 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