UNPKG

next

Version:

The React Framework

204 lines (203 loc) • 10.1 kB
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