How to configure Hot Module Replacement (HMR) with django-webpack-loader

It is very frustrating to reload your Django website manually each time you make a change to the frontend code. In addition to performing an extra action every time you change something, you also waste a lot of time by waiting until your whole website reloads.

Thankfully, Webpack has a feature called Hot Module Replacement (HMR). It means that instead of reloading a page manually every time you make a change, Webpack will listen to the changes you make, tell a browser what parts of the code have changed exactly and load them automatically (instead of doing a complete page reload).

Sounds great right? However, it is not clear how to configure it to work with django-webpack-loader: the tutorial written by the package author is outdated and didn't work for me. Here's what I did to solve the problem.

Webpack configuration

First, you'll need to install a webpack-dev-server (WDS) package:

 npm install --save-dev webpack-dev-server

This is a development server that will build and serve your assets (replacing Django staticfiles). It will also notify a browser when to reload the code.

Now, add these lines to your Webpack config (e.g. webpack.config.js):

module.exports = {
    ...
    mode: 'development',
    output: {
        // points to a webpack-dev-server (WDS), configured below
        // it is important that the url points to a WDS, not Django
        // I would use the same prefix you'd use in STATIC_URL,
        // in my case it is "/static/", but it is not really important
        publicPath: 'http://localhost:9000/static/',
    },
    // serve assets via webpack-dev-server instead of Django so that HMR can work
    devServer: {
        // for assets not handled by webpack
        contentBase: '/path/to/your/assets,
        // port should be different from the one you use to run Django
        port: 9000,
        headers: {
          'Access-Control-Allow-Origin': '*'
        },
        // gzip everything served by dev server, could speed things up a bit
        compress: true,
        // HMR
        hot: true
    },
});

This config tells WDS to listen for connections at 9000 port, by default the hostname is set to localhost. To start the WDS run this command:

npx webpack-dev-server

This command will start the WDS server, build your assets and wait for connections from the browser. Now when you visit your website, a browser loads the assets from WDS instead of the Django staticfiles module.

This approach doesn't require any changes to the Django configuration, considering you already had a basic django-webpack-loader setup.

How does the HMR work here?

The interesting thing here is that the contents of the assets files (loaded by a browser) are replaced with the code that does a couple of things:

  1. listens for a change to your asset file
  2. fetch the updated asset once you've changed the file
  3. execute the new asset code in the browser

The actual contents of your assets are kept inside WDS memory. This approach means that we don't need to install any browser extensions for this setup to work. Nice, right?