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)
The react-hot-loader only works for React components. Is route.js a React component?
Yes it is the react-router with a sample react component.
I test it before on one port with a webpack dev only server, and it worked, then splitted it into 2 servers and got the problem.
Or is it possible to redirect router paths to index.html with webpack-dev-server?
e.g. for a direct call of http://localhost:8080/some/path/4711
The log looks pretty good... It does't look like a connection/configuration issue.
cc @gaearon
Can you put up a reproducible example in a repo so I could examine it?
Funny, i create an example with the code above, everything worked.
Then i try my project again and it worked too.
Hope it was the update of chrome that solved the problem and it is no other strange problem.
Reopened the problem.
I try my app at my office computer and got the problem.
At home i run Win7 Host with a VirtualBox Mint 17 and it worked without a problem in the box.
In the office i use a native Mint 17 with the same chrome (synced with the same plugins)... the browser not update the view.
Did somebody have an idea how i can determine the problem?
Any change you have duplicate react in node_modules?
For example, some other library may have it in its own node_modules..
"dependencies": {
"react": "^0.12.2",
"react-router": "^0.11.6"
},
"devDependencies": {
"express": "^4.11.1",
"jsx-loader": "^0.12.2",
"react-hot-loader": "^1.1.3",
"webpack": "^1.5.3",
"webpack-dev-server": "^1.7.0"
}
cleaned node_modules dir and install all modules new.
Does https://github.com/gaearon/react-hot-boilerplate work on that computer?
Thanks, found the problem: apparmor blocked something on port 8080. (previously i run a docker project and uninstalled docker)
Funny problem, script compilation run and browser message for reload appears, only the browser view not update thats why it was not obvious what was not working.
Good, thank you for sharing!
I see the same problem @rottmann , how can I fix it?
Logs below look perfectly fine, just chrome not updated ..
[WDS] App hot update...
bundle.js:8022 [WDS] App hot update...
bundle.js:7911 [HMR] Checking for updates on the server...
bundle.js:7945 [HMR] Updated modules:
bundle.js:7947 [HMR] - 59
bundle.js:7897 [HMR] App is up to date.
@bobzhang did you find a solution? I am seeing the same problem.
I ran into the same problem yesterday. Any information on how to fix that?
@mikealexander Did you find a solution for your problem?
I have this same problem, anyone help
Same problem, the browser received the hot-update.js but updated nothing,
I tried to execute the code which is in the hot-update.js and still nothing happened.
Okay, I solved this problem by STOP USING webpack-merge for my config.entry.client.
module.exports = merge(config,
{
entry:
{
cilent:
[
'webpack-hot-middleware/client',
config.entry.client
]
}
})
CHANGE TO
config.entry.client = ['webpack-hot-middleware/client', config.entry.client]
Did anyone find a solution?
I also met this problem, and I solved it by change
~~~js
import { AppContainer } from 'react-hot-loader';
import App from 'js/App';
if (module.hot) {
module.hot.accept('./App', () => {
ReactDom.render(
document.getElementById('root'),
);
});
}
~~~
to
~~~js
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(
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 :)
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.
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)
})
}
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();
}
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.
Had the same issue since this morning and this fixed it !
I had the same issue and it boils down to how module code generation works in your setup (through Babel/TypeScript). From my limited understanding, webpack 2 should be able to inject the require call using ES6 modules. I use TypeScript, and the below tsconfig values worked for me:
{
"target": "es6",
// "module": Don't override this to anything
"moduleResolution": "node",
}
I remember reading about a module: false parameter in Babel that did something similar for webpack + Babel configs.
module.hot.accept() and module.hot.accept('module') may not always be interchangeable. Make sure you understand what they each do.
@ssynix I'm also using typescript (2.2.2) and I can't seem to get react-hot-loader@next it to work following the https://github.com/gaearon/react-hot-loader/tree/master/docs#webpack-2 example as @davincho did. Re-requiring the app in the hot reload handler works, as does just calling module.hot.accept(), but I'd like to get it working as documented. As I think @ssynix is right "it boils down to how module code generation works in your setup", I've been trying a number of different settings without much luck (would like to take advantage of tree shaking).
// main.tsx
import { AppContainer as HotContainer } from 'react-hot-loader';
import { default as App } from './containers/AppContainer';
...
const render = (Component: any) => {
ReactDOM.render(
<HotContainer>
<Component
store={store}
routes={routes}
/>
</HotContainer>,
root
);
};
...
if (module.hot) {
module.hot.accept('./containers/AppContainer', () => {
if (root) {
ReactDOM.unmountComponentAtNode(root);
}
render(App);
});
}
//.babelrc
{
"presets": [
[
"es2015",
{
"modules": false
}
],
"stage-0",
"react"
],
"plugins": [
"react-hot-loader/babel",
...
]
}
// tsconfig.json
{
"compilerOptions": {
"isolatedModules": true,
"moduleResolution": "node",
"target": "es2015"
...
}
}
if(module.hot) {
module.hot.accept();
}
This works for me too, in the angular app. Thanks so much~~~
I struggled with this for a bit with Webpack 3 and got it working with the import() syntax. Not sure if this is helpful to anyone but here's what's working for me:
```import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
const run = async () => {
const { Root } = await import('index');
ReactDOM.render(
document.getElementById('react'),
);
};
const loadedStates = ['complete', 'loaded', 'interactive'];
if (loadedStates.includes(document.readyState) && document.body) {
run();
} else {
window.addEventListener('DOMContentLoaded', run, false);
}
module.hot.accept('index', run);
```
@swxy
This works for me thanks a lot!
I am using, webpack 2.2 + RRV4 + React-hot-loader v3 and webpack-hot-middleware.
if(module.hot) {
module.hot.accept();
}
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
Thanks @hedgepigdaniel. Its mentioned in the react-hot-loader doc here, that
"To make this work, you'll need to opt out of Babel transpiling ES2015 modules by changing the Babel ES2015 preset to be ["es2015", { "modules": false }]"
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:
Two things helped resolve this issue and have the browser reload on source code change:
hot to false -- hot: falsePeople 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
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
@tiodot 's solution worked with Typescript + React but failed with Redux and Redux Saga Integrated.
Most helpful comment
I have the same problem, there is interesting solution which use "self-accepting",
the
index.jsis: