next
Version:
The React Framework
204 lines (203 loc) • 10.1 kB
JavaScript
import { getExpectedRequestStore } from '../app-render/work-unit-async-storage.external';
import { workAsyncStorage } from '../app-render/work-async-storage.external';
import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external';
import { abortAndThrowOnSynchronousRequestDataAccess, postponeWithTracking, trackSynchronousRequestDataAccessInDev } from '../app-render/dynamic-rendering';
import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger';
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout';
import { DynamicServerError } from '../../client/components/hooks-server-context';
export function draftMode() {
const callingExpression = 'draftMode';
const workStore = workAsyncStorage.getStore();
const workUnitStore = workUnitAsyncStorage.getStore();
if (workUnitStore) {
if (workUnitStore.type === 'cache' || workUnitStore.type === 'unstable-cache' || workUnitStore.type === 'prerender' || workUnitStore.type === 'prerender-ppr' || workUnitStore.type === 'prerender-legacy') {
// Return empty draft mode
if (process.env.NODE_ENV === 'development' && !(workStore == null ? void 0 : workStore.isPrefetchRequest)) {
const route = workStore == null ? void 0 : workStore.route;
return createExoticDraftModeWithDevWarnings(null, route);
} else {
return createExoticDraftMode(null);
}
}
}
const requestStore = getExpectedRequestStore(callingExpression);
const cachedDraftMode = CachedDraftModes.get(requestStore.draftMode);
if (cachedDraftMode) {
return cachedDraftMode;
}
let promise;
if (process.env.NODE_ENV === 'development' && !(workStore == null ? void 0 : workStore.isPrefetchRequest)) {
const route = workStore == null ? void 0 : workStore.route;
promise = createExoticDraftModeWithDevWarnings(requestStore.draftMode, route);
} else {
promise = createExoticDraftMode(requestStore.draftMode);
}
CachedDraftModes.set(requestStore.draftMode, promise);
return promise;
}
const CachedDraftModes = new WeakMap();
function createExoticDraftMode(underlyingProvider) {
const instance = new DraftMode(underlyingProvider);
const promise = Promise.resolve(instance);
Object.defineProperty(promise, 'isEnabled', {
get () {
return instance.isEnabled;
},
set (newValue) {
Object.defineProperty(promise, 'isEnabled', {
value: newValue,
writable: true,
enumerable: true
});
},
enumerable: true,
configurable: true
});
promise.enable = instance.enable.bind(instance);
promise.disable = instance.disable.bind(instance);
return promise;
}
function createExoticDraftModeWithDevWarnings(underlyingProvider, route) {
const instance = new DraftMode(underlyingProvider);
const promise = Promise.resolve(instance);
Object.defineProperty(promise, 'isEnabled', {
get () {
const expression = '`draftMode().isEnabled`';
syncIODev(route, expression);
return instance.isEnabled;
},
set (newValue) {
Object.defineProperty(promise, 'isEnabled', {
value: newValue,
writable: true,
enumerable: true
});
},
enumerable: true,
configurable: true
});
Object.defineProperty(promise, 'enable', {
value: function get() {
const expression = '`draftMode().enable()`';
syncIODev(route, expression);
return instance.enable.apply(instance, arguments);
}
});
Object.defineProperty(promise, 'disable', {
value: function get() {
const expression = '`draftMode().disable()`';
syncIODev(route, expression);
return instance.disable.apply(instance, arguments);
}
});
return promise;
}
class DraftMode {
constructor(provider){
this._provider = provider;
}
get isEnabled() {
if (this._provider !== null) {
return this._provider.isEnabled;
}
return false;
}
enable() {
// We have a store we want to track dynamic data access to ensure we
// don't statically generate routes that manipulate draft mode.
trackDynamicDraftMode('draftMode().enable()');
if (this._provider !== null) {
this._provider.enable();
}
}
disable() {
trackDynamicDraftMode('draftMode().disable()');
if (this._provider !== null) {
this._provider.disable();
}
}
}
function syncIODev(route, expression) {
const workUnitStore = workUnitAsyncStorage.getStore();
if (workUnitStore && workUnitStore.type === 'request' && workUnitStore.prerenderPhase === true) {
// When we're rendering dynamically in dev we need to advance out of the
// Prerender environment when we read Request data synchronously
const requestStore = workUnitStore;
trackSynchronousRequestDataAccessInDev(requestStore);
}
// In all cases we warn normally
warnForSyncAccess(route, expression);
}
const warnForSyncAccess = createDedupedByCallsiteServerErrorLoggerDev(createDraftModeAccessError);
function createDraftModeAccessError(route, expression) {
const prefix = route ? `Route "${route}" ` : 'This route ';
return Object.defineProperty(new Error(`${prefix}used ${expression}. ` + `\`draftMode()\` should be awaited before using its value. ` + `Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`), "__NEXT_ERROR_CODE", {
value: "E377",
enumerable: false,
configurable: true
});
}
function trackDynamicDraftMode(expression) {
const store = workAsyncStorage.getStore();
const workUnitStore = workUnitAsyncStorage.getStore();
if (store) {
// We have a store we want to track dynamic data access to ensure we
// don't statically generate routes that manipulate draft mode.
if (workUnitStore) {
if (workUnitStore.type === 'cache') {
throw Object.defineProperty(new Error(`Route ${store.route} used "${expression}" inside "use cache". The enabled status of draftMode can be read in caches but you must not enable or disable draftMode inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`), "__NEXT_ERROR_CODE", {
value: "E246",
enumerable: false,
configurable: true
});
} else if (workUnitStore.type === 'unstable-cache') {
throw Object.defineProperty(new Error(`Route ${store.route} used "${expression}" inside a function cached with "unstable_cache(...)". The enabled status of draftMode can be read in caches but you must not enable or disable draftMode inside a cache. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`), "__NEXT_ERROR_CODE", {
value: "E259",
enumerable: false,
configurable: true
});
} else if (workUnitStore.phase === 'after') {
throw Object.defineProperty(new Error(`Route ${store.route} used "${expression}" inside \`after\`. The enabled status of draftMode can be read inside \`after\` but you cannot enable or disable draftMode. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`), "__NEXT_ERROR_CODE", {
value: "E348",
enumerable: false,
configurable: true
});
}
}
if (store.dynamicShouldError) {
throw Object.defineProperty(new StaticGenBailoutError(`Route ${store.route} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), "__NEXT_ERROR_CODE", {
value: "E553",
enumerable: false,
configurable: true
});
}
if (workUnitStore) {
if (workUnitStore.type === 'prerender') {
// dynamicIO Prerender
const error = Object.defineProperty(new Error(`Route ${store.route} used ${expression} without first calling \`await connection()\`. See more info here: https://nextjs.org/docs/messages/next-prerender-sync-headers`), "__NEXT_ERROR_CODE", {
value: "E126",
enumerable: false,
configurable: true
});
abortAndThrowOnSynchronousRequestDataAccess(store.route, expression, error, workUnitStore);
} else if (workUnitStore.type === 'prerender-ppr') {
// PPR Prerender
postponeWithTracking(store.route, expression, workUnitStore.dynamicTracking);
} else if (workUnitStore.type === 'prerender-legacy') {
// legacy Prerender
workUnitStore.revalidate = 0;
const err = Object.defineProperty(new DynamicServerError(`Route ${store.route} couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`), "__NEXT_ERROR_CODE", {
value: "E558",
enumerable: false,
configurable: true
});
store.dynamicUsageDescription = expression;
store.dynamicUsageStack = err.stack;
throw err;
} else if (process.env.NODE_ENV === 'development' && workUnitStore && workUnitStore.type === 'request') {
workUnitStore.usedDynamic = true;
}
}
}
}
//# sourceMappingURL=draft-mode.js.map