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.

Introduction #

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:

Common entrypoint and bundle configurationAlthough 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/).

Improved Chunking #

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 (reactreact-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:

  • If you reduce the ratio, more unnecessary code gets downloaded.
  • If you increase the ratio, more code gets duplicated across multiple routes.

To solve this problem, Next.js adopted a different configuration forSplitChunksPlugin that reduces unecessary code for any route.

  • Any sufficiently large third-party module (greater than 160 KB) is split into its own individual chunk
  • A separate frameworks chunk is created for framework dependencies (reactreact-dom, and so on)
  • As many shared chunks as needed are created (up to 25)
  • The minimum size for a chunk to be generated is changed to 20 KB

This granular chunking strategy provides the following benefits:

  • Page load times are improved. Emitting multiple shared chunks, instead of a single one, minimizes the amount of unneeded (or duplicate) code for any entrypoint.
  • Improved caching during navigations. Splitting large libraries and framework dependencies into separate chunks reduces the possibility of cache invalidation since both are unlikely to change until an upgrade is made.

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

Improved Next.js and Gatsby page load performance with granular chunking
38.85 GEEK