Skip to content

Commit

Permalink
Enable code splitting for the web runtime build (#31090)
Browse files Browse the repository at this point in the history
When using the web runtime with SSR streaming, this PR significantly improves the build speed for large applications when there're large modules shared by most pages.

With another optimization, `react-dom` will now be excluded in the web runtime build if it's imported in the application. It will only take effect in the client bundle.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
  • Loading branch information
shuding committed Nov 8, 2021
1 parent 9e03c8d commit feed67e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 19 deletions.
14 changes: 10 additions & 4 deletions packages/next/build/webpack-config.ts
Expand Up @@ -990,7 +990,12 @@ export default async function getBaseWebpackConfig(
? // make sure importing "next" is handled gracefully for client
// bundles in case a user imported types and it wasn't removed
// TODO: should we warn/error for this instead?
['next', ...(webServerRuntime ? [{ etag: '{}', chalk: '{}' }] : [])]
[
'next',
...(webServerRuntime
? [{ etag: '{}', chalk: '{}', 'react-dom': '{}' }]
: []),
]
: !isServerless
? [
({
Expand Down Expand Up @@ -1054,10 +1059,10 @@ export default async function getBaseWebpackConfig(
}
: {}),
splitChunks: isServer
? dev || webServerRuntime
? dev
? false
: ({
filename: '[name].js',
filename: webServerRuntime ? 'chunks/[name].js' : '[name].js',
// allow to split entrypoints
chunks: ({ name }: any) => !name?.match(MIDDLEWARE_ROUTE),
// size of files is not so relevant for server build
Expand Down Expand Up @@ -1465,7 +1470,8 @@ export default async function getBaseWebpackConfig(
new PagesManifestPlugin({ serverless: isLikeServerless, dev }),
// MiddlewarePlugin should be after DefinePlugin so NEXT_PUBLIC_*
// replacement is done before its process.env.* handling
!isServer && new MiddlewarePlugin({ dev }),
(!isServer || webServerRuntime) &&
new MiddlewarePlugin({ dev, webServerRuntime }),
isServer && new NextJsSsrImportPlugin(),
!isServer &&
new BuildManifestPlugin({
Expand Down
43 changes: 28 additions & 15 deletions packages/next/build/webpack/plugins/middleware-plugin.ts
Expand Up @@ -4,7 +4,6 @@ import { getSortedRoutes } from '../../../shared/lib/router/utils'
import {
MIDDLEWARE_MANIFEST,
MIDDLEWARE_FLIGHT_MANIFEST,
MIDDLEWARE_SSR_RUNTIME_WEBPACK,
MIDDLEWARE_BUILD_MANIFEST,
MIDDLEWARE_REACT_LOADABLE_MANIFEST,
} from '../../../shared/lib/constants'
Expand All @@ -31,11 +30,25 @@ export interface MiddlewareManifest {
}
}

const middlewareManifest: MiddlewareManifest = {
sortedMiddleware: [],
clientInfo: [],
middleware: {},
version: 1,
}
export default class MiddlewarePlugin {
dev: boolean

constructor({ dev }: { dev: boolean }) {
webServerRuntime: boolean

constructor({
dev,
webServerRuntime,
}: {
dev: boolean
webServerRuntime: boolean
}) {
this.dev = dev
this.webServerRuntime = webServerRuntime
}

createAssets(
Expand All @@ -44,17 +57,14 @@ export default class MiddlewarePlugin {
envPerRoute: Map<string, string[]>
) {
const entrypoints = compilation.entrypoints
const middlewareManifest: MiddlewareManifest = {
sortedMiddleware: [],
clientInfo: [],
middleware: {},
version: 1,
}

for (const entrypoint of entrypoints.values()) {
if (!entrypoint.name) continue
const result = MIDDLEWARE_FULL_ROUTE_REGEX.exec(entrypoint.name)

const ssrEntryInfo = ssrEntries.get(entrypoint.name)
if (ssrEntryInfo && !this.webServerRuntime) continue
if (!ssrEntryInfo && this.webServerRuntime) continue

const location = result
? `/${result[1]}`
Expand All @@ -67,14 +77,15 @@ export default class MiddlewarePlugin {
}
const files = ssrEntryInfo
? [
`server/${MIDDLEWARE_SSR_RUNTIME_WEBPACK}.js`,
ssrEntryInfo.requireFlightManifest
? `server/${MIDDLEWARE_FLIGHT_MANIFEST}.js`
: null,
`server/${MIDDLEWARE_BUILD_MANIFEST}.js`,
`server/${MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js`,
`server/${entrypoint.name}.js`,
].filter(nonNullable)
...entrypoint.getFiles().map((file) => 'server/' + file),
]
.filter(nonNullable)
.filter((file: string) => !file.endsWith('.hot-update.js'))
: entrypoint
.getFiles()
.filter((file: string) => !file.endsWith('.hot-update.js'))
Expand Down Expand Up @@ -106,9 +117,11 @@ export default class MiddlewarePlugin {
}
)

assets[`server/${MIDDLEWARE_MANIFEST}`] = new sources.RawSource(
JSON.stringify(middlewareManifest, null, 2)
)
assets[
this.webServerRuntime
? MIDDLEWARE_MANIFEST
: `server/${MIDDLEWARE_MANIFEST}`
] = new sources.RawSource(JSON.stringify(middlewareManifest, null, 2))
}

apply(compiler: webpack5.Compiler) {
Expand Down

0 comments on commit feed67e

Please sign in to comment.