Initial boiler plate project
This commit is contained in:
962
node_modules/next/dist/esm/server/app-render/app-render.js
generated
vendored
Normal file
962
node_modules/next/dist/esm/server/app-render/app-render.js
generated
vendored
Normal file
@ -0,0 +1,962 @@
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import React from "react";
|
||||
import RenderResult from "../render-result";
|
||||
import { chainStreams, renderToInitialFizzStream, continueFizzStream, continueDynamicPrerender, continueStaticPrerender, continueDynamicHTMLResume, continueDynamicDataResume } from "../stream-utils/node-web-streams-helper";
|
||||
import { canSegmentBeOverridden } from "../../client/components/match-segments";
|
||||
import { stripInternalQueries } from "../internal-utils";
|
||||
import { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE, NEXT_URL, RSC_HEADER } from "../../client/components/app-router-headers";
|
||||
import { createMetadataComponents, createMetadataContext } from "../../lib/metadata/metadata";
|
||||
import { RequestAsyncStorageWrapper } from "../async-storage/request-async-storage-wrapper";
|
||||
import { StaticGenerationAsyncStorageWrapper } from "../async-storage/static-generation-async-storage-wrapper";
|
||||
import { isNotFoundError } from "../../client/components/not-found";
|
||||
import { getURLFromRedirectError, isRedirectError, getRedirectStatusCodeFromError } from "../../client/components/redirect";
|
||||
import { addImplicitTags } from "../lib/patch-fetch";
|
||||
import { AppRenderSpan, NextNodeServerSpan } from "../lib/trace/constants";
|
||||
import { getTracer } from "../lib/trace/tracer";
|
||||
import { FlightRenderResult } from "./flight-render-result";
|
||||
import { createErrorHandler, ErrorHandlerSource } from "./create-error-handler";
|
||||
import { getShortDynamicParamType, dynamicParamTypes } from "./get-short-dynamic-param-type";
|
||||
import { getSegmentParam } from "./get-segment-param";
|
||||
import { getScriptNonceFromHeader } from "./get-script-nonce-from-header";
|
||||
import { parseAndValidateFlightRouterState } from "./parse-and-validate-flight-router-state";
|
||||
import { validateURL } from "./validate-url";
|
||||
import { createFlightRouterStateFromLoaderTree } from "./create-flight-router-state-from-loader-tree";
|
||||
import { handleAction } from "./action-handler";
|
||||
import { isBailoutToCSRError } from "../../shared/lib/lazy-dynamic/bailout-to-csr";
|
||||
import { warn, error } from "../../build/output/log";
|
||||
import { appendMutableCookies } from "../web/spec-extension/adapters/request-cookies";
|
||||
import { createServerInsertedHTML } from "./server-inserted-html";
|
||||
import { getRequiredScripts } from "./required-scripts";
|
||||
import { addPathPrefix } from "../../shared/lib/router/utils/add-path-prefix";
|
||||
import { makeGetServerInsertedHTML } from "./make-get-server-inserted-html";
|
||||
import { walkTreeWithFlightRouterState } from "./walk-tree-with-flight-router-state";
|
||||
import { createComponentTree } from "./create-component-tree";
|
||||
import { getAssetQueryString } from "./get-asset-query-string";
|
||||
import { setReferenceManifestsSingleton } from "./encryption-utils";
|
||||
import { createStaticRenderer, getDynamicDataPostponedState, getDynamicHTMLPostponedState } from "./static/static-renderer";
|
||||
import { isDynamicServerError } from "../../client/components/hooks-server-context";
|
||||
import { useFlightStream, createInlinedDataReadableStream, flightRenderComplete } from "./use-flight-response";
|
||||
import { StaticGenBailoutError, isStaticGenBailoutError } from "../../client/components/static-generation-bailout";
|
||||
import { isInterceptionRouteAppPath } from "../future/helpers/interception-routes";
|
||||
import { getStackWithoutErrorMessage } from "../../lib/format-server-error";
|
||||
import { usedDynamicAPIs, createPostponedAbortSignal, formatDynamicAPIAccesses } from "./dynamic-rendering";
|
||||
import { getClientComponentLoaderMetrics, wrapClientComponentLoader } from "../client-component-renderer-logger";
|
||||
import { createServerModuleMap } from "./action-utils";
|
||||
function createNotFoundLoaderTree(loaderTree) {
|
||||
// Align the segment with parallel-route-default in next-app-loader
|
||||
return [
|
||||
"",
|
||||
{},
|
||||
loaderTree[2]
|
||||
];
|
||||
}
|
||||
/* This method is important for intercepted routes to function:
|
||||
* when a route is intercepted, e.g. /blog/[slug], it will be rendered
|
||||
* with the layout of the previous page, e.g. /profile/[id]. The problem is
|
||||
* that the loader tree needs to know the dynamic param in order to render (id and slug in the example).
|
||||
* Normally they are read from the path but since we are intercepting the route, the path would not contain id,
|
||||
* so we need to read it from the router state.
|
||||
*/ function findDynamicParamFromRouterState(flightRouterState, segment) {
|
||||
if (!flightRouterState) {
|
||||
return null;
|
||||
}
|
||||
const treeSegment = flightRouterState[0];
|
||||
if (canSegmentBeOverridden(segment, treeSegment)) {
|
||||
if (!Array.isArray(treeSegment) || Array.isArray(segment)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
param: treeSegment[0],
|
||||
value: treeSegment[1],
|
||||
treeSegment: treeSegment,
|
||||
type: treeSegment[2]
|
||||
};
|
||||
}
|
||||
for (const parallelRouterState of Object.values(flightRouterState[1])){
|
||||
const maybeDynamicParam = findDynamicParamFromRouterState(parallelRouterState, segment);
|
||||
if (maybeDynamicParam) {
|
||||
return maybeDynamicParam;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns a function that parses the dynamic segment and return the associated value.
|
||||
*/ function makeGetDynamicParamFromSegment(params, flightRouterState) {
|
||||
return function getDynamicParamFromSegment(// [slug] / [[slug]] / [...slug]
|
||||
segment) {
|
||||
const segmentParam = getSegmentParam(segment);
|
||||
if (!segmentParam) {
|
||||
return null;
|
||||
}
|
||||
const key = segmentParam.param;
|
||||
let value = params[key];
|
||||
// this is a special marker that will be present for interception routes
|
||||
if (value === "__NEXT_EMPTY_PARAM__") {
|
||||
value = undefined;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
value = value.map((i)=>encodeURIComponent(i));
|
||||
} else if (typeof value === "string") {
|
||||
value = encodeURIComponent(value);
|
||||
}
|
||||
if (!value) {
|
||||
// Handle case where optional catchall does not have a value, e.g. `/dashboard/[...slug]` when requesting `/dashboard`
|
||||
if (segmentParam.type === "optional-catchall") {
|
||||
const type = dynamicParamTypes[segmentParam.type];
|
||||
return {
|
||||
param: key,
|
||||
value: null,
|
||||
type: type,
|
||||
// This value always has to be a string.
|
||||
treeSegment: [
|
||||
key,
|
||||
"",
|
||||
type
|
||||
]
|
||||
};
|
||||
}
|
||||
return findDynamicParamFromRouterState(flightRouterState, segment);
|
||||
}
|
||||
const type = getShortDynamicParamType(segmentParam.type);
|
||||
return {
|
||||
param: key,
|
||||
// The value that is passed to user code.
|
||||
value: value,
|
||||
// The value that is rendered in the router tree.
|
||||
treeSegment: [
|
||||
key,
|
||||
Array.isArray(value) ? value.join("/") : value,
|
||||
type
|
||||
],
|
||||
type: type
|
||||
};
|
||||
};
|
||||
}
|
||||
function NonIndex({ ctx }) {
|
||||
const is404Page = ctx.pagePath === "/404";
|
||||
const isInvalidStatusCode = typeof ctx.res.statusCode === "number" && ctx.res.statusCode > 400;
|
||||
if (is404Page || isInvalidStatusCode) {
|
||||
return /*#__PURE__*/ _jsx("meta", {
|
||||
name: "robots",
|
||||
content: "noindex"
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Handle Flight render request. This is only used when client-side navigating. E.g. when you `router.push('/dashboard')` or `router.reload()`.
|
||||
async function generateFlight(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.
|
||||
let flightData = null;
|
||||
const { componentMod: { tree: loaderTree, renderToReadableStream, createDynamicallyTrackedSearchParams }, getDynamicParamFromSegment, appUsingSizeAdjustment, staticGenerationStore: { urlPathname }, query, requestId, flightRouterState } = ctx;
|
||||
if (!(options == null ? void 0 : options.skipFlight)) {
|
||||
const [MetadataTree, MetadataOutlet] = createMetadataComponents({
|
||||
tree: loaderTree,
|
||||
query,
|
||||
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
|
||||
getDynamicParamFromSegment,
|
||||
appUsingSizeAdjustment,
|
||||
createDynamicallyTrackedSearchParams
|
||||
});
|
||||
flightData = (await walkTreeWithFlightRouterState({
|
||||
ctx,
|
||||
createSegmentPath: (child)=>child,
|
||||
loaderTreeToFilter: loaderTree,
|
||||
parentParams: {},
|
||||
flightRouterState,
|
||||
isFirst: true,
|
||||
// For flight, render metadata inside leaf page
|
||||
// NOTE: in 14.2, fragment doesn't work well with React, using array instead
|
||||
rscPayloadHead: [
|
||||
/*#__PURE__*/ _jsx(MetadataTree, {}, requestId),
|
||||
/*#__PURE__*/ _jsx(NonIndex, {
|
||||
ctx: ctx
|
||||
}, "noindex")
|
||||
],
|
||||
injectedCSS: new Set(),
|
||||
injectedJS: new Set(),
|
||||
injectedFontPreloadTags: new Set(),
|
||||
rootLayoutIncluded: false,
|
||||
asNotFound: ctx.isNotFoundPath || (options == null ? void 0 : options.asNotFound),
|
||||
metadataOutlet: /*#__PURE__*/ _jsx(MetadataOutlet, {})
|
||||
})).map((path)=>path.slice(1)) // remove the '' (root) segment
|
||||
;
|
||||
}
|
||||
const buildIdFlightDataPair = [
|
||||
ctx.renderOpts.buildId,
|
||||
flightData
|
||||
];
|
||||
// For app dir, use the bundled version of Flight server renderer (renderToReadableStream)
|
||||
// which contains the subset React.
|
||||
const flightReadableStream = renderToReadableStream(options ? [
|
||||
options.actionResult,
|
||||
buildIdFlightDataPair
|
||||
] : buildIdFlightDataPair, ctx.clientReferenceManifest.clientModules, {
|
||||
onError: ctx.flightDataRendererErrorHandler
|
||||
});
|
||||
return new FlightRenderResult(flightReadableStream);
|
||||
}
|
||||
/**
|
||||
* Creates a resolver that eagerly generates a flight payload that is then
|
||||
* resolved when the resolver is called.
|
||||
*/ function createFlightDataResolver(ctx) {
|
||||
// Generate the flight data and as soon as it can, convert it into a string.
|
||||
const promise = generateFlight(ctx).then(async (result)=>({
|
||||
flightData: await result.toUnchunkedString(true)
|
||||
}))// Otherwise if it errored, return the error.
|
||||
.catch((err)=>({
|
||||
err
|
||||
}));
|
||||
return async ()=>{
|
||||
// Resolve the promise to get the flight data or error.
|
||||
const result = await promise;
|
||||
// If the flight data failed to render due to an error, re-throw the error
|
||||
// here.
|
||||
if ("err" in result) {
|
||||
throw result.err;
|
||||
}
|
||||
// Otherwise, return the flight data.
|
||||
return result.flightData;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 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(pathname) {
|
||||
return pathname.split("/");
|
||||
}
|
||||
// This is the root component that runs in the RSC context
|
||||
async function ReactServerApp({ tree, ctx, asNotFound }) {
|
||||
// Create full component tree from root to leaf.
|
||||
const injectedCSS = new Set();
|
||||
const injectedJS = new Set();
|
||||
const injectedFontPreloadTags = new Set();
|
||||
const missingSlots = new Set();
|
||||
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { AppRouter, GlobalError, createDynamicallyTrackedSearchParams }, staticGenerationStore: { urlPathname } } = ctx;
|
||||
const initialTree = createFlightRouterStateFromLoaderTree(tree, getDynamicParamFromSegment, query);
|
||||
const [MetadataTree, MetadataOutlet] = createMetadataComponents({
|
||||
tree,
|
||||
errorType: asNotFound ? "not-found" : undefined,
|
||||
query,
|
||||
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
|
||||
getDynamicParamFromSegment: getDynamicParamFromSegment,
|
||||
appUsingSizeAdjustment: appUsingSizeAdjustment,
|
||||
createDynamicallyTrackedSearchParams
|
||||
});
|
||||
const seedData = await createComponentTree({
|
||||
ctx,
|
||||
createSegmentPath: (child)=>child,
|
||||
loaderTree: tree,
|
||||
parentParams: {},
|
||||
firstItem: true,
|
||||
injectedCSS,
|
||||
injectedJS,
|
||||
injectedFontPreloadTags,
|
||||
rootLayoutIncluded: false,
|
||||
asNotFound: asNotFound,
|
||||
metadataOutlet: /*#__PURE__*/ _jsx(MetadataOutlet, {}),
|
||||
missingSlots
|
||||
});
|
||||
// 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(NEXT_URL);
|
||||
return /*#__PURE__*/ _jsx(AppRouter, {
|
||||
buildId: ctx.renderOpts.buildId,
|
||||
assetPrefix: ctx.assetPrefix,
|
||||
urlParts: prepareInitialCanonicalUrl(urlPathname),
|
||||
// This is the router state tree.
|
||||
initialTree: initialTree,
|
||||
// This is the tree of React nodes that are seeded into the cache
|
||||
initialSeedData: seedData,
|
||||
couldBeIntercepted: couldBeIntercepted,
|
||||
initialHead: /*#__PURE__*/ _jsxs(_Fragment, {
|
||||
children: [
|
||||
/*#__PURE__*/ _jsx(NonIndex, {
|
||||
ctx: ctx
|
||||
}),
|
||||
/*#__PURE__*/ _jsx(MetadataTree, {}, ctx.requestId)
|
||||
]
|
||||
}),
|
||||
globalErrorComponent: GlobalError,
|
||||
// This is used to provide debug information (when in development mode)
|
||||
// about which slots were not filled by page components while creating the component tree.
|
||||
missingSlots: missingSlots
|
||||
});
|
||||
}
|
||||
// This is the root component that runs in the RSC context
|
||||
async function ReactServerError({ tree, ctx, errorType }) {
|
||||
const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { AppRouter, GlobalError, createDynamicallyTrackedSearchParams }, staticGenerationStore: { urlPathname }, requestId } = ctx;
|
||||
const [MetadataTree] = createMetadataComponents({
|
||||
tree,
|
||||
metadataContext: createMetadataContext(urlPathname, ctx.renderOpts),
|
||||
errorType,
|
||||
query,
|
||||
getDynamicParamFromSegment,
|
||||
appUsingSizeAdjustment,
|
||||
createDynamicallyTrackedSearchParams
|
||||
});
|
||||
const head = /*#__PURE__*/ _jsxs(_Fragment, {
|
||||
children: [
|
||||
/*#__PURE__*/ _jsx(MetadataTree, {}, requestId),
|
||||
process.env.NODE_ENV === "development" && /*#__PURE__*/ _jsx("meta", {
|
||||
name: "next-error",
|
||||
content: "not-found"
|
||||
}),
|
||||
/*#__PURE__*/ _jsx(NonIndex, {
|
||||
ctx: ctx
|
||||
})
|
||||
]
|
||||
});
|
||||
const initialTree = createFlightRouterStateFromLoaderTree(tree, getDynamicParamFromSegment, query);
|
||||
// For metadata notFound error there's no global not found boundary on top
|
||||
// so we create a not found page with AppRouter
|
||||
const initialSeedData = [
|
||||
initialTree[0],
|
||||
{},
|
||||
/*#__PURE__*/ _jsxs("html", {
|
||||
id: "__next_error__",
|
||||
children: [
|
||||
/*#__PURE__*/ _jsx("head", {}),
|
||||
/*#__PURE__*/ _jsx("body", {})
|
||||
]
|
||||
}),
|
||||
null
|
||||
];
|
||||
return /*#__PURE__*/ _jsx(AppRouter, {
|
||||
buildId: ctx.renderOpts.buildId,
|
||||
assetPrefix: ctx.assetPrefix,
|
||||
urlParts: prepareInitialCanonicalUrl(urlPathname),
|
||||
initialTree: initialTree,
|
||||
initialHead: head,
|
||||
globalErrorComponent: GlobalError,
|
||||
initialSeedData: initialSeedData,
|
||||
missingSlots: new Set()
|
||||
});
|
||||
}
|
||||
// This component must run in an SSR context. It will render the RSC root component
|
||||
function ReactServerEntrypoint({ reactServerStream, preinitScripts, clientReferenceManifest, nonce }) {
|
||||
preinitScripts();
|
||||
const response = useFlightStream(reactServerStream, clientReferenceManifest, nonce);
|
||||
return React.use(response);
|
||||
}
|
||||
async function renderToHTMLOrFlightImpl(req, res, pagePath, query, renderOpts, baseCtx, requestEndedState) {
|
||||
var _getTracer_getRootSpanAttributes, _staticGenerationStore_prerenderState;
|
||||
const isNotFoundPath = pagePath === "/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 { buildManifest, subresourceIntegrityManifest, serverActionsManifest, ComponentMod, dev, nextFontManifest, supportsDynamicResponse, serverActions, appDirDevErrorLogger, 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 = wrapClientComponentLoader(ComponentMod);
|
||||
// @ts-ignore
|
||||
globalThis.__next_require__ = instrumented.require;
|
||||
// @ts-ignore
|
||||
globalThis.__next_chunk_load__ = instrumented.loadChunk;
|
||||
}
|
||||
if (typeof req.on === "function") {
|
||||
req.on("end", ()=>{
|
||||
requestEndedState.ended = true;
|
||||
if ("performance" in globalThis) {
|
||||
const metrics = getClientComponentLoaderMetrics({
|
||||
reset: true
|
||||
});
|
||||
if (metrics) {
|
||||
getTracer().startSpan(NextNodeServerSpan.clientComponentLoading, {
|
||||
startTime: metrics.clientComponentLoadStart,
|
||||
attributes: {
|
||||
"next.clientComponentLoadCount": metrics.clientComponentLoadCount
|
||||
}
|
||||
}).end(metrics.clientComponentLoadStart + metrics.clientComponentLoadTimes);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const metadata = {};
|
||||
const appUsingSizeAdjustment = !!(nextFontManifest == null ? void 0 : nextFontManifest.appUsingSizeAdjust);
|
||||
// TODO: fix this typescript
|
||||
const clientReferenceManifest = renderOpts.clientReferenceManifest;
|
||||
const serverModuleMap = createServerModuleMap({
|
||||
serverActionsManifest,
|
||||
pageName: renderOpts.page
|
||||
});
|
||||
setReferenceManifestsSingleton({
|
||||
clientReferenceManifest,
|
||||
serverActionsManifest,
|
||||
serverModuleMap
|
||||
});
|
||||
const digestErrorsMap = new Map();
|
||||
const allCapturedErrors = [];
|
||||
const isNextExport = !!renderOpts.nextExport;
|
||||
const { staticGenerationStore, requestStore } = baseCtx;
|
||||
const { isStaticGeneration } = staticGenerationStore;
|
||||
// when static generation fails during PPR, we log the errors separately. We intentionally
|
||||
// silence the error logger in this case to avoid double logging.
|
||||
const silenceStaticGenerationErrors = renderOpts.experimental.ppr && isStaticGeneration;
|
||||
const serverComponentsErrorHandler = createErrorHandler({
|
||||
source: ErrorHandlerSource.serverComponents,
|
||||
dev,
|
||||
isNextExport,
|
||||
errorLogger: appDirDevErrorLogger,
|
||||
digestErrorsMap,
|
||||
silenceLogger: silenceStaticGenerationErrors
|
||||
});
|
||||
const flightDataRendererErrorHandler = createErrorHandler({
|
||||
source: ErrorHandlerSource.flightData,
|
||||
dev,
|
||||
isNextExport,
|
||||
errorLogger: appDirDevErrorLogger,
|
||||
digestErrorsMap,
|
||||
silenceLogger: silenceStaticGenerationErrors
|
||||
});
|
||||
const htmlRendererErrorHandler = createErrorHandler({
|
||||
source: ErrorHandlerSource.html,
|
||||
dev,
|
||||
isNextExport,
|
||||
errorLogger: appDirDevErrorLogger,
|
||||
digestErrorsMap,
|
||||
allCapturedErrors,
|
||||
silenceLogger: silenceStaticGenerationErrors
|
||||
});
|
||||
ComponentMod.patchFetch();
|
||||
/**
|
||||
* Rules of Static & Dynamic HTML:
|
||||
*
|
||||
* 1.) We must generate static HTML unless the caller explicitly opts
|
||||
* in to dynamic HTML support.
|
||||
*
|
||||
* 2.) If dynamic HTML support is requested, we must honor that request
|
||||
* or throw an error. It is the sole responsibility of the caller to
|
||||
* ensure they aren't e.g. requesting dynamic HTML for an AMP page.
|
||||
*
|
||||
* These rules help ensure that other existing features like request caching,
|
||||
* coalescing, and ISR continue working as intended.
|
||||
*/ const generateStaticHTML = supportsDynamicResponse !== true;
|
||||
// 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);
|
||||
}
|
||||
staticGenerationStore.fetchMetrics = [];
|
||||
metadata.fetchMetrics = staticGenerationStore.fetchMetrics;
|
||||
// don't modify original query object
|
||||
query = {
|
||||
...query
|
||||
};
|
||||
stripInternalQueries(query);
|
||||
const isRSCRequest = req.headers[RSC_HEADER.toLowerCase()] !== undefined;
|
||||
const isPrefetchRSCRequest = isRSCRequest && req.headers[NEXT_ROUTER_PREFETCH_HEADER.toLowerCase()] !== undefined;
|
||||
/**
|
||||
* Router state provided from the client-side router. Used to handle rendering
|
||||
* from the common layout down. This value will be undefined if the request
|
||||
* is not a client-side navigation request or if the request is a prefetch
|
||||
* request (except when it's a prefetch request for an interception route
|
||||
* which is always dynamic).
|
||||
*/ const shouldProvideFlightRouterState = isRSCRequest && (!isPrefetchRSCRequest || !renderOpts.experimental.ppr || // Interception routes currently depend on the flight router state to
|
||||
// extract dynamic params.
|
||||
isInterceptionRouteAppPath(pagePath));
|
||||
const parsedFlightRouterState = parseAndValidateFlightRouterState(req.headers[NEXT_ROUTER_STATE_TREE.toLowerCase()]);
|
||||
/**
|
||||
* The metadata items array created in next-app-loader with all relevant information
|
||||
* that we need to resolve the final metadata.
|
||||
*/ let requestId;
|
||||
if (process.env.NEXT_RUNTIME === "edge") {
|
||||
requestId = crypto.randomUUID();
|
||||
} else {
|
||||
requestId = require("next/dist/compiled/nanoid").nanoid();
|
||||
}
|
||||
/**
|
||||
* Dynamic parameters. E.g. when you visit `/dashboard/vercel` which is rendered by `/dashboard/[slug]` the value will be {"slug": "vercel"}.
|
||||
*/ const params = renderOpts.params ?? {};
|
||||
const getDynamicParamFromSegment = makeGetDynamicParamFromSegment(params, // `FlightRouterState` is unconditionally provided here because this method uses it
|
||||
// to extract dynamic params as a fallback if they're not present in the path.
|
||||
parsedFlightRouterState);
|
||||
const ctx = {
|
||||
...baseCtx,
|
||||
getDynamicParamFromSegment,
|
||||
query,
|
||||
isPrefetch: isPrefetchRSCRequest,
|
||||
requestTimestamp,
|
||||
appUsingSizeAdjustment,
|
||||
flightRouterState: shouldProvideFlightRouterState ? parsedFlightRouterState : undefined,
|
||||
requestId,
|
||||
defaultRevalidate: false,
|
||||
pagePath,
|
||||
clientReferenceManifest,
|
||||
assetPrefix,
|
||||
flightDataRendererErrorHandler,
|
||||
serverComponentsErrorHandler,
|
||||
isNotFoundPath,
|
||||
res
|
||||
};
|
||||
if (isRSCRequest && !isStaticGeneration) {
|
||||
return generateFlight(ctx);
|
||||
}
|
||||
// Create the resolver that can get the flight payload when it's ready or
|
||||
// throw the error if it occurred. If we are not generating static HTML, we
|
||||
// don't need to generate the flight payload because it's a dynamic request
|
||||
// which means we're either getting the flight payload only or just the
|
||||
// regular HTML.
|
||||
const flightDataResolver = isStaticGeneration ? createFlightDataResolver(ctx) : null;
|
||||
// Get the nonce from the incoming request if it has one.
|
||||
const csp = req.headers["content-security-policy"] || req.headers["content-security-policy-report-only"];
|
||||
let nonce;
|
||||
if (csp && typeof csp === "string") {
|
||||
nonce = getScriptNonceFromHeader(csp);
|
||||
}
|
||||
const validateRootLayout = dev;
|
||||
const { HeadManagerContext } = require("../../shared/lib/head-manager-context.shared-runtime");
|
||||
// On each render, create a new `ServerInsertedHTML` context to capture
|
||||
// injected nodes from user code (`useServerInsertedHTML`).
|
||||
const { ServerInsertedHTMLProvider, renderServerInsertedHTML } = createServerInsertedHTML();
|
||||
(_getTracer_getRootSpanAttributes = getTracer().getRootSpanAttributes()) == null ? void 0 : _getTracer_getRootSpanAttributes.set("next.route", pagePath);
|
||||
const renderToStream = getTracer().wrap(AppRenderSpan.getBodyResult, {
|
||||
spanName: `render route (app) ${pagePath}`,
|
||||
attributes: {
|
||||
"next.route": pagePath
|
||||
}
|
||||
}, async ({ asNotFound, tree, formState })=>{
|
||||
const polyfills = buildManifest.polyfillFiles.filter((polyfill)=>polyfill.endsWith(".js") && !polyfill.endsWith(".module.js")).map((polyfill)=>({
|
||||
src: `${assetPrefix}/_next/${polyfill}${getAssetQueryString(ctx, false)}`,
|
||||
integrity: subresourceIntegrityManifest == null ? void 0 : subresourceIntegrityManifest[polyfill],
|
||||
crossOrigin: renderOpts.crossOrigin,
|
||||
noModule: true,
|
||||
nonce
|
||||
}));
|
||||
const [preinitScripts, bootstrapScript] = getRequiredScripts(buildManifest, assetPrefix, renderOpts.crossOrigin, subresourceIntegrityManifest, getAssetQueryString(ctx, true), nonce);
|
||||
// We kick off the Flight Request (render) here. It is ok to initiate the render in an arbitrary
|
||||
// place however it is critical that we only construct the Flight Response inside the SSR
|
||||
// render so that directives like preloads are correctly piped through
|
||||
const serverStream = ComponentMod.renderToReadableStream(/*#__PURE__*/ _jsx(ReactServerApp, {
|
||||
tree: tree,
|
||||
ctx: ctx,
|
||||
asNotFound: asNotFound
|
||||
}), clientReferenceManifest.clientModules, {
|
||||
onError: serverComponentsErrorHandler
|
||||
});
|
||||
// We are going to consume this render both for SSR and for inlining the flight data
|
||||
let [renderStream, dataStream] = serverStream.tee();
|
||||
const children = /*#__PURE__*/ _jsx(HeadManagerContext.Provider, {
|
||||
value: {
|
||||
appDir: true,
|
||||
nonce
|
||||
},
|
||||
children: /*#__PURE__*/ _jsx(ServerInsertedHTMLProvider, {
|
||||
children: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
|
||||
reactServerStream: renderStream,
|
||||
preinitScripts: preinitScripts,
|
||||
clientReferenceManifest: clientReferenceManifest,
|
||||
nonce: nonce
|
||||
})
|
||||
})
|
||||
});
|
||||
const isResume = !!renderOpts.postponed;
|
||||
const onHeaders = staticGenerationStore.prerenderState ? (headers)=>{
|
||||
headers.forEach((value, key)=>{
|
||||
metadata.headers ??= {};
|
||||
metadata.headers[key] = value;
|
||||
});
|
||||
} : isStaticGeneration || isResume ? // ask React to emit headers. For Resume this is just not supported
|
||||
// For static generation we know there will be an entire HTML document
|
||||
// output and so moving from tag to header for preloading can only
|
||||
// server to alter preloading priorities in unwanted ways
|
||||
undefined : // early headers to the response
|
||||
(headers)=>{
|
||||
headers.forEach((value, key)=>{
|
||||
res.appendHeader(key, value);
|
||||
});
|
||||
};
|
||||
const getServerInsertedHTML = makeGetServerInsertedHTML({
|
||||
polyfills,
|
||||
renderServerInsertedHTML,
|
||||
serverCapturedErrors: allCapturedErrors,
|
||||
basePath: renderOpts.basePath
|
||||
});
|
||||
const renderer = createStaticRenderer({
|
||||
ppr: renderOpts.experimental.ppr,
|
||||
isStaticGeneration,
|
||||
// If provided, the postpone state should be parsed as JSON so it can be
|
||||
// provided to React.
|
||||
postponed: typeof renderOpts.postponed === "string" ? JSON.parse(renderOpts.postponed) : null,
|
||||
streamOptions: {
|
||||
onError: htmlRendererErrorHandler,
|
||||
onHeaders,
|
||||
maxHeadersLength: 600,
|
||||
nonce,
|
||||
bootstrapScripts: [
|
||||
bootstrapScript
|
||||
],
|
||||
formState
|
||||
}
|
||||
});
|
||||
try {
|
||||
let { stream, postponed, resumed } = await renderer.render(children);
|
||||
const prerenderState = staticGenerationStore.prerenderState;
|
||||
if (prerenderState) {
|
||||
/**
|
||||
* When prerendering there are three outcomes to consider
|
||||
*
|
||||
* Dynamic HTML: The prerender has dynamic holes (caused by using Next.js Dynamic Rendering APIs)
|
||||
* We will need to resume this result when requests are handled and we don't include
|
||||
* any server inserted HTML or inlined flight data in the static HTML
|
||||
*
|
||||
* Dynamic Data: The prerender has no dynamic holes but dynamic APIs were used. We will not
|
||||
* resume this render when requests are handled but we will generate new inlined
|
||||
* flight data since it is dynamic and differences may end up reconciling on the client
|
||||
*
|
||||
* Static: The prerender has no dynamic holes and no dynamic APIs were used. We statically encode
|
||||
* all server inserted HTML and flight data
|
||||
*/ // First we check if we have any dynamic holes in our HTML prerender
|
||||
if (usedDynamicAPIs(prerenderState)) {
|
||||
if (postponed != null) {
|
||||
// This is the Dynamic HTML case.
|
||||
metadata.postponed = JSON.stringify(getDynamicHTMLPostponedState(postponed));
|
||||
} else {
|
||||
// This is the Dynamic Data case
|
||||
metadata.postponed = JSON.stringify(getDynamicDataPostponedState());
|
||||
}
|
||||
// Regardless of whether this is the Dynamic HTML or Dynamic Data case we need to ensure we include
|
||||
// server inserted html in the static response because the html that is part of the prerender may depend on it
|
||||
// It is possible in the set of stream transforms for Dynamic HTML vs Dynamic Data may differ but currently both states
|
||||
// require the same set so we unify the code path here
|
||||
return {
|
||||
stream: await continueDynamicPrerender(stream, {
|
||||
getServerInsertedHTML
|
||||
})
|
||||
};
|
||||
} else {
|
||||
// We may still be rendering the RSC stream even though the HTML is finished.
|
||||
// We wait for the RSC stream to complete and check again if dynamic was used
|
||||
const [original, flightSpy] = dataStream.tee();
|
||||
dataStream = original;
|
||||
await flightRenderComplete(flightSpy);
|
||||
if (usedDynamicAPIs(prerenderState)) {
|
||||
// This is the same logic above just repeated after ensuring the RSC stream itself has completed
|
||||
if (postponed != null) {
|
||||
// This is the Dynamic HTML case.
|
||||
metadata.postponed = JSON.stringify(getDynamicHTMLPostponedState(postponed));
|
||||
} else {
|
||||
// This is the Dynamic Data case
|
||||
metadata.postponed = JSON.stringify(getDynamicDataPostponedState());
|
||||
}
|
||||
// Regardless of whether this is the Dynamic HTML or Dynamic Data case we need to ensure we include
|
||||
// server inserted html in the static response because the html that is part of the prerender may depend on it
|
||||
// It is possible in the set of stream transforms for Dynamic HTML vs Dynamic Data may differ but currently both states
|
||||
// require the same set so we unify the code path here
|
||||
return {
|
||||
stream: await continueDynamicPrerender(stream, {
|
||||
getServerInsertedHTML
|
||||
})
|
||||
};
|
||||
} else {
|
||||
// This is the Static case
|
||||
// We still have not used any dynamic APIs. At this point we can produce an entirely static prerender response
|
||||
let renderedHTMLStream = stream;
|
||||
if (staticGenerationStore.forceDynamic) {
|
||||
throw new StaticGenBailoutError('Invariant: a Page with `dynamic = "force-dynamic"` did not trigger the dynamic pathway. This is a bug in Next.js');
|
||||
}
|
||||
if (postponed != null) {
|
||||
// We postponed but nothing dynamic was used. We resume the render now and immediately abort it
|
||||
// so we can set all the postponed boundaries to client render mode before we store the HTML response
|
||||
const resumeRenderer = createStaticRenderer({
|
||||
ppr: true,
|
||||
isStaticGeneration: false,
|
||||
postponed: getDynamicHTMLPostponedState(postponed),
|
||||
streamOptions: {
|
||||
signal: createPostponedAbortSignal("static prerender resume"),
|
||||
onError: htmlRendererErrorHandler,
|
||||
nonce
|
||||
}
|
||||
});
|
||||
// We don't actually want to render anything so we just pass a stream
|
||||
// that never resolves. The resume call is going to abort immediately anyway
|
||||
const foreverStream = new ReadableStream();
|
||||
const resumeChildren = /*#__PURE__*/ _jsx(HeadManagerContext.Provider, {
|
||||
value: {
|
||||
appDir: true,
|
||||
nonce
|
||||
},
|
||||
children: /*#__PURE__*/ _jsx(ServerInsertedHTMLProvider, {
|
||||
children: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
|
||||
reactServerStream: foreverStream,
|
||||
preinitScripts: ()=>{},
|
||||
clientReferenceManifest: clientReferenceManifest,
|
||||
nonce: nonce
|
||||
})
|
||||
})
|
||||
});
|
||||
const { stream: resumeStream } = await resumeRenderer.render(resumeChildren);
|
||||
// First we write everything from the prerender, then we write everything from the aborted resume render
|
||||
renderedHTMLStream = chainStreams(stream, resumeStream);
|
||||
}
|
||||
return {
|
||||
stream: await continueStaticPrerender(renderedHTMLStream, {
|
||||
inlinedDataStream: createInlinedDataReadableStream(dataStream, nonce, formState),
|
||||
getServerInsertedHTML
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (renderOpts.postponed) {
|
||||
// This is a continuation of either an Incomplete or Dynamic Data Prerender.
|
||||
const inlinedDataStream = createInlinedDataReadableStream(dataStream, nonce, formState);
|
||||
if (resumed) {
|
||||
// We have new HTML to stream and we also need to include server inserted HTML
|
||||
return {
|
||||
stream: await continueDynamicHTMLResume(stream, {
|
||||
inlinedDataStream,
|
||||
getServerInsertedHTML
|
||||
})
|
||||
};
|
||||
} else {
|
||||
// We are continuing a Dynamic Data Prerender and simply need to append new inlined flight data
|
||||
return {
|
||||
stream: await continueDynamicDataResume(stream, {
|
||||
inlinedDataStream
|
||||
})
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// This may be a static render or a dynamic render
|
||||
// @TODO factor this further to make the render types more clearly defined and remove
|
||||
// the deluge of optional params that passed to configure the various behaviors
|
||||
return {
|
||||
stream: await continueFizzStream(stream, {
|
||||
inlinedDataStream: createInlinedDataReadableStream(dataStream, nonce, formState),
|
||||
isStaticGeneration: isStaticGeneration || generateStaticHTML,
|
||||
getServerInsertedHTML,
|
||||
serverInsertedHTMLToHead: true,
|
||||
validateRootLayout
|
||||
})
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
if (isStaticGenBailoutError(err) || typeof err === "object" && err !== null && "message" in err && typeof err.message === "string" && err.message.includes("https://nextjs.org/docs/advanced-features/static-html-export")) {
|
||||
// Ensure that "next dev" prints the red error overlay
|
||||
throw err;
|
||||
}
|
||||
// If this is a static generation error, we need to throw it so that it
|
||||
// can be handled by the caller if we're in static generation mode.
|
||||
if (isStaticGeneration && isDynamicServerError(err)) {
|
||||
throw err;
|
||||
}
|
||||
// If a bailout made it to this point, it means it wasn't wrapped inside
|
||||
// a suspense boundary.
|
||||
const shouldBailoutToCSR = isBailoutToCSRError(err);
|
||||
if (shouldBailoutToCSR) {
|
||||
const stack = getStackWithoutErrorMessage(err);
|
||||
if (renderOpts.experimental.missingSuspenseWithCSRBailout) {
|
||||
error(`${err.reason} should be wrapped in a suspense boundary at page "${pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`);
|
||||
throw err;
|
||||
}
|
||||
warn(`Entire page "${pagePath}" deopted into client-side rendering due to "${err.reason}". Read more: https://nextjs.org/docs/messages/deopted-into-client-rendering\n${stack}`);
|
||||
}
|
||||
if (isNotFoundError(err)) {
|
||||
res.statusCode = 404;
|
||||
}
|
||||
let hasRedirectError = false;
|
||||
if (isRedirectError(err)) {
|
||||
hasRedirectError = true;
|
||||
res.statusCode = getRedirectStatusCodeFromError(err);
|
||||
if (err.mutableCookies) {
|
||||
const headers = new Headers();
|
||||
// If there were mutable cookies set, we need to set them on the
|
||||
// response.
|
||||
if (appendMutableCookies(headers, err.mutableCookies)) {
|
||||
res.setHeader("set-cookie", Array.from(headers.values()));
|
||||
}
|
||||
}
|
||||
const redirectUrl = addPathPrefix(getURLFromRedirectError(err), renderOpts.basePath);
|
||||
res.setHeader("Location", redirectUrl);
|
||||
}
|
||||
const is404 = ctx.res.statusCode === 404;
|
||||
if (!is404 && !hasRedirectError && !shouldBailoutToCSR) {
|
||||
res.statusCode = 500;
|
||||
}
|
||||
const errorType = is404 ? "not-found" : hasRedirectError ? "redirect" : undefined;
|
||||
const [errorPreinitScripts, errorBootstrapScript] = getRequiredScripts(buildManifest, assetPrefix, renderOpts.crossOrigin, subresourceIntegrityManifest, getAssetQueryString(ctx, false), nonce);
|
||||
const errorServerStream = ComponentMod.renderToReadableStream(/*#__PURE__*/ _jsx(ReactServerError, {
|
||||
tree: tree,
|
||||
ctx: ctx,
|
||||
errorType: errorType
|
||||
}), clientReferenceManifest.clientModules, {
|
||||
onError: serverComponentsErrorHandler
|
||||
});
|
||||
try {
|
||||
const fizzStream = await renderToInitialFizzStream({
|
||||
ReactDOMServer: require("react-dom/server.edge"),
|
||||
element: /*#__PURE__*/ _jsx(ReactServerEntrypoint, {
|
||||
reactServerStream: errorServerStream,
|
||||
preinitScripts: errorPreinitScripts,
|
||||
clientReferenceManifest: clientReferenceManifest,
|
||||
nonce: nonce
|
||||
}),
|
||||
streamOptions: {
|
||||
nonce,
|
||||
// Include hydration scripts in the HTML
|
||||
bootstrapScripts: [
|
||||
errorBootstrapScript
|
||||
],
|
||||
formState
|
||||
}
|
||||
});
|
||||
return {
|
||||
// Returning the error that was thrown so it can be used to handle
|
||||
// the response in the caller.
|
||||
err,
|
||||
stream: await continueFizzStream(fizzStream, {
|
||||
inlinedDataStream: createInlinedDataReadableStream(// This is intentionally using the readable datastream from the
|
||||
// main render rather than the flight data from the error page
|
||||
// render
|
||||
dataStream, nonce, formState),
|
||||
isStaticGeneration,
|
||||
getServerInsertedHTML: makeGetServerInsertedHTML({
|
||||
polyfills,
|
||||
renderServerInsertedHTML,
|
||||
serverCapturedErrors: [],
|
||||
basePath: renderOpts.basePath
|
||||
}),
|
||||
serverInsertedHTMLToHead: true,
|
||||
validateRootLayout
|
||||
})
|
||||
};
|
||||
} catch (finalErr) {
|
||||
if (process.env.NODE_ENV === "development" && isNotFoundError(finalErr)) {
|
||||
const bailOnNotFound = require("../../client/components/dev-root-not-found-boundary").bailOnNotFound;
|
||||
bailOnNotFound();
|
||||
}
|
||||
throw finalErr;
|
||||
}
|
||||
}
|
||||
});
|
||||
// For action requests, we handle them differently with a special render result.
|
||||
const actionRequestResult = await handleAction({
|
||||
req,
|
||||
res,
|
||||
ComponentMod,
|
||||
serverModuleMap,
|
||||
generateFlight,
|
||||
staticGenerationStore,
|
||||
requestStore,
|
||||
serverActions,
|
||||
ctx
|
||||
});
|
||||
let formState = null;
|
||||
if (actionRequestResult) {
|
||||
if (actionRequestResult.type === "not-found") {
|
||||
const notFoundLoaderTree = createNotFoundLoaderTree(loaderTree);
|
||||
const response = await renderToStream({
|
||||
asNotFound: true,
|
||||
tree: notFoundLoaderTree,
|
||||
formState
|
||||
});
|
||||
return new RenderResult(response.stream, {
|
||||
metadata
|
||||
});
|
||||
} else if (actionRequestResult.type === "done") {
|
||||
if (actionRequestResult.result) {
|
||||
actionRequestResult.result.assignMetadata(metadata);
|
||||
return actionRequestResult.result;
|
||||
} else if (actionRequestResult.formState) {
|
||||
formState = actionRequestResult.formState;
|
||||
}
|
||||
}
|
||||
}
|
||||
const options = {
|
||||
metadata
|
||||
};
|
||||
let response = await renderToStream({
|
||||
asNotFound: isNotFoundPath,
|
||||
tree: loaderTree,
|
||||
formState
|
||||
});
|
||||
// If we have pending revalidates, wait until they are all resolved.
|
||||
if (staticGenerationStore.pendingRevalidates) {
|
||||
var _staticGenerationStore_incrementalCache;
|
||||
options.waitUntil = Promise.all([
|
||||
(_staticGenerationStore_incrementalCache = staticGenerationStore.incrementalCache) == null ? void 0 : _staticGenerationStore_incrementalCache.revalidateTag(staticGenerationStore.revalidatedTags || []),
|
||||
...Object.values(staticGenerationStore.pendingRevalidates || {})
|
||||
]);
|
||||
}
|
||||
addImplicitTags(staticGenerationStore);
|
||||
if (staticGenerationStore.tags) {
|
||||
metadata.fetchTags = staticGenerationStore.tags.join(",");
|
||||
}
|
||||
// Create the new render result for the response.
|
||||
const result = new RenderResult(response.stream, options);
|
||||
// If we aren't performing static generation, we can return the result now.
|
||||
if (!isStaticGeneration) {
|
||||
return result;
|
||||
}
|
||||
// If this is static generation, we should read this in now rather than
|
||||
// sending it back to be sent to the client.
|
||||
response.stream = await result.toUnchunkedString(true);
|
||||
const buildFailingError = digestErrorsMap.size > 0 ? digestErrorsMap.values().next().value : null;
|
||||
// If we're debugging partial prerendering, print all the dynamic API accesses
|
||||
// that occurred during the render.
|
||||
if (staticGenerationStore.prerenderState && usedDynamicAPIs(staticGenerationStore.prerenderState) && ((_staticGenerationStore_prerenderState = staticGenerationStore.prerenderState) == null ? void 0 : _staticGenerationStore_prerenderState.isDebugSkeleton)) {
|
||||
warn("The following dynamic usage was detected:");
|
||||
for (const access of formatDynamicAPIAccesses(staticGenerationStore.prerenderState)){
|
||||
warn(access);
|
||||
}
|
||||
}
|
||||
if (!flightDataResolver) {
|
||||
throw new Error("Invariant: Flight data resolver is missing when generating static HTML");
|
||||
}
|
||||
// If we encountered any unexpected errors during build we fail the
|
||||
// prerendering phase and the build.
|
||||
if (buildFailingError) {
|
||||
throw buildFailingError;
|
||||
}
|
||||
// Wait for and collect the flight payload data if we don't have it
|
||||
// already
|
||||
const flightData = await flightDataResolver();
|
||||
if (flightData) {
|
||||
metadata.flightData = flightData;
|
||||
}
|
||||
// If force static is specifically set to false, we should not revalidate
|
||||
// the page.
|
||||
if (staticGenerationStore.forceStatic === false) {
|
||||
staticGenerationStore.revalidate = 0;
|
||||
}
|
||||
// Copy the revalidation value onto the render result metadata.
|
||||
metadata.revalidate = staticGenerationStore.revalidate ?? ctx.defaultRevalidate;
|
||||
// provide bailout info for debugging
|
||||
if (metadata.revalidate === 0) {
|
||||
metadata.staticBailoutInfo = {
|
||||
description: staticGenerationStore.dynamicUsageDescription,
|
||||
stack: staticGenerationStore.dynamicUsageStack
|
||||
};
|
||||
}
|
||||
return new RenderResult(response.stream, options);
|
||||
}
|
||||
export const renderToHTMLOrFlight = (req, res, pagePath, query, renderOpts)=>{
|
||||
// TODO: this includes query string, should it?
|
||||
const pathname = validateURL(req.url);
|
||||
return RequestAsyncStorageWrapper.wrap(renderOpts.ComponentMod.requestAsyncStorage, {
|
||||
req,
|
||||
res,
|
||||
renderOpts
|
||||
}, (requestStore)=>StaticGenerationAsyncStorageWrapper.wrap(renderOpts.ComponentMod.staticGenerationAsyncStorage, {
|
||||
urlPathname: pathname,
|
||||
renderOpts,
|
||||
requestEndedState: {
|
||||
ended: false
|
||||
}
|
||||
}, (staticGenerationStore)=>renderToHTMLOrFlightImpl(req, res, pagePath, query, renderOpts, {
|
||||
requestStore,
|
||||
staticGenerationStore,
|
||||
componentMod: renderOpts.ComponentMod,
|
||||
renderOpts
|
||||
}, staticGenerationStore.requestEndedState || {})));
|
||||
};
|
||||
|
||||
//# sourceMappingURL=app-render.js.map
|
||||
Reference in New Issue
Block a user