diff --git a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/index.ts b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/index.ts index 5341b620aba8b25..d457fcaa72d3668 100644 --- a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/index.ts @@ -44,37 +44,25 @@ export default async function middlewareSSRLoader(this: any) { } // Set server context - self.__current_route = ${JSON.stringify(page)} self.__server_context = { - Component: pageMod.default, - pageConfig: pageMod.config || {}, - buildManifest, - reactLoadableManifest, - Document, - App, - getStaticProps: pageMod.getStaticProps, - getServerSideProps: pageMod.getServerSideProps, - getStaticPaths: pageMod.getStaticPaths, - ComponentMod: undefined, - serverComponentManifest: ${isServerComponent} ? rscManifest : null, - - // components - errorMod, - error500Mod, - - // renderOpts + page: ${JSON.stringify(page)}, buildId: ${JSON.stringify(buildId)}, - dev: ${dev}, - env: process.env, - supportsDynamicHTML: true, - concurrentFeatures: true, - disableOptimizedLoading: true, } const render = getRender({ + dev: ${dev}, + page: ${JSON.stringify(page)}, + pageMod, + errorMod, + error500Mod, + App, Document, + buildManifest, + reactLoadableManifest, + serverComponentManifest: ${isServerComponent} ? rscManifest : null, isServerComponent: ${isServerComponent}, config: ${stringifiedConfig}, + buildId: ${JSON.stringify(buildId)}, }) export default function rscMiddleware(opts) { diff --git a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts index a56c33a3a7319de..b74d8a3be093ba4 100644 --- a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts @@ -1,4 +1,7 @@ import type { NextConfig } from '../../../../server/config-shared' +import type { DocumentType, AppType } from '../../../../shared/lib/utils' +import type { BuildManifest } from '../../../../server/get-page-files' +import type { ReactLoadableManifest } from '../../../../server/load-components' import { NextRequest } from '../../../../server/web/spec-extension/request' import { toNodeHeaders } from '../../../../server/web/utils' @@ -20,20 +23,98 @@ function sendError(req: any, error: Error) { }) } +// Polyfilled for `path-browserify` inside the Web Server. +process.cwd = () => '' + export function getRender({ + dev, + page, + pageMod, + errorMod, + error500Mod, Document, + App, + buildManifest, + reactLoadableManifest, + serverComponentManifest, isServerComponent, config, + buildId, }: { - Document: any + dev: boolean + page: string + pageMod: any + errorMod: any + error500Mod: any + Document: DocumentType + App: AppType + buildManifest: BuildManifest + reactLoadableManifest: ReactLoadableManifest + serverComponentManifest: any | null isServerComponent: boolean config: NextConfig + buildId: string }) { - // Polyfilled for `path-browserify`. - process.cwd = () => '' + const baseLoadComponentResult = { + dev, + buildManifest, + reactLoadableManifest, + Document, + App, + } + const server = new WebServer({ conf: config, minimalMode: true, + webServerConfig: { + extendRenderOpts: { + buildId, + supportsDynamicHTML: true, + concurrentFeatures: true, + disableOptimizedLoading: true, + serverComponentManifest, + }, + loadComponent: async (pathname) => { + if (pathname === page) { + return { + ...baseLoadComponentResult, + Component: pageMod.default, + pageConfig: pageMod.config || {}, + getStaticProps: pageMod.getStaticProps, + getServerSideProps: pageMod.getServerSideProps, + getStaticPaths: pageMod.getStaticPaths, + ComponentMod: pageMod, + } + } + + // If there is a custom 500 page, we need to handle it separately. + if (pathname === '/500' && error500Mod) { + return { + ...baseLoadComponentResult, + Component: error500Mod.default, + pageConfig: error500Mod.config || {}, + getStaticProps: error500Mod.getStaticProps, + getServerSideProps: error500Mod.getServerSideProps, + getStaticPaths: error500Mod.getStaticPaths, + ComponentMod: error500Mod, + } + } + + if (pathname === '/_error') { + return { + ...baseLoadComponentResult, + Component: errorMod.default, + pageConfig: errorMod.config || {}, + getStaticProps: errorMod.getStaticProps, + getServerSideProps: errorMod.getServerSideProps, + getStaticPaths: errorMod.getStaticPaths, + ComponentMod: errorMod, + } + } + + return null + }, + }, }) const requestHandler = server.getRequestHandler() @@ -72,8 +153,8 @@ export function getRender({ ? JSON.parse(query.__props__) : undefined - // Extend the context. - Object.assign((self as any).__server_context, { + // Extend the render options. + server.updateRenderOpts({ renderServerComponentData, serverComponentProps, }) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index f302d4517d84a41..e327ba718af0e01 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -158,6 +158,10 @@ export default abstract class Server { concurrentFeatures?: boolean serverComponents?: boolean crossOrigin?: string + supportsDynamicHTML?: boolean + serverComponentManifest?: any + renderServerComponentData?: boolean + serverComponentProps?: any } private incrementalCache: IncrementalCache private responseCache: ResponseCache diff --git a/packages/next/server/load-components.ts b/packages/next/server/load-components.ts index 5637e13258dfd0c..28d41a6d571d77b 100644 --- a/packages/next/server/load-components.ts +++ b/packages/next/server/load-components.ts @@ -19,7 +19,7 @@ export type ManifestItem = { files: string[] } -type ReactLoadableManifest = { [moduleId: string]: ManifestItem } +export type ReactLoadableManifest = { [moduleId: string]: ManifestItem } export type LoadComponentsReturnType = { Component: React.ComponentType diff --git a/packages/next/server/web-server.ts b/packages/next/server/web-server.ts index acb68e9a999d0f5..5e61a18a52ca186 100644 --- a/packages/next/server/web-server.ts +++ b/packages/next/server/web-server.ts @@ -4,12 +4,24 @@ import type RenderResult from './render-result' import type { NextParsedUrlQuery } from './request-meta' import type { Params } from './router' import type { PayloadOptions } from './send-payload' +import type { LoadComponentsReturnType } from './load-components' -import BaseServer from './base-server' +import BaseServer, { Options } from './base-server' import { renderToHTML } from './render' -import { LoadComponentsReturnType } from './load-components' + +interface WebServerConfig { + loadComponent: (pathname: string) => Promise + extendRenderOpts?: Partial +} export default class NextWebServer extends BaseServer { + webServerConfig: WebServerConfig + + constructor(options: Options & { webServerConfig: WebServerConfig }) { + super(options) + this.webServerConfig = options.webServerConfig + Object.assign(this.renderOpts, options.webServerConfig.extendRenderOpts) + } protected generateRewrites() { // @TODO: assuming minimal mode right now return { @@ -78,7 +90,7 @@ export default class NextWebServer extends BaseServer { } protected getPagesManifest() { return { - [(globalThis as any).__current_route]: '', + [(globalThis as any).__server_context.page]: '', } } protected getFilesystemPaths() { @@ -158,52 +170,19 @@ export default class NextWebServer extends BaseServer { query?: NextParsedUrlQuery, params?: Params | null ) { - if (pathname === (globalThis as any).__current_route) { - return { - query: { - ...(query || {}), - ...(params || {}), - }, - components: (globalThis as any) - .__server_context as LoadComponentsReturnType, - } - } - - const { errorMod, error500Mod } = (globalThis as any).__server_context + const result = await this.webServerConfig.loadComponent(pathname) + if (!result) return null - // If there is a custom 500 page. - if (pathname === '/500' && error500Mod) { - return { - query: { - ...(query || {}), - ...(params || {}), - }, - components: { - ...(globalThis as any).__server_context, - Component: error500Mod.default, - getStaticProps: error500Mod.getStaticProps, - getServerSideProps: error500Mod.getServerSideProps, - getStaticPaths: error500Mod.getStaticPaths, - } as LoadComponentsReturnType, - } - } - - if (pathname === '/_error') { - return { - query: { - ...(query || {}), - ...(params || {}), - }, - components: { - ...(globalThis as any).__server_context, - Component: errorMod.default, - getStaticProps: errorMod.getStaticProps, - getServerSideProps: errorMod.getServerSideProps, - getStaticPaths: errorMod.getStaticPaths, - } as LoadComponentsReturnType, - } + return { + query: { + ...(query || {}), + ...(params || {}), + }, + components: result, } + } - return null + public updateRenderOpts(renderOpts: Partial) { + Object.assign(this.renderOpts, renderOpts) } }