spaceDog
spaceDog

Reputation: 461

How to fix delay browser reload in webpack dev server with express

I am trying to setup webpack dev server using webpackDevMiddleware, webpackHotMiddleware with express generator and react. I got everything working, but there's a huge delay in the reload.

I will get this message every time in the browser

 'GET http://localhost:8080/__webpack_hmr 
 net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)'

But 5 to 10 seconds later the browser will reload. In the terminal, these messages are showing

GET /7310e23232f92e879547.hot-update.json 404 6.282 ms - 1573
GET / 304 1.071 ms - -
GET /__webpack_hmr 200 1.767 ms - -
GET /stylesheets/style.css 304 1.306 ms - -
GET /app-bundle.js 200 5.337 ms - 2960039

I think the express server has a delay or stopping from getting the hot-update.json.

I have tried time out and keepAliveTimeout the bin/www file

server.listen(port, () => {
  server.timeout = 0
  server.keepAliveTimeout = 0
 });

package.json

{
  "name": "react-webpack-hmr",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "dev": "nodemon ./bin/www --inspect --watch app.js --watch webpack.config.js --watch src",
    "build": "webpack --config=webpack.config.js",
    "clean": "rimraf public/dist"
  },
  "dependencies": {
    "babel-loader": "^8.0.4",
    "cookie-parser": "~1.4.3",
    "css-loader": "^2.1.0",
    "debug": "~2.6.9",
    "ejs": "~2.5.7",
    "ejs-loader": "^0.3.1",
    "express": "~4.16.0",
    "extract-loader": "^3.1.0",
    "file-loader": "^3.0.1",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "http-errors": "~1.6.2",
    "morgan": "~1.9.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-hot-loader": "^4.6.3",
    "style-loader": "^0.23.1"
  },
  "devDependencies": {
    "@babel/preset-react": "^7.0.0",
    "@babel/runtime": "^7.2.0",
    "@babel/generator": "^7.2.2",
    "@babel/polyfill": "^7.2.5",
    "babel-plugin-async-to-promises": "^1.0.5",
    "@babel/core": "^7.2.2",
    "@babel/plugin-transform-runtime": "^7.2.0",
    "@babel/preset-env": "^7.2.3",
    "webpack": "^4.28.3",
    "webpack-cli": "^3.1.2",
    "webpack-dev-middleware": "^3.4.0",
    "webpack-dev-server": "^3.1.14",
    "webpack-hot-middleware": "^2.24.3"
  }
}

webpack.config.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');

    module.exports = {
        entry: {
            app: [  
                'webpack-hot-middleware/client?reload=true',
                // 'webpack/hot/only-dev-server',
                // 'react-hot-loader/patch',
                "@babel/runtime/regenerator",
                "./src/app.js"
            ]
        },
        mode: 'development',
        output: {
            filename: "[name]-bundle.js",
            path: path.join(__dirname, 'public/dist'),
            publicPath: "/"
        },
        devtool: "cheap-eval-source-map",
        devServer: {
            contentBase: "dist",
            overlay: true,
            hot: true
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: [
                    {
                        loader: 'babel-loader'
                    }
                    ]
                },
                {
                    test: /\.html$/,
                    use: [
                    {
                        loader: "html-loader"
                    }
                    ]
                },
            ]
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NamedModulesPlugin(),
            new HtmlWebpackPlugin({
                template: './views/index.ejs'
            })
        ]
    }

app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

const webpack = require("webpack");
const config = require("./webpack.config");
const compiler = webpack(config);

const webpackDevMiddleware = require('webpack-dev-middleware')(compiler, config.devServer);
const webpackHotMiddleware = require('webpack-hot-middleware')(compiler, config.devServer);

var app = express();

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());


app.use(webpackDevMiddleware);
app.use(webpackHotMiddleware);
//app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

React side app.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import { AppContainer } from 'react-hot-loader';

function render(Component) {
  ReactDOM.render(
    <AppContainer>
      <Component />
    </AppContainer>, 
    document.getElementById('app')
  )
}

render(App);

if (module.hot) {
  module.hot.accept('./components/App', () => {
    const newApp = require('./components/App').default 
    render(newApp);
  })
}

I expect the browser will reload after is finished compiling the new code without a delay everytime I save my files.

Upvotes: 3

Views: 3612

Answers (2)

Tiberiu Maxim
Tiberiu Maxim

Reputation: 1582

TLDR; In order to have hot module reload working with Nodemon you need to exclude the client code from watch.

Webpack uses __webpack_hmr to receive events about changes in code. If you edit a file then save it, Nodemon restarts and in this time Webpack HMR loses connection to the event stream, resulting in a miss for getting updated code. This is the reason why you need to exclude client side code from the watch list of Nodemon. Basically client side code refresh is 'managed' by Webpack dev server.

Usually I have a nodemon.json file in my root to let Nodemon know what to watch:

{
  "watch": [
    "server.js",
    "src/server",
    "config"
  ]
}

Upvotes: 2

spaceDog
spaceDog

Reputation: 461

So I fixed it was my package.json

I was watching the react files which it shouldn't

I removed the old code this is the new one

"dev": "nodemon --inspect --watch webpack.config.js --watch app.js",

Upvotes: 3

Related Questions