Code Splitting with Webpack

Table of Contents

  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
  7. How to config HMR with Webpack and Django
  8. How to use HtmlWebpackPlugin to load Webpack bundle in Django

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

  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
  7. How to config HMR with Webpack and Django
  8. How to use HtmlWebpackPlugin to load Webpack bundle in Django

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

Launch Products Faster with Django

SaaS Hammer helps you launch products in faster way. It contains all the foundations you need so you can focus on your product.

Michael Yin

Michael Yin

Michael is a Full Stack Developer from China who loves writing code, tutorials about Django, and modern frontend tech.

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

© 2024 SaaS Hammer