webpack-dev-server: Hot update not update the view (screen)

I wrote a little react app and serve static files from a separate express server (to redirect all sub-pathes to index.html [react-router]).

static server on port 8080 webpack hot dev server on port 8081

Browser console log:

[HMR] Waiting for update signal from WDS...
client:14 [WDS] Hot Module Replacement enabled.

after modify and save a file (e.g. router.js)

client:18 [WDS] App updated. Recompiling...
client:60 [WDS] App hot update...
dev-server.js:54 [HMR] Checking for updates on the server...
dev-server.js:34 [HMR] Updated modules:
dev-server.js:36 [HMR]  - 11
dev-server.js:40 [HMR] App is up to date.

But on the screen nothing change

The cli console log show:

Hash: a00a156bb0c50980187c
Version: webpack 1.5.3
Time: 483ms
                               Asset     Size  Chunks             Chunk Names
                              app.js   130429       0  [emitted]  app
                           vendor.js  1854993       1  [emitted]  vendor
0.919fa51221ca3cdacfb2.hot-update.js     3980       0  [emitted]  app
919fa51221ca3cdacfb2.hot-update.json       36          [emitted]  
chunk    {0} app.js, 0.919fa51221ca3cdacfb2.hot-update.js (app) 117673 {1} [rendered]
    [0] multi app 52 {0}
    [1] (webpack)-dev-server/client?http://localhost:8081 1674 {0}
    [2] ./src/app.js 2597 {0} [1 error]
    [4] (webpack)/hot/dev-server.js 2916 {0}
   [11] ./src/router.js 3370 {0} [built]
   [34] (webpack)-dev-server/client/web_modules/socket.io/index.js 1149 {0}
   [89] (webpack)-dev-server/client/web_modules/socket.io/socket.io.js 105915 {0}
chunk    {1} vendor.js (vendor) 1601853 [rendered]
    [0] multi vendor 76 {1}
.
.
.
  [257] ./~/react/lib/toArray.js 3176 {1} [built]
webpack: bundle is now VALID.

Structure

|- build/
|- dev/
   |- webpack.base.js
   |- dev-server.js
|- src/
   |- app.js
   |- router.js
|- static/
   |- index.html
   |- assets/
      |- ...some files...

package.json

  "dependencies": {
    "react": "^0.12.2",
    "react-router": "^0.11.4"
  },
  "devDependencies": {
    "express": "^4.11.1",
    "jsx-loader": "^0.12.2",
    "react-hot-loader": "^1.1.1",
    "webpack": "^1.5.3",
    "webpack-dev-server": "^1.7.0"
  }

webpack.base.js

var webpack = require('webpack');
var path = require('path');

var vendorLibs = [
    'react',
    'react-router'
];

module.exports = function(options) {
    return {
        context: path.join(__dirname, '../', 'src'),
        entry: {
            app   : [
                'webpack-dev-server/client?http://localhost:8081',
                'webpack/hot/dev-server',
                './app.js'
            ],
            vendor: vendorLibs,
        },
        output: {
            path             : path.join(__dirname, '../', 'build'),
            filename         : '[name].js',
            chunkFilename    : '[id].bundle.js',
            sourceMapFilename: '[file].map',
            pathinfo         : true,
            publicPath       : 'http://localhost:8081/'
        },
        module: {
            loaders: [
                { test: /\.js$/, loaders: ['react-hot', 'jsx?harmony'] }
            ]
        },
        resolve: {
            extensions: ['', '.js']
        },
        debug: options.debug,
        devtool: options.devtool,
        plugins: [
            new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity }),
            new webpack.HotModuleReplacementPlugin()
        ]
    }
};

dev-server-js

var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var express = require('express');
var path = require('path');
var fs = require('fs');

var app = express();
var config = require('./webpack.base.js')

// Redirect all non existing files to index.html
app.get('/*', function(req, res) {
    var filename = path.join(__dirname, '../', 'static', req.url);
    if (fs.existsSync(filename)) {
        console.log('static: ' + req.url);
        res.sendFile(filename);
    } else {
        console.log('static: index.html (' + req.url + ')');
        res.sendFile(path.join(__dirname, '../', 'static') + '/index.html');
    }
});

var compiler = webpack(config({
    devServer    : true,
    devtool      : 'eval',
    debug        : true
}));

var server = new WebpackDevServer(compiler, {
    contentBase: 'http://localhost:8081',
    hot: true,
    quiet: false,
    noInfo: false,
    lazy: false,
    watchDelay: 300,
    publicPath: 'http://localhost:8081/',
    stats: { colors: true },
});

