rsnext/packages/next/next-server/server/load-components.ts
JJ Kasper 1435de15bc
Ensure component load order (#22731)
This ensures we load `_document` then `_app` and then the page's component in all cases which matches behavior between the serverless target and the default server target.  Additional tests to ensure this order is followed has been added to prevent regression. 

Fixes: https://github.com/vercel/next.js/issues/22732
2021-03-03 19:20:48 +00:00

94 lines
2.4 KiB
TypeScript

import { BUILD_MANIFEST, REACT_LOADABLE_MANIFEST } from '../lib/constants'
import { join } from 'path'
import { requirePage } from './require'
import { BuildManifest } from './get-page-files'
import { AppType, DocumentType } from '../lib/utils'
import {
PageConfig,
GetStaticPaths,
GetServerSideProps,
GetStaticProps,
} from 'next/types'
export function interopDefault(mod: any) {
return mod.default || mod
}
export type ManifestItem = {
id: number | string
name: string
file: string
}
type ReactLoadableManifest = { [moduleId: string]: ManifestItem[] }
export type LoadComponentsReturnType = {
Component: React.ComponentType
pageConfig?: PageConfig
buildManifest: BuildManifest
reactLoadableManifest: ReactLoadableManifest
Document: DocumentType
App: AppType
getStaticProps?: GetStaticProps
getStaticPaths?: GetStaticPaths
getServerSideProps?: GetServerSideProps
ComponentMod: any
}
export async function loadComponents(
distDir: string,
pathname: string,
serverless: boolean
): Promise<LoadComponentsReturnType> {
if (serverless) {
const Component = await requirePage(pathname, distDir, serverless)
let { getStaticProps, getStaticPaths, getServerSideProps } = Component
getStaticProps = await getStaticProps
getStaticPaths = await getStaticPaths
getServerSideProps = await getServerSideProps
const pageConfig = (await Component.config) || {}
return {
Component,
pageConfig,
getStaticProps,
getStaticPaths,
getServerSideProps,
ComponentMod: Component,
} as LoadComponentsReturnType
}
const DocumentMod = await requirePage('/_document', distDir, serverless)
const AppMod = await requirePage('/_app', distDir, serverless)
const ComponentMod = await requirePage(pathname, distDir, serverless)
const [
buildManifest,
reactLoadableManifest,
Component,
Document,
App,
] = await Promise.all([
require(join(distDir, BUILD_MANIFEST)),
require(join(distDir, REACT_LOADABLE_MANIFEST)),
interopDefault(ComponentMod),
interopDefault(DocumentMod),
interopDefault(AppMod),
])
const { getServerSideProps, getStaticProps, getStaticPaths } = ComponentMod
return {
App,
Document,
Component,
buildManifest,
reactLoadableManifest,
pageConfig: ComponentMod.config || {},
ComponentMod,
getServerSideProps,
getStaticProps,
getStaticPaths,
}
}