- server handler
- API
- SSR
- client initialization
- middleware
- client navigation, prefetch, and data request
- production build
- manifest generation
- webpack bundle
- swc, babel
- transform plugins
- dev server
- react fast refresh
- Build and Test
Cf. https://github.com/vercel/next.js/blob/canary/contributing.md
# (re)build only "next" package
yarn lerna run prepublish --scope 'next'
# Run unit test
yarn jest --findRelatedTests test/unit/link-rendering.test.ts
# Run integration test with headless mode
HEADLESS=true yarn jest --findRelatedTests test/integration/middleware/core/test/index.test.js
# Run integration test app
yarn next test/integration/middleware/core/
# Build app with printing trace
TRACE_TARGET=CONSOLE yarn next build ...- Grep
- include:
packages, test - exclude:
**/dist, **/compiled, **/.next
- include:
- Build
build (next/build/index.ts) =>
generateBuildId
verifyTypeScriptSetup => require("typescript"), runTypeCheck
verifyAndLint
collectPages
createPagesMapping
createEntrypoints =>
For each page, specify webpack entry file
e.g. "next-middleware-loader", "next-client-pages-loader", etc... or page js file itself
routesManifest
mkdir(".next")
writeFile(".next/routes-manifest.json", ...)
getBaseWebpackConfig for each entrypoint (client and server) =>
(choose "next-swc-loader" or `nextBabelLoader`)
(define webpack.Configuration)
handleExternals (e.g. not to bundle node_modules in server pages)
buildConfiguration (css loader etc...)
(run webpack override from next.config.js)
runCompiler (client and server)
(obtain `pageInfo` etc.. by statically checking built artifacts)
(if `outputFileTracing` create .nft.json for each page and next-server itself)
exportApp (static generation) =>
exportPage (Imitate SSR using loadComponents, renderToHTML, etc...)
writeFile (for a bunch of manifests, e.g. middleware, images, etc...)
- Server
[Server initialization]
NextServer.createServer =>
new Server (from "./next-servert.ts") or
new DevServer (from "./dev/next-dev-server.ts") =>
Server.constructor =>
(when production)
require(pagesManifestPath)
require(middlewareManifestPath)
generateRoutes =>
routes for middleware, render, etc...
new Router
DevServer.prepare =>
new HotReloader => ??
startWatcher => ??
[Server handler (via NextServer.getRequestHandler)]
Server.handleRequest =>
run => Router.execute
[SSR (via server router)]
Server.render => renderToResponse =>
# fallback to `renderErrorToResponse` when this routine throws
findPageComponents => loadComponents => requirePage => require
renderToResponseWithComponents =>
(doRender) => renderToHTML =>
new ServerRouter (for SSR router context)
getServerSideProps
(renderDocument) =>
loadGetInitialProps(Document, ...) =>
(defaultGetInitialProps) => (renderPage) =>
ReactDOMServer.renderToString(<AppContainer>...)
ReactDOMServer.renderToStaticMarkup(... <Document> ...) =>
<Main> => <div id="__next">__NEXT_BODY_RENDER_TARGET__</div>
<NextScript> => <script id="__NEXT_DATA__">
(replace "__NEXT_BODY_RENDER_TARGET__" with html from `renderToString` above)
[API (via server router)]
Server.handleApiRequest =>
getPagePath(page)
require
apiResolver => (module).default
[Middleware (via server router)]
catchAllMiddleware.fn =>
Server.runMiddleware =>
(for each matching middleware) sandbox.run => (module).default
break if not "x-middleware-next"
- Client
[Client initialization]
"main.js" chunk (CLIENT_STATIC_FILES_RUNTIME_MAIN in getBaseWebpackConfig) =>
(client/next.js or client/next-dev.js) =>
(client/index.tsx) =>
document.getElementById('__NEXT_DATA__') (e.g. hydrateProps, page, query, etc...)
new PageLoader => createRouteLoader
RouteLoader.onEntrypoint for each "window.__NEXT_P" =>
(cf. webpack/loaders/next-client-pages-loader.ts)
entrypoint[...].set(require(...))
initNext =>
RouteLoader.whenEntrypoint (for client side `App` and `Component`)
createRouter
render => doRender =>
renderReactElement =>
# AppContainer has `componentDidCatch`, which in turn triggers `renderError`
ReactDOM.hydrate(document.getElementById('__next'), <AppContainer> ...)
[Client navigation (Link, Router, etc...)]
useEffect(isVisible) or onMouseEnter => prefetch =>
Router.prefetch =>
PageLoader.getPageList => getClientBuildManifest
_preflightRequest =>
PageLoader.getMiddlewareList
(if matching middleware) _getPreflightData (and cache results)
PageLoader.prefetch => RouteLoader.prefetch => loadRoute =>
getFilesForRoute (lookup manifest for js/css file names used in the page)
maybeExecuteScript
fetchStyleSheet
(and cache results)
(if ssg url)
PageLoader.getDataHref (aka. "/_next/data/???.json")
fetchNextData
onClick => linkClicked => Router.push => Router.change =>
_preflightRequest
getRouteInfo =>
fetchComponent => PageLoader.loadPage => RouteLoader.loadRoute
getDataHref, fetchNextData (similar routines as prefetch above)
changeState (if relace, update window.history)
set => notify => subscription ~~> render (cf. createRouter in client./index.tsx)