Chrome is collaborating with tooling and frameworks in the JavaScript open-source ecosystem. A number of newer optimizations were recently added to improve the loading performance of Next.js and Gatsby. This article covers an improved granular chunking strategy that is now shipped by default in both frameworks.
Like many web frameworks, Next.js and Gatsby use webpack as their core bundler. webpack v3 introduced [CommonsChunkPlugin](https://webpack.js.org/plugins/commons-chunk-plugin/)
to make it possible to output modules shared between different entry points in a single (or few) “commons” chunk (or chunks). Shared code can be downloaded separately and stored in the browser cache early on which can result in a better loading performance.
This pattern became popular with many single-page application frameworks adopting an entrypoint and bundle configuration that looked like this:
Although practical, the concept of bundling all shared module code into a single chunk has its limitations. Modules not shared in every entry point can be downloaded for routes that do not use it resulting in more code being downloaded than necessary. For example, when page1
loads the common
chunk, it loads the code for moduleC
even though page1
doesn’t use moduleC
. For this reason, along with a few others, webpack v4 removed the plugin in favor of a new one: [SplitChunksPlugin](https://webpack.js.org/plugins/split-chunks-plugin/)
.
The default settings for SplitChunksPlugin
works well for most users. Multiple split chunks are created depending on a number of conditions to prevent fetching duplicated code across multiple routes.
However, many web frameworks that use this plugin still follow a “single-commons” approach to chunk splitting. Next.js, for example, would generate a commons
bundle that contained any module that is used in more than 50% of pages and all framework dependencies (react
, react-dom
, and so on).
const splitChunksConfigs = {
…
prod: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
commons: {
name: 'commons',
chunks: 'all',
minChunks: totalPages > 2 ? totalPages * 0.5 : 2,
},
react: {
name: 'commons',
chunks: 'all',
test: /[\\/]node_modules[\\/](react|react-dom|scheduler|use-subscription)[\\/]/,
},
},
},
Although including framework-dependent code into a shared chunk means that it can be downloaded and cached for any entrypoint, the usage-based heuristic of including common modules used in more than half of pages isn’t very effective. Modifying this ratio would only result in one of two outcomes:
To solve this problem, Next.js adopted a different configuration forSplitChunksPlugin
that reduces unecessary code for any route.
frameworks
chunk is created for framework dependencies (react
, react-dom
, and so on)This granular chunking strategy provides the following benefits:
You can see the entire configuration that Next.js adopted in [webpack-config.ts](https://github.com/vercel/next.js/blob/e125d905a0dd93d247c6122d349c2c90268f0713/packages/next/build/webpack-config.ts#L352-L429)
.
#next.js #gatsby