Code splitting with Webpack


Michael Yin

Full Stack Developer

Last updated on May 28 2021


Table of Contents

Django + Webpack Series:

  1. Introduction
  2. Setup Webpack Project with Django
  3. Load Webpack bundles in Django
  4. Linting in Webpack
  5. Load Webpack hash bundle in Django
  6. Code splitting with Webpack (this article)
  7. How to config HMR with Webpack and Django
  8. How to load Webpack bundle in Django without using 3-party package (coming soon)

If you want a quick start with Webpack and Django, please check python-webpack-boilerplate

Objective

By the end of this chapter, you should be able to:

  1. Understand the code splitting workflow in Webpack.
  2. Config splitChunks to control the splitting behavior.
  3. Load bundle file with splitChunks and Django static templatetag.

Background

What should we do When the bundle file grow? (new features, new 3-party library)

It's also good practice to extract third-party libraries, such as lodash or react, to a separate vendor chunk as they are less likely to change than our local source code. This step will allow clients to request even less from the server to stay up to date.

This can be done by using the splitChunks option of the SplitChunksPlugin

splitChunks

Let's update webpack/webpack.common.js

optimization: {
  splitChunks: {
    chunks: 'all',
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name(module) {
          // get the name. E.g. node_modules/packageName/not/this/part.js
          // or node_modules/packageName
          const packageName = module.context.match(
            /[\\/]node_modules[\\/](.*?)([\\/]|$)/
          )[1];

          // npm package names are URL-safe, but some servers don't like @ symbols
          return `npm.${packageName.replace("@", "")}`;
        }
      },
    }
  },
},

Notes:

  1. We created a vendor group in the optimization.splitChunks.cacheGroups
  2. The test means it would work on all packages which are in node_modules
  3. The name function would be used to generate name for the chunk.
(frontend)$ npm run build
(frontend)$ cat webpack-stats.json
{
  "status": "done",
    "chunks": {
    "app": [
      "js/npm.jquery.e2d46062.js",
      "js/npm.bootstrap.a31ec5e3.js",
      "js/app.fd53aa41.js",
      "css/app-e3e173a2b456b7aaf3a4.css"
    ]
  },
}
  1. As we can see, npm.jquery and npm.bootstrap chunks are generated.
  2. Actually, if we import new packages in the src/index.js (such as Axios), new chunks would be also generated.

The above config is to help us better understand the cacheGroups

Manual config

In some cases, we can use cacheGroups to control the code splitting behavior.

Let's update webpack/webpack.common.js

optimization: {
  splitChunks: {
    chunks: 'all',
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
      },
      jquery: {
        test: /[\\/]node_modules[\\/](jquery)[\\/]/,
        name: 'jquery',
      },
    }
  },
},

Notes:

  1. We created a vendor group which has name vendor
  2. We created a jquery group, which has name jquery, the test would make sure the chunk only match jquery.
  3. If we want the test match multiple packages, you can use Regex like this /[\\/]node_modules[\\/](react|react-dom)[\\/]/
{
  "status": "done",
  "chunks": {
    "app": [
      "js/jquery.5007ce70.js",
      "js/vendors.1acdbaad.js",
      "js/app.44ab1a1c.js",
      "css/app-e3e173a2b456b7aaf3a4.css"
    ]
  },
  "publicPath": "/static/",
  "assets": {
    "js/app.44ab1a1c.js": {
      "name": "js/app.44ab1a1c.js",
      "publicPath": "/static/js/app.44ab1a1c.js"
    },
    "js/jquery.5007ce70.js": {
      "name": "js/jquery.5007ce70.js",
      "publicPath": "/static/js/jquery.5007ce70.js"
    },
    "js/vendors.1acdbaad.js": {
      "name": "js/vendors.1acdbaad.js",
      "publicPath": "/static/js/vendors.1acdbaad.js"
    },
    "public/.gitkeep": {
      "name": "public/.gitkeep",
      "publicPath": "/static/public/.gitkeep"
    },
    "js/jquery.5007ce70.js.LICENSE.txt": {
      "name": "js/jquery.5007ce70.js.LICENSE.txt",
      "publicPath": "/static/js/jquery.5007ce70.js.LICENSE.txt"
    },
    "js/vendors.1acdbaad.js.LICENSE.txt": {
      "name": "js/vendors.1acdbaad.js.LICENSE.txt",
      "publicPath": "/static/js/vendors.1acdbaad.js.LICENSE.txt"
    },
    "js/app.44ab1a1c.js.map": {
      "name": "js/app.44ab1a1c.js.map",
      "publicPath": "/static/js/app.44ab1a1c.js.map"
    },
    "js/jquery.5007ce70.js.map": {
      "name": "js/jquery.5007ce70.js.map",
      "publicPath": "/static/js/jquery.5007ce70.js.map"
    },
    "js/vendors.1acdbaad.js.map": {
      "name": "js/vendors.1acdbaad.js.map",
      "publicPath": "/static/js/vendors.1acdbaad.js.map"
    },
    "css/app-e3e173a2b456b7aaf3a4.css": {
      "name": "css/app-e3e173a2b456b7aaf3a4.css",
      "publicPath": "/static/css/app-e3e173a2b456b7aaf3a4.css"
    },
    "css/app-e3e173a2b456b7aaf3a4.css.map": {
      "name": "css/app-e3e173a2b456b7aaf3a4.css.map",
      "publicPath": "/static/css/app-e3e173a2b456b7aaf3a4.css.map"
    },
  }
}

Notes:

  1. The jquery chunk contains code from jquery
  2. The vendors chunk contains code from the bootstrap

It is also recommended to use webpack-bundle-analyzer if you want to customize splitChunks.

Django

In the previous chapters, when our JS code size is small, we can use Django static templatetag to import js code like this

<script src="{% static 'js/vendors.js' %}"></script>
<script src="{% static 'js/app.js' %}"></script>
  1. When the JS code size grow bigger, we can config code splitting to generate some specific chunk file.
  2. And then, we can config Webpack to removehash from the generated bundle file.
  3. In the end, we can import JS in Django template like this
<script src="{% static 'js/vendors-aaa.js' %}"></script>
<script src="{% static 'js/vendors-bbb.js' %}"></script>
<script src="{% static 'js/vendors-ccc.js' %}"></script>
<script src="{% static 'js/app.js' %}"></script>

Conclusion

Django + Webpack Series:

  1. Introduction
  2. Setup Webpack Project with Django
  3. Load Webpack bundles in Django
  4. Linting in Webpack
  5. Load Webpack hash bundle in Django
  6. Code splitting with Webpack (this article)
  7. How to config HMR with Webpack and Django
  8. How to load Webpack bundle in Django without using 3-party package (coming soon)

If you want a quick start with Webpack and Django, please check python-webpack-boilerplate


Michael Yin

Michael is a Full Stack Developer from China who loves writing code, tutorials about Django, Wagtail CMS and React.

He has published some ebooks on leanpub and tech course on testdriven.io.

He is also the founder of the AccordBox which provides the web development services.


Table of Contents

This book will teach you how to build a blog with React, Wagtail CMS and SSR (Server-Side Rendering), which has good performance and good SEO.

Read More

Subscribe

Get notified about new great Web Development Tutorial