rag-context-optimizer / frontend /node_modules /next /dist /esm /server /app-render /dynamic-rendering.js
| /** | |
| * The functions provided by this module are used to communicate certain properties | |
| * about the currently running code so that Next.js can make decisions on how to handle | |
| * the current execution in different rendering modes such as pre-rendering, resuming, and SSR. | |
| * | |
| * Today Next.js treats all code as potentially static. Certain APIs may only make sense when dynamically rendering. | |
| * Traditionally this meant deopting the entire render to dynamic however with PPR we can now deopt parts | |
| * of a React tree as dynamic while still keeping other parts static. There are really two different kinds of | |
| * Dynamic indications. | |
| * | |
| * The first is simply an intention to be dynamic. unstable_noStore is an example of this where | |
| * the currently executing code simply declares that the current scope is dynamic but if you use it | |
| * inside unstable_cache it can still be cached. This type of indication can be removed if we ever | |
| * make the default dynamic to begin with because the only way you would ever be static is inside | |
| * a cache scope which this indication does not affect. | |
| * | |
| * The second is an indication that a dynamic data source was read. This is a stronger form of dynamic | |
| * because it means that it is inappropriate to cache this at all. using a dynamic data source inside | |
| * unstable_cache should error. If you want to use some dynamic data inside unstable_cache you should | |
| * read that data outside the cache and pass it in as an argument to the cached function. | |
| */ // Once postpone is in stable we should switch to importing the postpone export directly | |
| import React from 'react'; | |
| import { DynamicServerError } from '../../client/components/hooks-server-context'; | |
| import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'; | |
| import { getRuntimeStagePromise, workUnitAsyncStorage } from './work-unit-async-storage.external'; | |
| import { workAsyncStorage } from '../app-render/work-async-storage.external'; | |
| import { makeHangingPromise } from '../dynamic-rendering-utils'; | |
| import { METADATA_BOUNDARY_NAME, VIEWPORT_BOUNDARY_NAME, OUTLET_BOUNDARY_NAME, ROOT_LAYOUT_BOUNDARY_NAME } from '../../lib/framework/boundary-constants'; | |
| import { scheduleOnNextTick } from '../../lib/scheduler'; | |
| import { BailoutToCSRError } from '../../shared/lib/lazy-dynamic/bailout-to-csr'; | |
| import { InvariantError } from '../../shared/lib/invariant-error'; | |
| const hasPostpone = typeof React.unstable_postpone === 'function'; | |
| export function createDynamicTrackingState(isDebugDynamicAccesses) { | |
| return { | |
| isDebugDynamicAccesses, | |
| dynamicAccesses: [], | |
| syncDynamicErrorWithStack: null | |
| }; | |
| } | |
| export function createDynamicValidationState() { | |
| return { | |
| hasSuspenseAboveBody: false, | |
| hasDynamicMetadata: false, | |
| hasDynamicViewport: false, | |
| hasAllowedDynamic: false, | |
| dynamicErrors: [] | |
| }; | |
| } | |
| export function getFirstDynamicReason(trackingState) { | |
| var _trackingState_dynamicAccesses_; | |
| return (_trackingState_dynamicAccesses_ = trackingState.dynamicAccesses[0]) == null ? void 0 : _trackingState_dynamicAccesses_.expression; | |
| } | |
| /** | |
| * This function communicates that the current scope should be treated as dynamic. | |
| * | |
| * In most cases this function is a no-op but if called during | |
| * a PPR prerender it will postpone the current sub-tree and calling | |
| * it during a normal prerender will cause the entire prerender to abort | |
| */ export function markCurrentScopeAsDynamic(store, workUnitStore, expression) { | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'cache': | |
| case 'unstable-cache': | |
| // Inside cache scopes, marking a scope as dynamic has no effect, | |
| // because the outer cache scope creates a cache boundary. This is | |
| // subtly different from reading a dynamic data source, which is | |
| // forbidden inside a cache scope. | |
| return; | |
| case 'private-cache': | |
| // A private cache scope is already dynamic by definition. | |
| return; | |
| case 'prerender-legacy': | |
| case 'prerender-ppr': | |
| case 'request': | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| // If we're forcing dynamic rendering or we're forcing static rendering, we | |
| // don't need to do anything here because the entire page is already dynamic | |
| // or it's static and it should not throw or postpone here. | |
| if (store.forceDynamic || store.forceStatic) return; | |
| 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) { | |
| switch(workUnitStore.type){ | |
| case 'prerender-ppr': | |
| return postponeWithTracking(store.route, expression, workUnitStore.dynamicTracking); | |
| case 'prerender-legacy': | |
| workUnitStore.revalidate = 0; | |
| // We aren't prerendering, but we are generating a static page. We need | |
| // to bail out of static generation. | |
| 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: "E550", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| store.dynamicUsageDescription = expression; | |
| store.dynamicUsageStack = err.stack; | |
| throw err; | |
| case 'request': | |
| if (process.env.NODE_ENV !== 'production') { | |
| workUnitStore.usedDynamic = true; | |
| } | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| } | |
| /** | |
| * This function is meant to be used when prerendering without cacheComponents or PPR. | |
| * When called during a build it will cause Next.js to consider the route as dynamic. | |
| * | |
| * @internal | |
| */ export function throwToInterruptStaticGeneration(expression, store, prerenderStore) { | |
| // We aren't prerendering but we are generating a static page. We need to bail out of static generation | |
| 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 | |
| }); | |
| prerenderStore.revalidate = 0; | |
| store.dynamicUsageDescription = expression; | |
| store.dynamicUsageStack = err.stack; | |
| throw err; | |
| } | |
| /** | |
| * This function should be used to track whether something dynamic happened even when | |
| * we are in a dynamic render. This is useful for Dev where all renders are dynamic but | |
| * we still track whether dynamic APIs were accessed for helpful messaging | |
| * | |
| * @internal | |
| */ export function trackDynamicDataInDynamicRender(workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'cache': | |
| case 'unstable-cache': | |
| // Inside cache scopes, marking a scope as dynamic has no effect, | |
| // because the outer cache scope creates a cache boundary. This is | |
| // subtly different from reading a dynamic data source, which is | |
| // forbidden inside a cache scope. | |
| return; | |
| case 'private-cache': | |
| // A private cache scope is already dynamic by definition. | |
| return; | |
| case 'prerender': | |
| case 'prerender-runtime': | |
| case 'prerender-legacy': | |
| case 'prerender-ppr': | |
| case 'prerender-client': | |
| break; | |
| case 'request': | |
| if (process.env.NODE_ENV !== 'production') { | |
| workUnitStore.usedDynamic = true; | |
| } | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| function abortOnSynchronousDynamicDataAccess(route, expression, prerenderStore) { | |
| const reason = `Route ${route} needs to bail out of prerendering at this point because it used ${expression}.`; | |
| const error = createPrerenderInterruptedError(reason); | |
| prerenderStore.controller.abort(error); | |
| const dynamicTracking = prerenderStore.dynamicTracking; | |
| if (dynamicTracking) { | |
| dynamicTracking.dynamicAccesses.push({ | |
| // When we aren't debugging, we don't need to create another error for the | |
| // stack trace. | |
| stack: dynamicTracking.isDebugDynamicAccesses ? new Error().stack : undefined, | |
| expression | |
| }); | |
| } | |
| } | |
| export function abortOnSynchronousPlatformIOAccess(route, expression, errorWithStack, prerenderStore) { | |
| const dynamicTracking = prerenderStore.dynamicTracking; | |
| abortOnSynchronousDynamicDataAccess(route, expression, prerenderStore); | |
| // It is important that we set this tracking value after aborting. Aborts are executed | |
| // synchronously except for the case where you abort during render itself. By setting this | |
| // value late we can use it to determine if any of the aborted tasks are the task that | |
| // called the sync IO expression in the first place. | |
| if (dynamicTracking) { | |
| if (dynamicTracking.syncDynamicErrorWithStack === null) { | |
| dynamicTracking.syncDynamicErrorWithStack = errorWithStack; | |
| } | |
| } | |
| } | |
| export function trackSynchronousPlatformIOAccessInDev(requestStore) { | |
| // We don't actually have a controller to abort but we do the semantic equivalent by | |
| // advancing the request store out of prerender mode | |
| requestStore.prerenderPhase = false; | |
| } | |
| /** | |
| * use this function when prerendering with cacheComponents. If we are doing a | |
| * prospective prerender we don't actually abort because we want to discover | |
| * all caches for the shell. If this is the actual prerender we do abort. | |
| * | |
| * This function accepts a prerenderStore but the caller should ensure we're | |
| * actually running in cacheComponents mode. | |
| * | |
| * @internal | |
| */ export function abortAndThrowOnSynchronousRequestDataAccess(route, expression, errorWithStack, prerenderStore) { | |
| const prerenderSignal = prerenderStore.controller.signal; | |
| if (prerenderSignal.aborted === false) { | |
| // TODO it would be better to move this aborted check into the callsite so we can avoid making | |
| // the error object when it isn't relevant to the aborting of the prerender however | |
| // since we need the throw semantics regardless of whether we abort it is easier to land | |
| // this way. See how this was handled with `abortOnSynchronousPlatformIOAccess` for a closer | |
| // to ideal implementation | |
| abortOnSynchronousDynamicDataAccess(route, expression, prerenderStore); | |
| // It is important that we set this tracking value after aborting. Aborts are executed | |
| // synchronously except for the case where you abort during render itself. By setting this | |
| // value late we can use it to determine if any of the aborted tasks are the task that | |
| // called the sync IO expression in the first place. | |
| const dynamicTracking = prerenderStore.dynamicTracking; | |
| if (dynamicTracking) { | |
| if (dynamicTracking.syncDynamicErrorWithStack === null) { | |
| dynamicTracking.syncDynamicErrorWithStack = errorWithStack; | |
| } | |
| } | |
| } | |
| throw createPrerenderInterruptedError(`Route ${route} needs to bail out of prerendering at this point because it used ${expression}.`); | |
| } | |
| /** | |
| * Use this function when dynamically prerendering with dynamicIO. | |
| * We don't want to error, because it's better to return something | |
| * (and we've already aborted the render at the point where the sync dynamic error occured), | |
| * but we should log an error server-side. | |
| * @internal | |
| */ export function warnOnSyncDynamicError(dynamicTracking) { | |
| if (dynamicTracking.syncDynamicErrorWithStack) { | |
| // the server did something sync dynamic, likely | |
| // leading to an early termination of the prerender. | |
| console.error(dynamicTracking.syncDynamicErrorWithStack); | |
| } | |
| } | |
| // For now these implementations are the same so we just reexport | |
| export const trackSynchronousRequestDataAccessInDev = trackSynchronousPlatformIOAccessInDev; | |
| export function Postpone({ reason, route }) { | |
| const prerenderStore = workUnitAsyncStorage.getStore(); | |
| const dynamicTracking = prerenderStore && prerenderStore.type === 'prerender-ppr' ? prerenderStore.dynamicTracking : null; | |
| postponeWithTracking(route, reason, dynamicTracking); | |
| } | |
| export function postponeWithTracking(route, expression, dynamicTracking) { | |
| assertPostpone(); | |
| if (dynamicTracking) { | |
| dynamicTracking.dynamicAccesses.push({ | |
| // When we aren't debugging, we don't need to create another error for the | |
| // stack trace. | |
| stack: dynamicTracking.isDebugDynamicAccesses ? new Error().stack : undefined, | |
| expression | |
| }); | |
| } | |
| React.unstable_postpone(createPostponeReason(route, expression)); | |
| } | |
| function createPostponeReason(route, expression) { | |
| return `Route ${route} needs to bail out of prerendering at this point because it used ${expression}. ` + `React throws this special object to indicate where. It should not be caught by ` + `your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error`; | |
| } | |
| export function isDynamicPostpone(err) { | |
| if (typeof err === 'object' && err !== null && typeof err.message === 'string') { | |
| return isDynamicPostponeReason(err.message); | |
| } | |
| return false; | |
| } | |
| function isDynamicPostponeReason(reason) { | |
| return reason.includes('needs to bail out of prerendering at this point because it used') && reason.includes('Learn more: https://nextjs.org/docs/messages/ppr-caught-error'); | |
| } | |
| if (isDynamicPostponeReason(createPostponeReason('%%%', '^^^')) === false) { | |
| throw Object.defineProperty(new Error('Invariant: isDynamicPostpone misidentified a postpone reason. This is a bug in Next.js'), "__NEXT_ERROR_CODE", { | |
| value: "E296", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const NEXT_PRERENDER_INTERRUPTED = 'NEXT_PRERENDER_INTERRUPTED'; | |
| function createPrerenderInterruptedError(message) { | |
| const error = Object.defineProperty(new Error(message), "__NEXT_ERROR_CODE", { | |
| value: "E394", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| error.digest = NEXT_PRERENDER_INTERRUPTED; | |
| return error; | |
| } | |
| export function isPrerenderInterruptedError(error) { | |
| return typeof error === 'object' && error !== null && error.digest === NEXT_PRERENDER_INTERRUPTED && 'name' in error && 'message' in error && error instanceof Error; | |
| } | |
| export function accessedDynamicData(dynamicAccesses) { | |
| return dynamicAccesses.length > 0; | |
| } | |
| export function consumeDynamicAccess(serverDynamic, clientDynamic) { | |
| // We mutate because we only call this once we are no longer writing | |
| // to the dynamicTrackingState and it's more efficient than creating a new | |
| // array. | |
| serverDynamic.dynamicAccesses.push(...clientDynamic.dynamicAccesses); | |
| return serverDynamic.dynamicAccesses; | |
| } | |
| export function formatDynamicAPIAccesses(dynamicAccesses) { | |
| return dynamicAccesses.filter((access)=>typeof access.stack === 'string' && access.stack.length > 0).map(({ expression, stack })=>{ | |
| stack = stack.split('\n')// Remove the "Error: " prefix from the first line of the stack trace as | |
| // well as the first 4 lines of the stack trace which is the distance | |
| // from the user code and the `new Error().stack` call. | |
| .slice(4).filter((line)=>{ | |
| // Exclude Next.js internals from the stack trace. | |
| if (line.includes('node_modules/next/')) { | |
| return false; | |
| } | |
| // Exclude anonymous functions from the stack trace. | |
| if (line.includes(' (<anonymous>)')) { | |
| return false; | |
| } | |
| // Exclude Node.js internals from the stack trace. | |
| if (line.includes(' (node:')) { | |
| return false; | |
| } | |
| return true; | |
| }).join('\n'); | |
| return `Dynamic API Usage Debug - ${expression}:\n${stack}`; | |
| }); | |
| } | |
| function assertPostpone() { | |
| if (!hasPostpone) { | |
| throw Object.defineProperty(new Error(`Invariant: React.unstable_postpone is not defined. This suggests the wrong version of React was loaded. This is a bug in Next.js`), "__NEXT_ERROR_CODE", { | |
| value: "E224", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| } | |
| /** | |
| * This is a bit of a hack to allow us to abort a render using a Postpone instance instead of an Error which changes React's | |
| * abort semantics slightly. | |
| */ export function createRenderInBrowserAbortSignal() { | |
| const controller = new AbortController(); | |
| controller.abort(Object.defineProperty(new BailoutToCSRError('Render in Browser'), "__NEXT_ERROR_CODE", { | |
| value: "E721", | |
| enumerable: false, | |
| configurable: true | |
| })); | |
| return controller.signal; | |
| } | |
| /** | |
| * In a prerender, we may end up with hanging Promises as inputs due them | |
| * stalling on connection() or because they're loading dynamic data. In that | |
| * case we need to abort the encoding of arguments since they'll never complete. | |
| */ export function createHangingInputAbortSignal(workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender': | |
| case 'prerender-runtime': | |
| const controller = new AbortController(); | |
| if (workUnitStore.cacheSignal) { | |
| // If we have a cacheSignal it means we're in a prospective render. If | |
| // the input we're waiting on is coming from another cache, we do want | |
| // to wait for it so that we can resolve this cache entry too. | |
| workUnitStore.cacheSignal.inputReady().then(()=>{ | |
| controller.abort(); | |
| }); | |
| } else { | |
| // Otherwise we're in the final render and we should already have all | |
| // our caches filled. | |
| // If the prerender uses stages, we have wait until the runtime stage, | |
| // at which point all runtime inputs will be resolved. | |
| // (otherwise, a runtime prerender might consider `cookies()` hanging | |
| // even though they'd resolve in the next task.) | |
| // | |
| // We might still be waiting on some microtasks so we | |
| // wait one tick before giving up. When we give up, we still want to | |
| // render the content of this cache as deeply as we can so that we can | |
| // suspend as deeply as possible in the tree or not at all if we don't | |
| // end up waiting for the input. | |
| const runtimeStagePromise = getRuntimeStagePromise(workUnitStore); | |
| if (runtimeStagePromise) { | |
| runtimeStagePromise.then(()=>scheduleOnNextTick(()=>controller.abort())); | |
| } else { | |
| scheduleOnNextTick(()=>controller.abort()); | |
| } | |
| } | |
| return controller.signal; | |
| case 'prerender-client': | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| case 'request': | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| return undefined; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| export function annotateDynamicAccess(expression, prerenderStore) { | |
| const dynamicTracking = prerenderStore.dynamicTracking; | |
| if (dynamicTracking) { | |
| dynamicTracking.dynamicAccesses.push({ | |
| stack: dynamicTracking.isDebugDynamicAccesses ? new Error().stack : undefined, | |
| expression | |
| }); | |
| } | |
| } | |
| export function useDynamicRouteParams(expression) { | |
| const workStore = workAsyncStorage.getStore(); | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workStore && workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender-client': | |
| case 'prerender': | |
| { | |
| const fallbackParams = workUnitStore.fallbackRouteParams; | |
| if (fallbackParams && fallbackParams.size > 0) { | |
| // We are in a prerender with cacheComponents semantics. We are going to | |
| // hang here and never resolve. This will cause the currently | |
| // rendering component to effectively be a dynamic hole. | |
| React.use(makeHangingPromise(workUnitStore.renderSignal, workStore.route, expression)); | |
| } | |
| break; | |
| } | |
| case 'prerender-ppr': | |
| { | |
| const fallbackParams = workUnitStore.fallbackRouteParams; | |
| if (fallbackParams && fallbackParams.size > 0) { | |
| return postponeWithTracking(workStore.route, expression, workUnitStore.dynamicTracking); | |
| } | |
| break; | |
| } | |
| case 'prerender-runtime': | |
| throw Object.defineProperty(new InvariantError(`\`${expression}\` was called during a runtime prerender. Next.js should be preventing ${expression} from being included in server components statically, but did not in this case.`), "__NEXT_ERROR_CODE", { | |
| value: "E771", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'cache': | |
| case 'private-cache': | |
| throw Object.defineProperty(new InvariantError(`\`${expression}\` was called inside a cache scope. Next.js should be preventing ${expression} from being included in server components statically, but did not in this case.`), "__NEXT_ERROR_CODE", { | |
| value: "E745", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'prerender-legacy': | |
| case 'request': | |
| case 'unstable-cache': | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| } | |
| const hasSuspenseRegex = /\n\s+at Suspense \(<anonymous>\)/; | |
| // Common implicit body tags that React will treat as body when placed directly in html | |
| const bodyAndImplicitTags = 'body|div|main|section|article|aside|header|footer|nav|form|p|span|h1|h2|h3|h4|h5|h6'; | |
| // Detects when RootLayoutBoundary (our framework marker component) appears | |
| // after Suspense in the component stack, indicating the root layout is wrapped | |
| // within a Suspense boundary. Ensures no body/html/implicit-body components are in between. | |
| // | |
| // Example matches: | |
| // at Suspense (<anonymous>) | |
| // at __next_root_layout_boundary__ (<anonymous>) | |
| // | |
| // Or with other components in between (but not body/html/implicit-body): | |
| // at Suspense (<anonymous>) | |
| // at SomeComponent (<anonymous>) | |
| // at __next_root_layout_boundary__ (<anonymous>) | |
| const hasSuspenseBeforeRootLayoutWithoutBodyOrImplicitBodyRegex = new RegExp(`\\n\\s+at Suspense \\(<anonymous>\\)(?:(?!\\n\\s+at (?:${bodyAndImplicitTags}) \\(<anonymous>\\))[\\s\\S])*?\\n\\s+at ${ROOT_LAYOUT_BOUNDARY_NAME} \\([^\\n]*\\)`); | |
| const hasMetadataRegex = new RegExp(`\\n\\s+at ${METADATA_BOUNDARY_NAME}[\\n\\s]`); | |
| const hasViewportRegex = new RegExp(`\\n\\s+at ${VIEWPORT_BOUNDARY_NAME}[\\n\\s]`); | |
| const hasOutletRegex = new RegExp(`\\n\\s+at ${OUTLET_BOUNDARY_NAME}[\\n\\s]`); | |
| export function trackAllowedDynamicAccess(workStore, componentStack, dynamicValidation, clientDynamic) { | |
| if (hasOutletRegex.test(componentStack)) { | |
| // We don't need to track that this is dynamic. It is only so when something else is also dynamic. | |
| return; | |
| } else if (hasMetadataRegex.test(componentStack)) { | |
| dynamicValidation.hasDynamicMetadata = true; | |
| return; | |
| } else if (hasViewportRegex.test(componentStack)) { | |
| dynamicValidation.hasDynamicViewport = true; | |
| return; | |
| } else if (hasSuspenseBeforeRootLayoutWithoutBodyOrImplicitBodyRegex.test(componentStack)) { | |
| // For Suspense within body, the prelude wouldn't be empty so it wouldn't violate the empty static shells rule. | |
| // But if you have Suspense above body, the prelude is empty but we allow that because having Suspense | |
| // is an explicit signal from the user that they acknowledge the empty shell and want dynamic rendering. | |
| dynamicValidation.hasAllowedDynamic = true; | |
| dynamicValidation.hasSuspenseAboveBody = true; | |
| return; | |
| } else if (hasSuspenseRegex.test(componentStack)) { | |
| // this error had a Suspense boundary above it so we don't need to report it as a source | |
| // of disallowed | |
| dynamicValidation.hasAllowedDynamic = true; | |
| return; | |
| } else if (clientDynamic.syncDynamicErrorWithStack) { | |
| // This task was the task that called the sync error. | |
| dynamicValidation.dynamicErrors.push(clientDynamic.syncDynamicErrorWithStack); | |
| return; | |
| } else { | |
| const message = `Route "${workStore.route}": A component accessed data, headers, params, searchParams, or a short-lived cache without a Suspense boundary nor a "use cache" above it. See more info: https://nextjs.org/docs/messages/next-prerender-missing-suspense`; | |
| const error = createErrorWithComponentOrOwnerStack(message, componentStack); | |
| dynamicValidation.dynamicErrors.push(error); | |
| return; | |
| } | |
| } | |
| /** | |
| * In dev mode, we prefer using the owner stack, otherwise the provided | |
| * component stack is used. | |
| */ function createErrorWithComponentOrOwnerStack(message, componentStack) { | |
| const ownerStack = process.env.NODE_ENV !== 'production' && React.captureOwnerStack ? React.captureOwnerStack() : null; | |
| const error = Object.defineProperty(new Error(message), "__NEXT_ERROR_CODE", { | |
| value: "E394", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| error.stack = error.name + ': ' + message + (ownerStack ?? componentStack); | |
| return error; | |
| } | |
| export var PreludeState = /*#__PURE__*/ function(PreludeState) { | |
| PreludeState[PreludeState["Full"] = 0] = "Full"; | |
| PreludeState[PreludeState["Empty"] = 1] = "Empty"; | |
| PreludeState[PreludeState["Errored"] = 2] = "Errored"; | |
| return PreludeState; | |
| }({}); | |
| export function logDisallowedDynamicError(workStore, error) { | |
| console.error(error); | |
| if (!workStore.dev) { | |
| if (workStore.hasReadableErrorStacks) { | |
| console.error(`To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "${workStore.route}" in your browser to investigate the error.`); | |
| } else { | |
| console.error(`To get a more detailed stack trace and pinpoint the issue, try one of the following: | |
| - Start the app in development mode by running \`next dev\`, then open "${workStore.route}" in your browser to investigate the error. | |
| - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.`); | |
| } | |
| } | |
| } | |
| export function throwIfDisallowedDynamic(workStore, prelude, dynamicValidation, serverDynamic) { | |
| if (prelude !== 0) { | |
| if (dynamicValidation.hasSuspenseAboveBody) { | |
| // This route has opted into allowing fully dynamic rendering | |
| // by including a Suspense boundary above the body. In this case | |
| // a lack of a shell is not considered disallowed so we simply return | |
| return; | |
| } | |
| if (serverDynamic.syncDynamicErrorWithStack) { | |
| // There is no shell and the server did something sync dynamic likely | |
| // leading to an early termination of the prerender before the shell | |
| // could be completed. We terminate the build/validating render. | |
| logDisallowedDynamicError(workStore, serverDynamic.syncDynamicErrorWithStack); | |
| throw new StaticGenBailoutError(); | |
| } | |
| // We didn't have any sync bailouts but there may be user code which | |
| // blocked the root. We would have captured these during the prerender | |
| // and can log them here and then terminate the build/validating render | |
| const dynamicErrors = dynamicValidation.dynamicErrors; | |
| if (dynamicErrors.length > 0) { | |
| for(let i = 0; i < dynamicErrors.length; i++){ | |
| logDisallowedDynamicError(workStore, dynamicErrors[i]); | |
| } | |
| throw new StaticGenBailoutError(); | |
| } | |
| // If we got this far then the only other thing that could be blocking | |
| // the root is dynamic Viewport. If this is dynamic then | |
| // you need to opt into that by adding a Suspense boundary above the body | |
| // to indicate your are ok with fully dynamic rendering. | |
| if (dynamicValidation.hasDynamicViewport) { | |
| console.error(`Route "${workStore.route}" has a \`generateViewport\` that depends on Request data (\`cookies()\`, etc...) or uncached external data (\`fetch(...)\`, etc...) without explicitly allowing fully dynamic rendering. See more info here: https://nextjs.org/docs/messages/next-prerender-dynamic-viewport`); | |
| throw new StaticGenBailoutError(); | |
| } | |
| if (prelude === 1) { | |
| // If we ever get this far then we messed up the tracking of invalid dynamic. | |
| // We still adhere to the constraint that you must produce a shell but invite the | |
| // user to report this as a bug in Next.js. | |
| console.error(`Route "${workStore.route}" did not produce a static shell and Next.js was unable to determine a reason. This is a bug in Next.js.`); | |
| throw new StaticGenBailoutError(); | |
| } | |
| } else { | |
| if (dynamicValidation.hasAllowedDynamic === false && dynamicValidation.hasDynamicMetadata) { | |
| console.error(`Route "${workStore.route}" has a \`generateMetadata\` that depends on Request data (\`cookies()\`, etc...) or uncached external data (\`fetch(...)\`, etc...) when the rest of the route does not. See more info here: https://nextjs.org/docs/messages/next-prerender-dynamic-metadata`); | |
| throw new StaticGenBailoutError(); | |
| } | |
| } | |
| } | |
| export function delayUntilRuntimeStage(prerenderStore, result) { | |
| if (prerenderStore.runtimeStagePromise) { | |
| return prerenderStore.runtimeStagePromise.then(()=>result); | |
| } | |
| return result; | |
| } | |
| //# sourceMappingURL=dynamic-rendering.js.map |