next
Version:
The React Framework
96 lines (95 loc) • 5.17 kB
JavaScript
import { workAsyncStorage } from '../app-render/work-async-storage.external';
import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external';
import { makeDynamicHangingPromise, makeDevtoolsIOAwarePromise } from '../dynamic-rendering-utils';
import { RenderStage } from '../app-render/staged-rendering';
import { throwPrerenderPPRRemovedError } from '../../shared/lib/ppr-removed-error';
import { isRequestApiAllowedInCurrentPhase } from './utils';
// A fulfilled thenable that React can unwrap synchronously via `use()` without
// ever suspending. Reusing a single instance avoids allocating on every call.
const resolvedIOPromise = Promise.resolve(undefined);
resolvedIOPromise.status = 'fulfilled';
resolvedIOPromise.value = undefined;
/**
* This function allows you to indicate that the code following it performs
* I/O or accesses dynamic data sources such as `new Date()` or `Math.random()`.
*
* During prerendering it will prevent the prerender from continuing past this
* point, creating a dynamic boundary. Inside `"use cache"` scopes or during
* a real request it resolves immediately.
*
* Unlike `connection()`, `io()` does not require an actual HTTP request and
* can be used freely inside cache scopes and client components.
*/ export function io() {
const workStore = workAsyncStorage.getStore();
const workUnitStore = workUnitAsyncStorage.getStore();
if (workStore && workUnitStore) {
if (workUnitStore && !isRequestApiAllowedInCurrentPhase(workUnitStore)) {
throw Object.defineProperty(new Error(`Route ${workStore.route} used \`io()\` inside \`after()\` while rendering. The \`io()\` function is not allowed in this scope. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`), "__NEXT_ERROR_CODE", {
value: "E1380",
enumerable: false,
configurable: true
});
}
switch(workUnitStore.type){
case 'request':
// For dev renders we instrument the promise so it will show up in
// React Suspense Devtools and, if also doing `instant` validation,
// ensure it resolves in the right stage for staged rendering
// In production we just let it resolve immediately because we're doing
// a dynamic SSR or resume render and have no need to delay anything
// after this call
if (process.env.NODE_ENV === 'development') {
if (workUnitStore.asyncApiPromises) {
return workUnitStore.asyncApiPromises.io;
}
return makeDevtoolsIOAwarePromise(undefined, workUnitStore, RenderStage.Dynamic);
} else if (workUnitStore.asyncApiPromises) {
return workUnitStore.asyncApiPromises.io;
}
return resolvedIOPromise;
case 'prerender':
case 'prerender-client':
case 'prerender-runtime':
// When prerendering with Cache Components we consider `io()` to be
// actual IO if not in a cache scope and we can avoid actually executing
// anything after it by making it return a hanging promise.
return makeDynamicHangingPromise(workUnitStore.renderSignal, workStore.route, '`io()`');
case 'prerender-ppr':
// Dead code to be removed when we eliminate legacy ppr code
throwPrerenderPPRRemovedError();
break;
case 'cache':
case 'private-cache':
case 'unstable-cache':
// Inside cache scopes, io() resolves immediately.
// Caches can contain IO-dependent code like new Date() — it will
// simply return the value at cache-fill time.
// ...
// intentional fallthrough
case 'generate-static-params':
// generateStaticParams runs at build time. There is no prerender
// to stall so we resolve immediately.
// ...
// intentional fallthrough
case 'validation-client':
// io() is usable in client components, resolve immediately.
// The reason we take this position is most io shielding you would do
// in a browser is for sync IO as there aren't many non-fetch based IO
// operations you can do in the browser that have meaningful latency.
// So while you might use
// ...
// intentional fallthrough
case 'prerender-legacy':
// Without cache components, IO is not inherently dynamic.
// Resolve immediately rather than interrupting static generation.
return resolvedIOPromise;
default:
workUnitStore;
}
}
// No work store — we're outside the Next.js rendering context (e.g. in
// a client component on the browser or in a standalone script). Resolve
// immediately.
return resolvedIOPromise;
}
//# sourceMappingURL=io.js.map