server.listen(8081, 'localhost', function() {});
app.listen(8080);

app.js

<!DOCTYPE html>
<html>
<body>
    <div id="app"></div>
    <script src="http://localhost:8081/vendor.js"></script>
    <script src="http://localhost:8081/app.js"></script>
</body>
</html>

Is it a problem when serving the index.html from an other port? The docs say it is possible (http://webpack.github.io/docs/webpack-dev-server.html#combining-with-an-existing-server)

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 34 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I have the same problem, there is interesting solution which use “self-accepting”, the index.js is:

import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'

import App from './containers/App'

const render = Component => { 
    ReactDOM.render(
        <AppContainer>
            <Component/>
        </AppContainer>,
        document.getElementById('react-root')
    )
}

render(App)

/** It doesn't work
 * 
    if(module.hot) {
        module.hot.accept('./containers/App', () => {
            render(App)
        })
    }
 */

// It works well
if(module.hot) {
    module.hot.accept();
}

@bobzhang did you find a solution? I am seeing the same problem.

I also met this problem, and I solved it by change

import { AppContainer } from 'react-hot-loader';
import App from 'js/App';

if (module.hot) {
    module.hot.accept('./App', () => {
        ReactDom.render(
          <AppContainer>
            <App />
          </AppContainer>,
          document.getElementById('root'),
        );
    });
}

to

import { AppContainer } from 'react-hot-loader';
import App from 'js/App';

if (module.hot) {
    module.hot.accept('./App', () => {
        const NextApp = require('js/App').default;
        ReactDom.render(
          <AppContainer>
            <NextApp />
          </AppContainer>,
          document.getElementById('root'),
        );
    });
}

Seems the App won’t refresh it self, so we need to re-import it, also need to make sure import it after(or say inside) the module.hot.accept function call.

Hope it helps 😃

I’m also experiencing this issue. I’ve asked a question on StackOverflow which can be seen here:

http://stackoverflow.com/questions/43491310/cant-get-webpack-2-hmr-react-to-work

This works for me:

if(module.hot) {
  module.hot.accept();
}

This also works for me:

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

This doesn’t:

if (module.hot) {
  module.hot.accept('./components/TodoApp', () => {
    render(TodoApp)
  });
}

Why doesn’t the default setup work? Really confused.

Thanks @Armour, it works well! My index.js is:

import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'

import App from './containers/App'

const render = Component => { 
    ReactDOM.render(
        <AppContainer>
            <Component/>
        </AppContainer>,
        document.getElementById('react-root')
    )
}

render(App)

/** It doesn't work
 * 
    if(module.hot) {
        module.hot.accept('./containers/App', () => {
            render(App)
        })
    }
 */

// It works well
if(module.hot) {
    module.hot.accept('./containers/App', () => {
        const NextApp = require('./containers/App').default
        render(NextApp)
    })
}

Thanks @Armour. I followed https://webpack.js.org/guides/hmr-react/ which says “Note that because webpack 2 has built-in support for ES2015 modules, you won’t need to re-require your root component in module.hot.accept” but the browser did not update the view. After “re-requiring” the component within the module.hot.accept callback everything worked as expected.

I finally got this working after 5+ hours looking through many different github issues and tutorials.

First off, versions for what I’m using currently:

  • webpack: 4.1.1
  • webpack-dev-server: 3.1.1

Two things helped resolve this issue and have the browser reload on source code change:

  1. setting webpack’s config for hot to false – hot: false

People said that they did not include this property in their config s but I had to set the value to false for it to work for me

  1. including a bundle to the client for webpack-dev-server:
entry: {
  hmr_endpoint: 'webpack-dev-server/client?http://localhost:8008'
}

Whatever you name it doesn’t matter. including it in an array works as well; just be wary of mismatching types if you are doing this all through Node’s api like I am.

entry: [
  'webpack-dev-server/client?http://localhost:8008'
]

Obviously change the port to whichever one you are working with in your project. Hope this helps someone and resources I looked at that helped me come to this: 1 2 3

I had this issue and for me the underlying problem was misconfigured babel presets. Before (leading to exactly the same HMR situation as @daviddelusenet):

presets: [
  [ 'es2015', { modules: false } ],
  'stage-0',
   'react',
]

After (The usual approach now works):

presets: [
  [ 'env', { modules: false } ],
   'react',
]

I think options to a preset can be overriden by other presets, in this case presumably stage-0 also turned the modules transform back on.

Source: https://stackoverflow.com/questions/43491310/cant-get-webpack-2-hmr-react-to-work/43500626