Webpack hot module replacement with Express

Craig Stroman
3 min readNov 13, 2019

Lately I’ve been developing a lot of React apps and I use Express for my backend. I realized I wanted to have hot module replacement (HMR) but most examples I found where using WebPack dev server.

After doing some research I discovered you can use hot module replacement with Express instead of just using WebPack dev server as your server. And since there weren’t that many sources when I was searching I figured I would write a blog post about how to do this.

To get Started, open up the terminal in your projects directory and run the following command to install Express, Pug, and React using npm:

npm install --save express pug react react-dom

For this example code I’ll be using React for the frontend along with Express, and Pug for the backend.

Run the following command for installing WebPack, webpack-dev-middleware, webpack-hot-middleware, and nodemon:

npm install --save-dev webpack webpack-dev-middleware webpack-hot-middleware nodemon

Please note if you’re using nodemon with Express you have to also create a nodemon.json file in the root of the project and tell it to ignore the public folder. Otherwise nodemon will restart the server when files in the public folder are updated.

It should be setup using the following pattern:

{
"ignore": [
"public/"
]
}

For this I’m using WebPack version 4.

Now it’s time to configure the server. Create a file called index.js and add the following to it:

const path = require('path');
const express = require('express');
const PORT = 3000;
const app = express();
app.set('views', path.join(__dirname, './views'));app.set('view engine', 'pug');app.use('/static', express.static('public'));app.use('/', (req, res) => {
res.render('index', {
title: 'WebPack Hot Module Replacement with Express',
});
});
app.listen(PORT, () => {
console.log(`App is listening on port ${PORT}`);
});

The following is a simple example of a Pug template that I’m using for this example located within the server/views folder:

doctype html
html(lang='en')
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1')
meta(name='description', content=content)
title #{title}
body
#app
script(src='/static/js/bundle.js')

Now it’s time to attach the middleware to the server, in the index.js file add the following:

const webpack = require('webpack');
const webpackConfig = require('./webpack.config');
const webpackCompiler = webpack(webpackConfig);
app.use(
require('webpack-dev-middleware')(webpackCompiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath,
}),
);
app.use(
require('webpack-hot-middleware')(webpackCompiler, {
path: '/__webpack_hmr',
}),
);

Adding all that code to your main index.js file should now make Express work with hot module replacement. These lines of code will make Express watch for changes and then push those changes to the client side code.

Now with the server side all set you have to make some additions to the client side and the webpack.config file for this to work. Setup your webpack.config.js file with the following:

const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
app: [
path.join(__dirname, 'client/index.jsx'),
'webpack-hot-middleware/client?path=/__webpack_hmr&reload=true',
],
},
output: {
publicPath: '/static/js/',
path: filePath,
filename: fileName,
hotUpdateChunkFilename: '.hot/hot-update.js',
hotUpdateMainFilename: '.hot/hot-update.json',
},
watchOptions: {
ignored: '/node_modules/',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
]
};

Setting up your webpack.config this way will make it work with Express. The main things to notice are in the app property and the path.

The other 2 items are the hotUpdateChunkFilename and hotUpdateMainFilename properties in the output object. What these two properties do is clean up the HMR output files. Adding those properties will keep WebPack from generating new files every time hot module replacement is run.

Adding this to your project should make HMR with WebPack and Express work.

Note for this example I’m using React but you can also configure this to work with Vue, or Angular.

You can find a complete source of this boiler plate code at my GitHub. I also included a simple React app showing you how to use that. With this example repo you can also see how your package.json scripts should look.

--

--