webpack / webpack-dev-server

Serves a webpack app. Updates the browser on changes. Documentation https://webpack.js.org/configuration/dev-server/.
MIT License
7.8k stars 1.44k forks source link

React Hot Reloader + webpack-dev-server doesn't update after a syntax error is fixed #655

Closed mikeengland closed 8 years ago

mikeengland commented 8 years ago

I'm submitting a bug report

webpack and webpack-dev-server version: webpack: 1.13.1 webpack-dev-server: 1.14.1

Please tell us about your environment: OSX 10.11

Current behavior: I am using the React Hot Reloader (v3.0.0-beta.5) with the webpack-dev-server. It works as expected if no errors occur. If an error occurs, for example due to an invalid JSX tag, an error is displayed in the console. This is great, however when the code is fixed and valid, the hot reloader says it is recompiling and then ready, but any future changes are not 'hot reloaded' and are not shown on the screen.

An issue was raised on react-hot-loader about this. One of the contributors closed the issue
and said This is an issue with Webpack Dev Server, and I recommend using webpack-dev-middleware/webpack-hot-middleware.

https://github.com/gaearon/react-hot-loader/issues/389

I can see the updated code in the hot-update.js response however, so I am not sure if this is an issue with the React hot reloader not picking it up.

Note: I also added the noErrorsPlugin, which seems to stop emitting if a compilation error occurs, however, the hot reloader still does not update properly once this is fixed.

When I fix the error, I receive a 404 on the hot-update.json file. Maybe this is causing the issue?

image

Please can someone advise?

Thanks!

SpaceK33z commented 8 years ago

This might be related to https://github.com/webpack/webpack/issues/2117.

mikeengland commented 8 years ago

@SpaceK33z Looks like the fix only went into webpack v2.1.0-beta.x 👎

SpaceK33z commented 8 years ago

You're free to back port it to v1 with a PR.

Closing because it has been fixed in v2.

koddo commented 8 years ago

I have the same issue. Could you point me to the fix in the beta? Update: Ok, found the commit.

SpaceK33z commented 8 years ago

@koddo, it's called hotOnly throughout the code of dev-server.

koddo commented 8 years ago

I wonder why noErrorsPlugin doesn't work. It should stop any emitting, but it doesn't.

koddo commented 8 years ago

When using the noErrorsPlugin, after making an error and then fixing it, module.hot.status() returns "check", when it should return "idle". So, basically it gets stuck somewhere, I can't figure out.

koddo commented 8 years ago

Ok, a tiny monkey patch for this issue. I have webpack v1.13.2 with noErrorsPlugin.

I know this is an awful hack, please don't hate me.

First, add the setStatus() function in node_modules/webpack/lib/HotModuleReplacement.runtime.js

module.exports = function() {
    // ...
    function hotCreateRequire(moduleId) {
        // ...
        setStatus: function(s) {
            hotSetStatus(s);
        },
        // ...

Second, call it in the module.hot.check callback in node_modules/webpack/hot/only-dev-server.js to make it unstuck from the "check" status.

if(module.hot) {
    var check = function check() {
        module.hot.check(function(err, updatedModules) {
            if(err) {
                // ...
                } else {
                    console.warn("[HMR] Update check failed: " + err.stack || err.message);
                    module.hot.setStatus("idle");    // <<<---------- here it is !!!
                }
                return;
            }
            // ...             
mikeengland commented 8 years ago

@koddo I tried both this hack and upgrading to the latest beta webpack-dev-server and webpack releases. The red box is shown if you break a dependency e.g. try and use instead of , but if you actually break the JSX tag e.g. 'Link>', an error is raised in the console but no further updates actually seem to hot reload on the page.

koddo commented 8 years ago

@mikeengland, what is a red box? I only have errors in the console. I see syntax errors in jsx, fix them, and then it hot reloads. I understand this feeling of helplessness because of lack of live reload in the twenty first century, so I'm willing to help. Do you use webpack v1.13.2 with noErrorsPlugin, webpack/hot/only-dev-server.js, and webpack-dev-server/client? I use create-react-app, and then eject, and configure this stuff in the webpack.conf.

koddo commented 8 years ago

@mikeengland, webpack/hot/only-dev-server.js, not just webpack/hot/dev-server.js, this is important.

mrdulin commented 8 years ago

@koddo Same issue with you. The NoErrorsPlugin, I made a syntax error to test this plugin, but it seems not work.

koddo commented 8 years ago

@mrdulin, please try the hack I've posted above. I'd share it, but I'll have to create a hundred megabytes repo with all those node_modules/. And that wouldn't be safe for you to run arbitrary code which came from an internet stranger.

Before doing the following steps from scratch, try to add an error handler to the module.hot.accept() first. Should look like this: if(module.hot) { module.hot.accept( function(err){console.log(err)} ) }. Without this the HMR goes to fail state: https://github.com/webpack/webpack/issues/418#issuecomment-53398056

@mikeengland: I forgot to mention that callback for module.hot.accept(). Please try it.

To make it work I did create-react-app, ejected it, monkey patched those node_modules/react-scripts/node_modules/webpack/lib/HotModuleReplacement.runtime.js and node_modules/webpack/hot/only-dev-server.js. Then added NoErrorsPlugin and commened out require.resolve('react-dev-utils/webpackHotDevClient'), uncommented require.resolve('webpack-dev-server/client') + '?/' and require.resolve('webpack/hot/dev-server'), we need the only-dev-server though, so I made this edit. And then I put if(module.hot) { module.hot.accept( function(err){console.log(err)} ) } to index.js.

mikeengland commented 8 years ago

@koddo I tried this but I couldn't get it working if a compilation error occurs. Note, I am not using Create-React-App. One thing I did not do is add if(module.hot) { module.hot.accept( function(err){console.log(err)} ) } to index.js. I am using the Hot Reloader v3 Beta (latest) so I have this in index.js:

const HotContainer = ({store}) => <AppContainer><Root store={store}/></AppContainer>;

if (module.hot) {
    module.hot.accept(Root, () => {
        render(<HotContainer store={store}/>, document.getElementById('app-root'));
    });
}
koddo commented 8 years ago

@mikeengland, hm, I've just checked, this line has no effect, hmr doesn't break without it. So, I've found the only configuration that works for me. Sorry, can't help you with the hot reloader.

dsteinman commented 7 years ago

I encountered this same problem, and I discovered it was because in my server (nodejs/express) I defined my webpack /build/ directory to be a static directory served by Express:

app.use(express.static('/build', '../public/build'));

But the new webpack-dev-server and hot-loader need to be the one serving your build directory while in development mode. So my solution was to enable static delivery of my build directory when not in development mode:

if (process.env.NODE_ENV != 'dev') { app.use(express.static('/build', '../public/build')); }

And then in my webpack config I set publicPath to be '/build':

var config = { devtool: 'source-map', output: { path: path.resolve(__dirname, '../public/build'), filename: 'bundle.js', publicPath: '/build' }, ....

So now in dev mode, the bundle and the .hot-update.json files are served by webpack-dev-server:

http://localhost:8000/build/bundle.js http://localhost:8000/build/c3b3297060d3e2abe0a4.hot-update.json