Is it possible to do hot reloading when using Gulp and Browsersync?

This probably sounds familiar: you have a setup with Gulp, Webpack and BrowserSync. Gulp compiles your scss/less files, Webpack compiles your JS files and BrowserSync nicely refreshes the page when anything changes.

Now you'd like to make this even better - and have hot reloading of your JavaScript.

But you're not sure how to go about it - and you definitely wouldn't like to ditch your entire Gulp setup for a Webpack-only one just for hot reloading.

The good news is - you don't have to!

What makes the integration possible?

In a Webpack only setup, you would use webpack-dev-server to serve your application in development mode and to have hot reloading work.

But you already serve your files through BrowserSync. So you will need to extend BrowserSync's server abilities to also support hot reloading.

This can be achieved using midlleware components and Webpack already provides webpack-dev-middleware and webpack-hot-middleware specifically for this purpose.

Up next, we'll walk through the steps described in this BrowserSync recipe.

1. Configure BrowserSync with Webpack middleware

Install the modules from npm:

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

Then, include them at the top of your Gulpfile.js:

var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var browserSync = require('browser-sync').create();

And finally, add them to your browserSync.init config:

var webpackConfig = require('./webpack.config');
var bundler = webpack(webpackConfig);
browserSync.init({
        server: {
            baseDir: "./",

            middleware: [
                webpackDevMiddleware(bundler, {
                    publicPath: webpackConfig.output.publicPath,
                    stats: { colors: true }
                }),
                webpackHotMiddleware(bundler)
            ]
        }
    });
});    

That's it for this file! Now you also need to make some changes in the webpack.config.js.

Note: Did you already have any Gulp task for listening to JS file changes before? If yes, you can now safely delete that, since Webpack will now notify Browsersync of changes out of the box

2. Configure Webpack config for hot module reloading

There are two things you need to change in the config file:

  • update the entry property with two new entries
  • add the Webpack plugin for hot reloading
var webpack = require('webpack');
var path = require('path');

module.exports = {
    entry: [
        'webpack/hot/dev-server',
        'webpack-hot-middleware/client',
        './src/index.js'
    ],
    output: {
        filename: 'index.js',
        path: path.join(__dirname, 'dist'),
        publicPath: '/dist'
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    module: {
        loaders: [
            {
                test: /\.js?$/,
                exclude: /node_modules/,
                loaders: ['react-hot', 'babel']
            }
        ]
    }
};

Make sure to double check your output property to ensure path and publicPath are set. This is weird, but if you don't have path set you will get a very cryptic error :)

Also, you'll see that react-hot-loader was added to the loaders - this is only needed if you use React (don't forgat to also install it using npm install --save-dev react-hot-loader).

3. Good to go

Now run your gulp task for starting BrowserSync again and you should have hot reloading working!

Had trouble setting this up? Let me know in the comments!