UNPKG

next

Version:

The React Framework

158 lines (157 loc) • 7.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return ResponseCache; } }); 0 && __export(require("./types")); const _batcher = require("../../lib/batcher"); const _scheduler = require("../../lib/scheduler"); const _utils = require("./utils"); _export_star(require("./types"), exports); function _export_star(from, to) { Object.keys(from).forEach(function(k) { if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { Object.defineProperty(to, k, { enumerable: true, get: function() { return from[k]; } }); } }); return from; } class ResponseCache { constructor(minimalMode){ this.batcher = _batcher.Batcher.create({ // Ensure on-demand revalidate doesn't block normal requests, it should be // safe to run an on-demand revalidate for the same key as a normal request. cacheKeyFn: ({ key, isOnDemandRevalidate })=>`${key}-${isOnDemandRevalidate ? '1' : '0'}`, // We wait to do any async work until after we've added our promise to // `pendingResponses` to ensure that any any other calls will reuse the // same promise until we've fully finished our work. schedulerFn: _scheduler.scheduleOnNextTick }); // this is a hack to avoid Webpack knowing this is equal to this.minimalMode // because we replace this.minimalMode to true in production bundles. const minimalModeKey = 'minimalMode'; this[minimalModeKey] = minimalMode; } async get(key, responseGenerator, context) { // If there is no key for the cache, we can't possibly look this up in the // cache so just return the result of the response generator. if (!key) { return responseGenerator({ hasResolved: false, previousCacheEntry: null }); } const { incrementalCache, isOnDemandRevalidate = false, isFallback = false, isRoutePPREnabled = false } = context; const response = await this.batcher.batch({ key, isOnDemandRevalidate }, async (cacheKey, resolve)=>{ var _this_previousCacheItem; // We keep the previous cache entry around to leverage when the // incremental cache is disabled in minimal mode. if (this.minimalMode && ((_this_previousCacheItem = this.previousCacheItem) == null ? void 0 : _this_previousCacheItem.key) === cacheKey && this.previousCacheItem.expiresAt > Date.now()) { return this.previousCacheItem.entry; } // Coerce the kindHint into a given kind for the incremental cache. const kind = (0, _utils.routeKindToIncrementalCacheKind)(context.routeKind); let resolved = false; let cachedResponse = null; try { cachedResponse = !this.minimalMode ? await incrementalCache.get(key, { kind, isRoutePPREnabled: context.isRoutePPREnabled, isFallback }) : null; if (cachedResponse && !isOnDemandRevalidate) { resolve(cachedResponse); resolved = true; if (!cachedResponse.isStale || context.isPrefetch) { // The cached value is still valid, so we don't need // to update it yet. return null; } } const cacheEntry = await responseGenerator({ hasResolved: resolved, previousCacheEntry: cachedResponse, isRevalidating: true }); // If the cache entry couldn't be generated, we don't want to cache // the result. if (!cacheEntry) { // Unset the previous cache item if it was set. if (this.minimalMode) this.previousCacheItem = undefined; return null; } const resolveValue = await (0, _utils.fromResponseCacheEntry)({ ...cacheEntry, isMiss: !cachedResponse }); if (!resolveValue) { // Unset the previous cache item if it was set. if (this.minimalMode) this.previousCacheItem = undefined; return null; } // For on-demand revalidate wait to resolve until cache is set. // Otherwise resolve now. if (!isOnDemandRevalidate && !resolved) { resolve(resolveValue); resolved = true; } // We want to persist the result only if it has a cache control value // defined. if (resolveValue.cacheControl) { if (this.minimalMode) { this.previousCacheItem = { key: cacheKey, entry: resolveValue, expiresAt: Date.now() + 1000 }; } else { await incrementalCache.set(key, resolveValue.value, { cacheControl: resolveValue.cacheControl, isRoutePPREnabled, isFallback }); } } return resolveValue; } catch (err) { // When a path is erroring we automatically re-set the existing cache // with new revalidate and expire times to prevent non-stop retrying. if (cachedResponse == null ? void 0 : cachedResponse.cacheControl) { const newRevalidate = Math.min(Math.max(cachedResponse.cacheControl.revalidate || 3, 3), 30); const newExpire = cachedResponse.cacheControl.expire === undefined ? undefined : Math.max(newRevalidate + 3, cachedResponse.cacheControl.expire); await incrementalCache.set(key, cachedResponse.value, { cacheControl: { revalidate: newRevalidate, expire: newExpire }, isRoutePPREnabled, isFallback }); } // While revalidating in the background we can't reject as we already // resolved the cache entry so log the error here. if (resolved) { console.error(err); return null; } // We haven't resolved yet, so let's throw to indicate an error. throw err; } }); return (0, _utils.toResponseCacheEntry)(response); } } //# sourceMappingURL=index.js.map