Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor page component getter in web server #33759

Merged
merged 5 commits into from Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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) {
Expand Down
@@ -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'
Expand All @@ -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()

Expand Down Expand Up @@ -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,
})
Expand Down
4 changes: 4 additions & 0 deletions packages/next/server/base-server.ts
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/load-components.ts
Expand Up @@ -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
Expand Down
73 changes: 26 additions & 47 deletions packages/next/server/web-server.ts
Expand Up @@ -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<LoadComponentsReturnType | null>
extendRenderOpts?: Partial<BaseServer['renderOpts']>
}

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 {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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<BaseServer['renderOpts']>) {
Object.assign(this.renderOpts, renderOpts)
}
}