next
Version:
The React Framework
963 lines • 166 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "renderToHTMLOrFlight", {
enumerable: true,
get: function() {
return renderToHTMLOrFlight;
}
});
const _jsxruntime = require("react/jsx-runtime");
const _workasyncstorageexternal = require("../app-render/work-async-storage.external");
const _react = /*#__PURE__*/ _interop_require_default(require("react"));
const _renderresult = /*#__PURE__*/ _interop_require_default(require("../render-result"));
const _nodewebstreamshelper = require("../stream-utils/node-web-streams-helper");
const _internalutils = require("../internal-utils");
const _approuterheaders = require("../../client/components/app-router-headers");
const _metadatacontext = require("../../lib/metadata/metadata-context");
const _requeststore = require("../async-storage/request-store");
const _workstore = require("../async-storage/work-store");
const _httpaccessfallback = require("../../client/components/http-access-fallback/http-access-fallback");
const _redirect = require("../../client/components/redirect");
const _redirecterror = require("../../client/components/redirect-error");
const _implicittags = require("../lib/implicit-tags");
const _constants = require("../lib/trace/constants");
const _tracer = require("../lib/trace/tracer");
const _flightrenderresult = require("./flight-render-result");
const _createerrorhandler = require("./create-error-handler");
const _getshortdynamicparamtype = require("./get-short-dynamic-param-type");
const _getsegmentparam = require("./get-segment-param");
const _getscriptnoncefromheader = require("./get-script-nonce-from-header");
const _parseandvalidateflightrouterstate = require("./parse-and-validate-flight-router-state");
const _createflightrouterstatefromloadertree = require("./create-flight-router-state-from-loader-tree");
const _actionhandler = require("./action-handler");
const _bailouttocsr = require("../../shared/lib/lazy-dynamic/bailout-to-csr");
const _log = require("../../build/output/log");
const _requestcookies = require("../web/spec-extension/adapters/request-cookies");
const _serverinsertedhtml = require("./server-inserted-html");
const _requiredscripts = require("./required-scripts");
const _addpathprefix = require("../../shared/lib/router/utils/add-path-prefix");
const _makegetserverinsertedhtml = require("./make-get-server-inserted-html");
const _walktreewithflightrouterstate = require("./walk-tree-with-flight-router-state");
const _createcomponenttree = require("./create-component-tree");
const _getassetquerystring = require("./get-asset-query-string");
const _encryptionutils = require("./encryption-utils");
const _postponedstate = require("./postponed-state");
const _hooksservercontext = require("../../client/components/hooks-server-context");
const _useflightresponse = require("./use-flight-response");
const _staticgenerationbailout = require("../../client/components/static-generation-bailout");
const _formatservererror = require("../../lib/format-server-error");
const _dynamicrendering = require("./dynamic-rendering");
const _clientcomponentrendererlogger = require("../client-component-renderer-logger");
const _actionutils = require("./action-utils");
const _helpers = require("../base-http/helpers");
const _parserelativeurl = require("../../shared/lib/router/utils/parse-relative-url");
const _approuter = /*#__PURE__*/ _interop_require_default(require("../../client/components/app-router"));
const _serveractionrequestmeta = require("../lib/server-action-request-meta");
const _createinitialrouterstate = require("../../client/components/router-reducer/create-initial-router-state");
const _approuterinstance = require("../../client/components/app-router-instance");
const _utils = require("../instrumentation/utils");
const _segment = require("../../shared/lib/segment");
const _apprenderprerenderutils = require("./app-render-prerender-utils");
const _prospectiverenderutils = require("./prospective-render-utils");
const _apprenderrenderutils = require("./app-render-render-utils");
const _scheduler = require("../../lib/scheduler");
const _workunitasyncstorageexternal = require("./work-unit-async-storage.external");
const _cachesignal = require("./cache-signal");
const _utils1 = require("../lib/trace/utils");
const _invarianterror = require("../../shared/lib/invariant-error");
const _constants1 = require("../../lib/constants");
const _createcomponentstylesandscripts = require("./create-component-styles-and-scripts");
const _parseloadertree = require("./parse-loader-tree");
const _resumedatacache = require("../resume-data-cache/resume-data-cache");
const _iserror = /*#__PURE__*/ _interop_require_default(require("../../lib/is-error"));
const _createserverinsertedmetadata = require("./metadata-insertion/create-server-inserted-metadata");
const _serverutils = require("../server-utils");
const _revalidationutils = require("../revalidation-utils");
const _trackmoduleloadingexternal = require("./module-loading/track-module-loading.external");
const _reactlargeshellerror = require("./react-large-shell-error");
const _segmentexplorerpath = require("./segment-explorer-path");
const _requestmeta = require("../request-meta");
const _getdynamicparam = require("../../shared/lib/router/utils/get-dynamic-param");
const _promisewithresolvers = require("../../shared/lib/promise-with-resolvers");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const flightDataPathHeadKey = 'h';
const getFlightViewportKey = (requestId)=>requestId + 'v';
const getFlightMetadataKey = (requestId)=>requestId + 'm';
const filterStackFrame = process.env.NODE_ENV !== 'production' ? require('../lib/source-maps').filterStackFrameDEV : undefined;
function parseRequestHeaders(headers, options) {
const isDevWarmupRequest = options.isDevWarmup === true;
// dev warmup requests are treated as prefetch RSC requests
// runtime prefetch requests are *not* treated as prefetch requests
// (TODO: this is confusing, we should refactor this to express this better)
const isPrefetchRequest = isDevWarmupRequest || headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '1';
const isRuntimePrefetchRequest = headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '2';
const isHmrRefresh = headers[_approuterheaders.NEXT_HMR_REFRESH_HEADER] !== undefined;
// dev warmup requests are treated as prefetch RSC requests
const isRSCRequest = isDevWarmupRequest || headers[_approuterheaders.RSC_HEADER] !== undefined;
const shouldProvideFlightRouterState = isRSCRequest && (!isPrefetchRequest || !options.isRoutePPREnabled);
const flightRouterState = shouldProvideFlightRouterState ? (0, _parseandvalidateflightrouterstate.parseAndValidateFlightRouterState)(headers[_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER]) : undefined;
// Checks if this is a prefetch of the Route Tree by the Segment Cache
const isRouteTreePrefetchRequest = headers[_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER] === '/_tree';
const csp = headers['content-security-policy'] || headers['content-security-policy-report-only'];
const nonce = typeof csp === 'string' ? (0, _getscriptnoncefromheader.getScriptNonceFromHeader)(csp) : undefined;
const previouslyRevalidatedTags = (0, _serverutils.getPreviouslyRevalidatedTags)(headers, options.previewModeId);
return {
flightRouterState,
isPrefetchRequest,
isRuntimePrefetchRequest,
isRouteTreePrefetchRequest,
isHmrRefresh,
isRSCRequest,
isDevWarmupRequest,
nonce,
previouslyRevalidatedTags
};
}
function createNotFoundLoaderTree(loaderTree) {
const components = loaderTree[2];
const hasGlobalNotFound = !!components['global-not-found'];
return [
'',
{
children: [
_segment.PAGE_SEGMENT_KEY,
{},
{
page: components['global-not-found'] ?? components['not-found']
}
]
},
// When global-not-found is present, skip layout from components
hasGlobalNotFound ? components : {}
];
}
/**
* Returns a function that parses the dynamic segment and return the associated value.
*/ function makeGetDynamicParamFromSegment(params, pagePath, fallbackRouteParams) {
return function getDynamicParamFromSegment(// [slug] / [[slug]] / [...slug]
segment) {
const segmentParam = (0, _getsegmentparam.getSegmentParam)(segment);
if (!segmentParam) {
return null;
}
const segmentKey = segmentParam.param;
const dynamicParamType = _getshortdynamicparamtype.dynamicParamTypes[segmentParam.type];
return (0, _getdynamicparam.getDynamicParam)(params, segmentKey, dynamicParamType, pagePath, fallbackRouteParams);
};
}
function NonIndex({ pagePath, statusCode, isPossibleServerAction }) {
const is404Page = pagePath === '/404';
const isInvalidStatusCode = typeof statusCode === 'number' && statusCode > 400;
// Only render noindex for page request, skip for server actions
// TODO: is this correct if `isPossibleServerAction` is a false positive?
if (!isPossibleServerAction && (is404Page || isInvalidStatusCode)) {
return /*#__PURE__*/ (0, _jsxruntime.jsx)("meta", {
name: "robots",
content: "noindex"
});
}
return null;
}
/**
* This is used by server actions & client-side navigations to generate RSC data from a client-side request.
* This function is only called on "dynamic" requests (ie, there wasn't already a static response).
* It uses request headers (namely `next-router-state-tree`) to determine where to start rendering.
*/ async function generateDynamicRSCPayload(ctx, options) {
// Flight data that is going to be passed to the browser.
// Currently a single item array but in the future multiple patches might be combined in a single request.
// We initialize `flightData` to an empty string because the client router knows how to tolerate
// it (treating it as an MPA navigation). The only time this function wouldn't generate flight data
// is for server actions, if the server action handler instructs this function to skip it. When the server
// action reducer sees a falsy value, it'll simply resolve the action with no data.
let flightData = '';
const { componentMod: { tree: loaderTree, createMetadataComponents, MetadataBoundary, ViewportBoundary }, getDynamicParamFromSegment, appUsingSizeAdjustment, query, requestId, flightRouterState, workStore, url } = ctx;
const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata;
if (!(options == null ? void 0 : options.skipFlight)) {
const preloadCallbacks = [];
const { ViewportTree, MetadataTree, getViewportReady, getMetadataReady, StreamingMetadataOutlet } = createMetadataComponents({
tree: loaderTree,
parsedQuery: query,
pathname: url.pathname,
metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts),
getDynamicParamFromSegment,
appUsingSizeAdjustment,
workStore,
MetadataBoundary,
ViewportBoundary,
serveStreamingMetadata
});
flightData = (await (0, _walktreewithflightrouterstate.walkTreeWithFlightRouterState)({
ctx,
loaderTreeToFilter: loaderTree,
parentParams: {},
flightRouterState,
// For flight, render metadata inside leaf page
rscHead: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_react.default.Fragment, {
children: [
/*#__PURE__*/ (0, _jsxruntime.jsx)(NonIndex, {
pagePath: ctx.pagePath,
statusCode: ctx.res.statusCode,
isPossibleServerAction: ctx.isPossibleServerAction
}),
/*#__PURE__*/ (0, _jsxruntime.jsx)(ViewportTree, {}, getFlightViewportKey(requestId)),
/*#__PURE__*/ (0, _jsxruntime.jsx)(MetadataTree, {}, getFlightMetadataKey(requestId))
]
}, flightDataPathHeadKey),
injectedCSS: new Set(),
injectedJS: new Set(),
injectedFontPreloadTags: new Set(),
rootLayoutIncluded: false,
getViewportReady,
getMetadataReady,
preloadCallbacks,
StreamingMetadataOutlet
})).map((path)=>path.slice(1)) // remove the '' (root) segment
;
}
// If we have an action result, then this is a server action response.
// We can rely on this because `ActionResult` will always be a promise, even if
// the result is falsey.
if (options == null ? void 0 : options.actionResult) {
return {
a: options.actionResult,
f: flightData,
b: ctx.sharedContext.buildId
};
}
// Otherwise, it's a regular RSC response.
return {
b: ctx.sharedContext.buildId,
f: flightData,
S: workStore.isStaticGeneration
};
}
function createErrorContext(ctx, renderSource) {
return {
routerKind: 'App Router',
routePath: ctx.pagePath,
// TODO: is this correct if `isPossibleServerAction` is a false positive?
routeType: ctx.isPossibleServerAction ? 'action' : 'render',
renderSource,
revalidateReason: (0, _utils.getRevalidateReason)(ctx.workStore)
};
}
/**
* Produces a RenderResult containing the Flight data for the given request. See
* `generateDynamicRSCPayload` for information on the contents of the render result.
*/ async function generateDynamicFlightRenderResult(req, ctx, requestStore, options) {
const renderOpts = ctx.renderOpts;
function onFlightDataRenderError(err) {
return renderOpts.onInstrumentationRequestError == null ? void 0 : renderOpts.onInstrumentationRequestError.call(renderOpts, err, req, createErrorContext(ctx, 'react-server-components-payload'));
}
const onError = (0, _createerrorhandler.createFlightReactServerErrorHandler)(!!renderOpts.dev, onFlightDataRenderError);
const RSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, options);
// For app dir, use the bundled version of Flight server renderer (renderToReadableStream)
// which contains the subset React.
const flightReadableStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, ctx.componentMod.renderToReadableStream, RSCPayload, ctx.clientReferenceManifest.clientModules, {
onError,
temporaryReferences: options == null ? void 0 : options.temporaryReferences,
filterStackFrame
});
return new _flightrenderresult.FlightRenderResult(flightReadableStream, {
fetchMetrics: ctx.workStore.fetchMetrics
});
}
async function generateRuntimePrefetchResult(req, res, ctx, requestStore) {
const { workStore } = ctx;
const renderOpts = ctx.renderOpts;
function onFlightDataRenderError(err) {
return renderOpts.onInstrumentationRequestError == null ? void 0 : renderOpts.onInstrumentationRequestError.call(renderOpts, err, req, // TODO(runtime-ppr): should we use a different value?
createErrorContext(ctx, 'react-server-components-payload'));
}
const onError = (0, _createerrorhandler.createFlightReactServerErrorHandler)(false, onFlightDataRenderError);
const metadata = {};
const generatePayload = ()=>generateDynamicRSCPayload(ctx, undefined);
const { componentMod: { tree }, getDynamicParamFromSegment } = ctx;
const rootParams = (0, _createcomponenttree.getRootParams)(tree, getDynamicParamFromSegment);
// We need to share caches between the prospective prerender and the final prerender,
// but we're not going to persist this anywhere.
const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)();
// We're not resuming an existing render.
const renderResumeDataCache = null;
await prospectiveRuntimeServerPrerender(ctx, generatePayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, requestStore.cookies, requestStore.draftMode);
const response = await finalRuntimeServerPrerender(ctx, generatePayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, requestStore.cookies, requestStore.draftMode, onError);
applyMetadataFromPrerenderResult(response, metadata, workStore);
metadata.fetchMetrics = ctx.workStore.fetchMetrics;
if (response.isPartial) {
res.setHeader(_approuterheaders.NEXT_DID_POSTPONE_HEADER, '1');
}
return new _flightrenderresult.FlightRenderResult(response.result.prelude, metadata);
}
async function prospectiveRuntimeServerPrerender(ctx, getPayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, cookies, draftMode) {
const { implicitTags, renderOpts, workStore } = ctx;
const { clientReferenceManifest, ComponentMod } = renderOpts;
assertClientReferenceManifest(clientReferenceManifest);
// Prerender controller represents the lifetime of the prerender.
// It will be aborted when a Task is complete or a synchronously aborting
// API is called. Notably during cache-filling renders this does not actually
// terminate the render itself which will continue until all caches are filled
const initialServerPrerenderController = new AbortController();
// This controller represents the lifetime of the React render call. Notably
// during the cache-filling render it is different from the prerender controller
// because we don't want to end the react render until all caches are filled.
const initialServerRenderController = new AbortController();
// The cacheSignal helps us track whether caches are still filling or we are ready
// to cut the render off.
const cacheSignal = new _cachesignal.CacheSignal();
const initialServerPrerenderStore = {
type: 'prerender-runtime',
phase: 'render',
rootParams,
implicitTags,
renderSignal: initialServerRenderController.signal,
controller: initialServerPrerenderController,
// During the initial prerender we need to track all cache reads to ensure
// we render long enough to fill every cache it is possible to visit during
// the final prerender.
cacheSignal,
// We only need to track dynamic accesses during the final prerender.
dynamicTracking: null,
// Runtime prefetches are never cached server-side, only client-side,
// so we set `expire` and `revalidate` to their minimum values just in case.
revalidate: 1,
expire: 0,
stale: _constants1.INFINITE_CACHE,
tags: [
...implicitTags.tags
],
renderResumeDataCache,
prerenderResumeDataCache,
hmrRefreshHash: undefined,
captureOwnerStack: undefined,
// We only need task sequencing in the final prerender.
runtimeStagePromise: null,
// These are not present in regular prerenders, but allowed in a runtime prerender.
cookies,
draftMode
};
// We're not going to use the result of this render because the only time it could be used
// is if it completes in a microtask and that's likely very rare for any non-trivial app
const initialServerPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPrerenderStore, getPayload);
const pendingInitialServerResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPrerenderStore, ComponentMod.prerender, initialServerPayload, clientReferenceManifest.clientModules, {
filterStackFrame,
onError: (err)=>{
const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err);
if (digest) {
return digest;
}
if (initialServerPrerenderController.signal.aborted) {
// The render aborted before this error was handled which indicates
// the error is caused by unfinished components within the render
return;
} else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) {
(0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route);
}
},
// we don't care to track postpones during the prospective render because we need
// to always do a final render anyway
onPostpone: undefined,
// We don't want to stop rendering until the cacheSignal is complete so we pass
// a different signal to this render call than is used by dynamic APIs to signify
// transitioning out of the prerender environment
signal: initialServerRenderController.signal
});
// Wait for all caches to be finished filling and for async imports to resolve
(0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal);
await cacheSignal.cacheReady();
initialServerRenderController.abort();
initialServerPrerenderController.abort();
// We don't need to continue the prerender process if we already
// detected invalid dynamic usage in the initial prerender phase.
if (workStore.invalidDynamicUsageError) {
throw workStore.invalidDynamicUsageError;
}
try {
return await (0, _apprenderprerenderutils.createReactServerPrerenderResult)(pendingInitialServerResult);
} catch (err) {
if (initialServerRenderController.signal.aborted || initialServerPrerenderController.signal.aborted) {
// These are expected errors that might error the prerender. we ignore them.
} else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) {
// We don't normally log these errors because we are going to retry anyway but
// it can be useful for debugging Next.js itself to get visibility here when needed
(0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route);
}
return null;
}
}
async function finalRuntimeServerPrerender(ctx, getPayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, cookies, draftMode, onError) {
const { implicitTags, renderOpts } = ctx;
const { clientReferenceManifest, ComponentMod, experimental, isDebugDynamicAccesses } = renderOpts;
assertClientReferenceManifest(clientReferenceManifest);
const selectStaleTime = createSelectStaleTime(experimental);
let serverIsDynamic = false;
const finalServerController = new AbortController();
const serverDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(isDebugDynamicAccesses);
const { promise: runtimeStagePromise, resolve: resolveBlockedRuntimeAPIs } = (0, _promisewithresolvers.createPromiseWithResolvers)();
const finalServerPrerenderStore = {
type: 'prerender-runtime',
phase: 'render',
rootParams,
implicitTags,
renderSignal: finalServerController.signal,
controller: finalServerController,
// All caches we could read must already be filled so no tracking is necessary
cacheSignal: null,
dynamicTracking: serverDynamicTracking,
// Runtime prefetches are never cached server-side, only client-side,
// so we set `expire` and `revalidate` to their minimum values just in case.
revalidate: 1,
expire: 0,
stale: _constants1.INFINITE_CACHE,
tags: [
...implicitTags.tags
],
prerenderResumeDataCache,
renderResumeDataCache,
hmrRefreshHash: undefined,
captureOwnerStack: undefined,
// Used to separate the "Static" stage from the "Runtime" stage.
runtimeStagePromise,
// These are not present in regular prerenders, but allowed in a runtime prerender.
cookies,
draftMode
};
const finalRSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalServerPrerenderStore, getPayload);
let prerenderIsPending = true;
const result = await (0, _apprenderprerenderutils.prerenderAndAbortInSequentialTasksWithStages)(async ()=>{
// Static stage
const prerenderResult = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalServerPrerenderStore, ComponentMod.prerender, finalRSCPayload, clientReferenceManifest.clientModules, {
filterStackFrame,
onError,
signal: finalServerController.signal
});
prerenderIsPending = false;
return prerenderResult;
}, ()=>{
// Advance to the runtime stage.
//
// We make runtime APIs hang during the first task (above), and unblock them in the following task (here).
// This makes sure that, at this point, we'll have finished all the static parts (what we'd prerender statically).
// We know that they don't contain any incorrect sync IO, because that'd have caused a build error.
// After we unblock Runtime APIs, if we encounter sync IO (e.g. `await cookies(); Date.now()`),
// we'll abort, but we'll produce at least as much output as a static prerender would.
resolveBlockedRuntimeAPIs();
}, ()=>{
// Abort.
if (finalServerController.signal.aborted) {
// If the server controller is already aborted we must have called something
// that required aborting the prerender synchronously such as with new Date()
serverIsDynamic = true;
return;
}
if (prerenderIsPending) {
// If prerenderIsPending then we have blocked for longer than a Task and we assume
// there is something unfinished.
serverIsDynamic = true;
}
finalServerController.abort();
});
(0, _dynamicrendering.warnOnSyncDynamicError)(serverDynamicTracking);
return {
result,
// TODO(runtime-ppr): do we need to produce a digest map here?
// digestErrorsMap: ...,
dynamicAccess: serverDynamicTracking,
isPartial: serverIsDynamic,
collectedRevalidate: finalServerPrerenderStore.revalidate,
collectedExpire: finalServerPrerenderStore.expire,
collectedStale: selectStaleTime(finalServerPrerenderStore.stale),
collectedTags: finalServerPrerenderStore.tags
};
}
/**
* Performs a "warmup" render of the RSC payload for a given route. This function is called by the server
* prior to an actual render request in Dev mode only. It's purpose is to fill caches so the actual render
* can accurately log activity in the right render context (Prerender vs Render).
*
* At the moment this implementation is mostly a fork of generateDynamicFlightRenderResult
*/ async function warmupDevRender(req, ctx) {
const { clientReferenceManifest, componentMod: ComponentMod, getDynamicParamFromSegment, implicitTags, renderOpts, workStore } = ctx;
const { allowEmptyStaticShell = false, dev, onInstrumentationRequestError } = renderOpts;
if (!dev) {
throw Object.defineProperty(new _invarianterror.InvariantError('generateDynamicFlightRenderResult should never be called in `next start` mode.'), "__NEXT_ERROR_CODE", {
value: "E523",
enumerable: false,
configurable: true
});
}
const rootParams = (0, _createcomponenttree.getRootParams)(ComponentMod.tree, getDynamicParamFromSegment);
function onFlightDataRenderError(err) {
return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components-payload'));
}
const onError = (0, _createerrorhandler.createFlightReactServerErrorHandler)(true, onFlightDataRenderError);
// We're doing a dev warmup, so we should create a new resume data cache so
// we can fill it.
const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)();
const renderController = new AbortController();
const prerenderController = new AbortController();
const reactController = new AbortController();
const cacheSignal = new _cachesignal.CacheSignal();
const prerenderStore = {
type: 'prerender',
phase: 'render',
rootParams,
implicitTags,
renderSignal: renderController.signal,
controller: prerenderController,
cacheSignal,
dynamicTracking: null,
allowEmptyStaticShell,
revalidate: _constants1.INFINITE_CACHE,
expire: _constants1.INFINITE_CACHE,
stale: _constants1.INFINITE_CACHE,
tags: [],
prerenderResumeDataCache,
renderResumeDataCache: null,
hmrRefreshHash: req.cookies[_approuterheaders.NEXT_HMR_REFRESH_HASH_COOKIE],
captureOwnerStack: ComponentMod.captureOwnerStack,
// warmup is a dev only feature and no fallback params are used in the
// primary render which is static. We only use a prerender store here to
// allow the warmup to halt on Request data APIs and fetches.
fallbackRouteParams: null
};
const rscPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderStore, generateDynamicRSCPayload, ctx);
// For app dir, use the bundled version of Flight server renderer (renderToReadableStream)
// which contains the subset React.
_workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderStore, ComponentMod.renderToReadableStream, rscPayload, clientReferenceManifest.clientModules, {
filterStackFrame,
onError,
signal: renderController.signal
});
// Wait for all caches to be finished filling and for async imports to resolve
(0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal);
await cacheSignal.cacheReady();
// We unset the cache so any late over-run renders aren't able to write into this cache
prerenderStore.prerenderResumeDataCache = null;
// Abort the render
reactController.abort();
renderController.abort();
// We don't really want to return a result here but the stack of functions
// that calls into renderToHTML... expects a result. We should refactor this to
// lift the warmup pathway outside of renderToHTML... but for now this suffices
return new _flightrenderresult.FlightRenderResult('', {
fetchMetrics: workStore.fetchMetrics,
renderResumeDataCache: (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache)
});
}
/**
* Crawlers will inadvertently think the canonicalUrl in the RSC payload should be crawled
* when our intention is to just seed the router state with the current URL.
* This function splits up the pathname so that we can later join it on
* when we're ready to consume the path.
*/ function prepareInitialCanonicalUrl(url) {
return (url.pathname + url.search).split('/');
}
// This is the data necessary to render <AppRouter /> when no SSR errors are encountered
async function getRSCPayload(tree, ctx, is404) {
const injectedCSS = new Set();
const injectedJS = new Set();
const injectedFontPreloadTags = new Set();
let missingSlots;
// We only track missing parallel slots in development
if (process.env.NODE_ENV === 'development') {
missingSlots = new Set();
}
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { createMetadataComponents, MetadataBoundary, ViewportBoundary }, url, workStore } = ctx;
const initialTree = (0, _createflightrouterstatefromloadertree.createFlightRouterStateFromLoaderTree)(tree, getDynamicParamFromSegment, query);
const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata;
const hasGlobalNotFound = !!tree[2]['global-not-found'];
const { ViewportTree, MetadataTree, getViewportReady, getMetadataReady, StreamingMetadataOutlet } = createMetadataComponents({
tree,
// When it's using global-not-found, metadata errorType is undefined, which will retrieve the
// metadata from the page.
// When it's using not-found, metadata errorType is 'not-found', which will retrieve the
// metadata from the not-found.js boundary.
// TODO: remove this condition and keep it undefined when global-not-found is stabilized.
errorType: is404 && !hasGlobalNotFound ? 'not-found' : undefined,
parsedQuery: query,
pathname: url.pathname,
metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts),
getDynamicParamFromSegment,
appUsingSizeAdjustment,
workStore,
MetadataBoundary,
ViewportBoundary,
serveStreamingMetadata
});
const preloadCallbacks = [];
const seedData = await (0, _createcomponenttree.createComponentTree)({
ctx,
loaderTree: tree,
parentParams: {},
injectedCSS,
injectedJS,
injectedFontPreloadTags,
rootLayoutIncluded: false,
getViewportReady,
getMetadataReady,
missingSlots,
preloadCallbacks,
authInterrupts: ctx.renderOpts.experimental.authInterrupts,
StreamingMetadataOutlet
});
// When the `vary` response header is present with `Next-URL`, that means there's a chance
// it could respond differently if there's an interception route. We provide this information
// to `AppRouter` so that it can properly seed the prefetch cache with a prefix, if needed.
const varyHeader = ctx.res.getHeader('vary');
const couldBeIntercepted = typeof varyHeader === 'string' && varyHeader.includes(_approuterheaders.NEXT_URL);
const initialHead = /*#__PURE__*/ (0, _jsxruntime.jsxs)(_react.default.Fragment, {
children: [
/*#__PURE__*/ (0, _jsxruntime.jsx)(NonIndex, {
pagePath: ctx.pagePath,
statusCode: ctx.res.statusCode,
isPossibleServerAction: ctx.isPossibleServerAction
}),
/*#__PURE__*/ (0, _jsxruntime.jsx)(ViewportTree, {}),
/*#__PURE__*/ (0, _jsxruntime.jsx)(MetadataTree, {})
]
}, flightDataPathHeadKey);
const { GlobalError, styles: globalErrorStyles } = await getGlobalErrorStyles(tree, ctx);
// Assume the head we're rendering contains only partial data if PPR is
// enabled and this is a statically generated response. This is used by the
// client Segment Cache after a prefetch to determine if it can skip the
// second request to fill in the dynamic data.
//
// See similar comment in create-component-tree.tsx for more context.
const isPossiblyPartialHead = workStore.isStaticGeneration && ctx.renderOpts.experimental.isRoutePPREnabled === true;
return {
// See the comment above the `Preloads` component (below) for why this is part of the payload
P: /*#__PURE__*/ (0, _jsxruntime.jsx)(Preloads, {
preloadCallbacks: preloadCallbacks
}),
b: ctx.sharedContext.buildId,
p: ctx.assetPrefix,
c: prepareInitialCanonicalUrl(url),
i: !!couldBeIntercepted,
f: [
[
initialTree,
seedData,
initialHead,
isPossiblyPartialHead
]
],
m: missingSlots,
G: [
GlobalError,
globalErrorStyles
],
s: typeof ctx.renderOpts.postponed === 'string',
S: workStore.isStaticGeneration
};
}
/**
* Preload calls (such as `ReactDOM.preloadStyle` and `ReactDOM.preloadFont`) need to be called during rendering
* in order to create the appropriate preload tags in the DOM, otherwise they're a no-op. Since we invoke
* renderToReadableStream with a function that returns component props rather than a component itself, we use
* this component to "render " the preload calls.
*/ function Preloads({ preloadCallbacks }) {
preloadCallbacks.forEach((preloadFn)=>preloadFn());
return null;
}
// This is the data necessary to render <AppRouter /> when an error state is triggered
async function getErrorRSCPayload(tree, ctx, ssrError, errorType) {
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { createMetadataComponents, MetadataBoundary, ViewportBoundary }, url, workStore } = ctx;
const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata;
const { MetadataTree, ViewportTree } = createMetadataComponents({
tree,
parsedQuery: query,
pathname: url.pathname,
metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts),
errorType,
getDynamicParamFromSegment,
appUsingSizeAdjustment,
workStore,
MetadataBoundary,
ViewportBoundary,
serveStreamingMetadata: serveStreamingMetadata
});
const initialHead = /*#__PURE__*/ (0, _jsxruntime.jsxs)(_react.default.Fragment, {
children: [
/*#__PURE__*/ (0, _jsxruntime.jsx)(NonIndex, {
pagePath: ctx.pagePath,
statusCode: ctx.res.statusCode,
isPossibleServerAction: ctx.isPossibleServerAction
}),
/*#__PURE__*/ (0, _jsxruntime.jsx)(ViewportTree, {}),
process.env.NODE_ENV === 'development' && /*#__PURE__*/ (0, _jsxruntime.jsx)("meta", {
name: "next-error",
content: "not-found"
}),
/*#__PURE__*/ (0, _jsxruntime.jsx)(MetadataTree, {})
]
}, flightDataPathHeadKey);
const initialTree = (0, _createflightrouterstatefromloadertree.createFlightRouterStateFromLoaderTree)(tree, getDynamicParamFromSegment, query);
let err = undefined;
if (ssrError) {
err = (0, _iserror.default)(ssrError) ? ssrError : Object.defineProperty(new Error(ssrError + ''), "__NEXT_ERROR_CODE", {
value: "E394",
enumerable: false,
configurable: true
});
}
// For metadata notFound error there's no global not found boundary on top
// so we create a not found page with AppRouter
const seedData = [
initialTree[0],
/*#__PURE__*/ (0, _jsxruntime.jsxs)("html", {
id: "__next_error__",
children: [
/*#__PURE__*/ (0, _jsxruntime.jsx)("head", {}),
/*#__PURE__*/ (0, _jsxruntime.jsx)("body", {
children: process.env.NODE_ENV !== 'production' && err ? /*#__PURE__*/ (0, _jsxruntime.jsx)("template", {
"data-next-error-message": err.message,
"data-next-error-digest": 'digest' in err ? err.digest : '',
"data-next-error-stack": err.stack
}) : null
})
]
}),
{},
null,
false
];
const { GlobalError, styles: globalErrorStyles } = await getGlobalErrorStyles(tree, ctx);
const isPossiblyPartialHead = workStore.isStaticGeneration && ctx.renderOpts.experimental.isRoutePPREnabled === true;
return {
b: ctx.sharedContext.buildId,
p: ctx.assetPrefix,
c: prepareInitialCanonicalUrl(url),
m: undefined,
i: false,
f: [
[
initialTree,
seedData,
initialHead,
isPossiblyPartialHead
]
],
G: [
GlobalError,
globalErrorStyles
],
s: typeof ctx.renderOpts.postponed === 'string',
S: workStore.isStaticGeneration
};
}
function assertClientReferenceManifest(clientReferenceManifest) {
if (!clientReferenceManifest) {
throw Object.defineProperty(new _invarianterror.InvariantError('Expected clientReferenceManifest to be defined.'), "__NEXT_ERROR_CODE", {
value: "E692",
enumerable: false,
configurable: true
});
}
}
// This component must run in an SSR context. It will render the RSC root component
function App({ reactServerStream, preinitScripts, clientReferenceManifest, ServerInsertedHTMLProvider, nonce }) {
preinitScripts();
const response = _react.default.use((0, _useflightresponse.useFlightStream)(reactServerStream, clientReferenceManifest, nonce));
const initialState = (0, _createinitialrouterstate.createInitialRouterState)({
// This is not used during hydration, so we don't have to pass a
// real timestamp.
navigatedAt: -1,
initialFlightData: response.f,
initialCanonicalUrlParts: response.c,
initialParallelRoutes: new Map(),
// location is not initialized in the SSR render
// it's set to window.location during hydration
location: null,
couldBeIntercepted: response.i,
postponed: response.s,
prerendered: response.S
});
const actionQueue = (0, _approuterinstance.createMutableActionQueue)(initialState, null);
const { HeadManagerContext } = require('../../shared/lib/head-manager-context.shared-runtime');
return /*#__PURE__*/ (0, _jsxruntime.jsx)(HeadManagerContext.Provider, {
value: {
appDir: true,
nonce
},
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(ServerInsertedHTMLProvider, {
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_approuter.default, {
actionQueue: actionQueue,
globalErrorState: response.G,
assetPrefix: response.p
})
})
});
}
// @TODO our error stream should be probably just use the same root component. But it was previously
// different I don't want to figure out if that is meaningful at this time so just keeping the behavior
// consistent for now.
function ErrorApp({ reactServerStream, preinitScripts, clientReferenceManifest, ServerInsertedHTMLProvider, nonce }) {
preinitScripts();
const response = _react.default.use((0, _useflightresponse.useFlightStream)(reactServerStream, clientReferenceManifest, nonce));
const initialState = (0, _createinitialrouterstate.createInitialRouterState)({
// This is not used during hydration, so we don't have to pass a
// real timestamp.
navigatedAt: -1,
initialFlightData: response.f,
initialCanonicalUrlParts: response.c,
initialParallelRoutes: new Map(),
// location is not initialized in the SSR render
// it's set to window.location during hydration
location: null,
couldBeIntercepted: response.i,
postponed: response.s,
prerendered: response.S
});
const actionQueue = (0, _approuterinstance.createMutableActionQueue)(initialState, null);
return /*#__PURE__*/ (0, _jsxruntime.jsx)(ServerInsertedHTMLProvider, {
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_approuter.default, {
actionQueue: actionQueue,
globalErrorState: response.G,
assetPrefix: response.p
})
});
}
async function renderToHTMLOrFlightImpl(req, res, url, pagePath, query, renderOpts, workStore, parsedRequestHeaders, postponedState, serverComponentsHmrCache, sharedContext, fallbackRouteParams) {
const isNotFoundPath = pagePath === '/404';
if (isNotFoundPath) {
res.statusCode = 404;
}
// A unique request timestamp used by development to ensure that it's
// consistent and won't change during this request. This is important to
// avoid that resources can be deduped by React Float if the same resource is
// rendered or preloaded multiple times: `<link href="a.css?v={Date.now()}"/>`.
const requestTimestamp = Date.now();
const { clientReferenceManifest, serverActionsManifest, ComponentMod, nextFontManifest, serverActions, assetPrefix = '', enableTainting } = renderOpts;
// We need to expose the bundled `require` API globally for
// react-server-dom-webpack. This is a hack until we find a better way.
if (ComponentMod.__next_app__) {
const instrumented = (0, _clientcomponentrendererlogger.wrapClientComponentLoader)(ComponentMod);
// When we are prerendering if there is a cacheSignal for tracking
// cache reads we track calls to `loadChunk` and `require`. This allows us
// to treat chunk/module loading with similar semantics as cache reads to avoid
// module loading from causing a prerender to abort too early.
const shouldTrackModuleLoading = ()=>{
if (!renderOpts.experimental.cacheComponents) {
return false;
}
if (renderOpts.dev) {
return true;
}
const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();
if (!workUnitStore) {
return false;
}
switch(workUnitStore.type){
case 'prerender':
case 'prerender-client':
case 'prerender-runtime':
case 'cache':
case 'private-cache':
return true;
case 'prerender-ppr':
case 'prerender-legacy':
case 'request':
case 'unstable-cache':
return false;
default:
workUnitStore;
}
};
const __next_require__ = (...args)=>{
const exportsOrPromise = instrumented.require(...args);
if (shouldTrackModuleLoading()) {
// requiring an async module returns a promise.
(0, _trackmoduleloadingexternal.trackPendingImport)(exportsOrPromise);
}
return exportsOrPromise;
};
// @ts-expect-error
globalThis.__next_require__ = __next_require__;
const __next_chunk_load__ = (...args)=>{
const loadingChunk = instrumented.loadChunk(...args);
if (shouldTrackModuleLoading()) {
(0, _trackmoduleloadingexternal.trackPendingChunkLoad)(loadingChunk);
}
return loadingChunk;
};
// @ts-expect-error
globalThis.__next_chunk_load__ = __next_chunk_load__;
}
if (process.env.NODE_ENV === 'development') {
// reset isr status at start of request
const { pathname } = new URL(req.url || '/', 'http://n');
renderOpts.setIsrStatus == null ? void 0 : renderOpts.setIsrStatus.call(renderOpts, pathname, null);
}
if (// The type check here ensures that `req` is correctly typed, and the
// environment variable check provides dead code elimination.
process.env.NEXT_RUNTIME !== 'edge' && (0, _helpers.isNodeNextRequest)(req)) {
res.onClose(()=>{
// We stop tracking fetch metrics when the response closes, since we
// report them at that time.
workStore.shouldTrackFetchMetrics = false;
});
req.originalRequest.on('end', ()=>{
if ('performance' in globalThis) {
const metrics = (0, _clientcomponentrendererlogger.getClientComponentLoaderMetrics)({
reset: true
});
if (metrics) {
(0, _tracer.getTracer)().startSpan(_constants.NextNodeServerSpan.clientComponentLoading, {
startTime: metrics.clientComponentLoadStart,
attributes: {
'next.clientComponentLoadCount': metrics.clientComponentLoadCount,
'next.span_type': _constants.NextNodeServerSpan.clientComponentLoading
}
}).end(metrics.clientComponentLoadStart + metrics.clientComponentLoadTimes);
}
}
});
}
const metadata = {
statusCode: isNotFoundPath ? 404 : undefined
};
const appUsingSizeAdjustment = !!(nextFontManifest == null ? void 0 : nextFontManifest.appUsingSizeAdjust);
assertClientReferenceManifest(clientReferenceManifest);
const serverModuleMap = (0, _actionutils.createServerModuleMap)({
serverActionsManifest
});
(0, _encryptionutils.setReferenceManifestsSingleton)({
page: workStore.page,
clientReferenceManifest,
serverActionsManifest,
serverModuleMap
});
ComponentMod.patchFetch();
// Pull out the hooks/references from the component.
const { tree: loaderTree, taintObjectReference } = ComponentMod;
if (enableTainting) {
taintObjectReference('Do not pass process.env to Client Components since it will leak sensitive data', process.env);
}
workStore.fetchMetrics = [];
metadata.fetchMetrics = workStore.fetchMetrics;
// don't modify original query object
query = {
...query
};
(0, _internalutils.stripInternalQueries)(query);
const { flightRouterState, isPrefetchRequest, isRuntimePrefetchRequest, isRSCRequest, isDevWarmupRequest, isHmrRefresh, nonce } = parsedRequestHeaders;
const { isStaticGeneration } = workStore;
/**
* The metadata items array created in next-app-loader with all relevant information
* that we need to resolve the final metadata.
*/ let requestId;
if (isStaticGeneration) {
requestId = Buffer.from(await crypto.subtle.digest('SHA-1', Buffer.from(req.url))).toString('hex');
} else if (process.env.NEXT_RUNTIME === 'edge') {
requestId = crypto.randomUUID();
} else {
requestId = require('next/dist/compiled/nanoid').nanoid();
}
/**
* Dynamic parameters. E.g. when you visi