next
Version:
The React Framework
241 lines (240 loc) • 10.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
anySegmentHasPartialPrefetchingEnabled: null,
anySegmentNeedsInstantValidationInBuild: null,
anySegmentNeedsInstantValidationInDev: null,
isFrameworkErrorRoute: null,
isImplicitValidationSegment: null,
isPageAllowedToBlock: null,
resolveInstantConfigSamplesForPage: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
anySegmentHasPartialPrefetchingEnabled: function() {
return anySegmentHasPartialPrefetchingEnabled;
},
anySegmentNeedsInstantValidationInBuild: function() {
return anySegmentNeedsInstantValidationInBuild;
},
anySegmentNeedsInstantValidationInDev: function() {
return anySegmentNeedsInstantValidationInDev;
},
isFrameworkErrorRoute: function() {
return isFrameworkErrorRoute;
},
isImplicitValidationSegment: function() {
return isImplicitValidationSegment;
},
isPageAllowedToBlock: function() {
return isPageAllowedToBlock;
},
resolveInstantConfigSamplesForPage: function() {
return resolveInstantConfigSamplesForPage;
}
});
const _appdirmodule = require("../../lib/app-dir-module");
const _parseloadertree = require("../../../shared/lib/router/utils/parse-loader-tree");
const _segment = require("../../../shared/lib/segment");
const _entryconstants = require("../../../shared/lib/entry-constants");
const _workasyncstorageexternal = require("../work-async-storage.external");
const _invarianterror = require("../../../shared/lib/invariant-error");
function isImplicitValidationSegment(segment) {
const key = typeof segment === 'string' ? segment : segment[0];
return key === _segment.PAGE_SEGMENT_KEY || key.startsWith(_segment.PAGE_SEGMENT_KEY) || key === _segment.DEFAULT_SEGMENT_KEY;
}
function isFrameworkErrorRoute(route) {
return route === _entryconstants.UNDERSCORE_GLOBAL_ERROR_ROUTE || route === _entryconstants.UNDERSCORE_NOT_FOUND_ROUTE;
}
async function anySegmentHasPartialPrefetchingEnabled(tree) {
const { mod: layoutOrPageMod } = await (0, _appdirmodule.getLayoutOrPageModule)(tree);
// TODO(restart-on-cache-miss): Does this work correctly for client page/layout modules?
const prefetchConfig = layoutOrPageMod ? layoutOrPageMod.prefetch : undefined;
if (prefetchConfig === 'partial' || prefetchConfig === 'unstable_eager') {
return true;
}
const { parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree);
for(const parallelRouteKey in parallelRoutes){
const parallelRoute = parallelRoutes[parallelRouteKey];
const hasChildPartialPrefetching = await anySegmentHasPartialPrefetchingEnabled(parallelRoute);
if (hasChildPartialPrefetching) {
return true;
}
}
return false;
}
async function isPageAllowedToBlock(tree) {
const { mod: layoutOrPageMod } = await (0, _appdirmodule.getLayoutOrPageModule)(tree);
// TODO(restart-on-cache-miss): Does this work correctly for client page/layout modules?
const instantConfig = layoutOrPageMod ? layoutOrPageMod.instant : undefined;
// If we encounter a non-false instant config before a instant=false,
// the page isn't allowed to block. The config expresses a requirement for
// instant UI, so we should make sure that a static shell exists.
// (even if it'd use runtime prefetching for client navs)
if (instantConfig !== undefined) {
if (instantConfig === false) {
return true;
} else {
return false;
}
}
const { parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree);
for(const parallelRouteKey in parallelRoutes){
const parallelRoute = parallelRoutes[parallelRouteKey];
const subtreeIsBlocking = await isPageAllowedToBlock(parallelRoute);
if (subtreeIsBlocking) {
return true;
}
}
return false;
}
var VALIDATION_LEVEL = /*#__PURE__*/ function(VALIDATION_LEVEL) {
VALIDATION_LEVEL[VALIDATION_LEVEL["WARNING"] = 0] = "WARNING";
VALIDATION_LEVEL[VALIDATION_LEVEL["ERROR"] = 1] = "ERROR";
return VALIDATION_LEVEL;
}(VALIDATION_LEVEL || {});
/**
* Walks the loader tree and checks if any segment has an `instant` config
* that needs validating for the given mode.
*
* - Explicit `instant` exports are checked against mode.
* - Page and default segments without an explicit config get implicit
* validation when the default validation level applies to this mode.
* - `unstable_disableValidation` on any segment kills validation for
* the whole tree.
*/ async function anySegmentNeedsInstantValidation(rootTree, level) {
const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();
if (!workStore) {
throw Object.defineProperty(new _invarianterror.InvariantError('anySegmentNeedsInstantValidation must run inside a WorkStore'), "__NEXT_ERROR_CODE", {
value: "E1185",
enumerable: false,
configurable: true
});
}
const { validationLevel } = workStore;
let baseValidationLevel = 0;
let manualValidation = false;
switch(validationLevel){
case 'manual-warning':
manualValidation = true;
// intentional fallthrough
case 'warning':
baseValidationLevel = 0;
break;
case 'experimental-manual-error':
manualValidation = true;
// intentional fallthrough
case 'experimental-error':
baseValidationLevel = 1;
break;
default:
validationLevel;
}
const applyDefaultValidation = // We need to be validating the right level
level <= baseValidationLevel && // We need to not be in manual validation mode
!manualValidation && // We don't validate framework internal routes by default
!isFrameworkErrorRoute(workStore.route);
let needsValidation = false;
let disabled = false;
async function visit(tree) {
if (disabled) return;
const { mod: layoutOrPageMod } = await (0, _appdirmodule.getLayoutOrPageModule)(tree);
const instantConfig = layoutOrPageMod ? layoutOrPageMod.instant : undefined;
if (instantConfig === false) {
// Explicit opt-out. Doesn't itself trigger validation.
} else if (instantConfig === true) {
// Explicit opt-in using the default level.
if (level <= baseValidationLevel) {
needsValidation = true;
}
} else if (typeof instantConfig === 'object' && instantConfig !== null) {
if (instantConfig.unstable_disableValidation === true || level === 0 && instantConfig.unstable_disableDevValidation === true || level === 1 && instantConfig.unstable_disableBuildValidation === true) {
disabled = true;
return;
}
if (instantConfig.level !== undefined) {
const configuredLevel = instantConfig.level === 'experimental-error' ? 1 : 0;
if (level <= configuredLevel) {
needsValidation = true;
}
} else if (level <= baseValidationLevel) {
needsValidation = true;
}
} else if (applyDefaultValidation && isImplicitValidationSegment(tree[0])) {
// No explicit config. Implicit validation applies to page/default
// segments when the default level is active for this mode.
needsValidation = true;
}
const { parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree);
for(const parallelRouteKey in parallelRoutes){
await visit(parallelRoutes[parallelRouteKey]);
if (disabled) return;
}
}
await visit(rootTree);
if (disabled) {
return false;
}
return needsValidation;
}
const anySegmentNeedsInstantValidationInDev = cacheScopedToWorkStore(async (rootTree)=>anySegmentNeedsInstantValidation(rootTree, 0));
const anySegmentNeedsInstantValidationInBuild = cacheScopedToWorkStore(async (rootTree)=>anySegmentNeedsInstantValidation(rootTree, 1));
const resolveInstantConfigSamplesForPage = async (tree)=>{
const { mod: layoutOrPageMod } = await (0, _appdirmodule.getLayoutOrPageModule)(tree);
const instantConfig = layoutOrPageMod ? layoutOrPageMod.instant : undefined;
let samples = null;
if (instantConfig !== undefined && typeof instantConfig === 'object' && instantConfig.unstable_samples) {
samples = instantConfig.unstable_samples;
}
// The samples from inner segments override samples from outer segments,
// i.e. a page overrides the samples from a layout.
// We do not perform any merging logic.
const { parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree);
for(const parallelRouteKey in parallelRoutes){
if (parallelRouteKey !== 'children') {
continue;
}
const childTree = parallelRoutes[parallelRouteKey];
const childSamples = await resolveInstantConfigSamplesForPage(childTree);
if (childSamples !== null) {
samples = childSamples;
}
}
return samples;
};
/**
* A simple cache wrapper for 1-argument functions.
* The cache will live as long as the current WorkStore,
* i.e. it's scoped to a single request.
*/ function cacheScopedToWorkStore(func) {
const resultsPerWorkStore = new WeakMap();
return (arg)=>{
const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();
if (!workStore) {
throw Object.defineProperty(new _invarianterror.InvariantError(`${func.name || 'cacheScopedToWorkStore callee'} must run inside a WorkStore`), "__NEXT_ERROR_CODE", {
value: "E1186",
enumerable: false,
configurable: true
});
}
let results = resultsPerWorkStore.get(workStore);
if (results && results.has(arg)) {
return results.get(arg);
}
const result = func(arg);
if (!results) {
results = new WeakMap();
resultsPerWorkStore.set(workStore, results);
}
results.set(arg, result);
return result;
};
}
//# sourceMappingURL=instant-config.js.map