I have a basic setup with two apps each in a separate directory, I'm using a custom server to compile them using webpack-dev-middleware
/webpack-hot-middleware
. Things are working fine except that I can't get HMR to work for the second app (I'm using react-hot-loader
).
Here's a minimal repo illustrating the problem: https://github.com/AmrN/multi-react-app-hmr
My main code files:
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = function (appName) {
return {
devtool: 'cheap-module-eval-source-map',
entry: [
'react-hot-loader/patch',
'webpack-hot-middleware/client',
path.join(__dirname, appName, 'index'),
],
output: {
path: path.join(__dirname, 'dist', appName),
filename: 'bundle.js',
publicPath: '/'+appName+'/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, appName, 'index.html'),
}),
],
module: {
loaders: [{
test: /\.jsx?$/,
loaders: ['babel-loader'],
exclude: /node_modules/,
}]
},
};
};
server.js
var path = require('path');
var webpack = require('webpack');
var express = require('express');
var config1 = require('./webpack.config')('app1');
var config2 = require('./webpack.config')('app2');
var app = express();
[config1, config2].forEach((config) => {
var compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
});
app.listen(3000, function (err) {
if (err) {
return console.error(err);
}
console.log('Listening at http://localhost:3000/');
});
(app1|app2)/index.js
import { AppContainer } from 'react-hot-loader';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const rootEl = document.getElementById('root');
const render = Component =>
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
rootEl
);
render(App);
if (module.hot) module.hot.accept('./App', () => render(App));
Now if I run the server, my files are compiled correctly, and I can visit http://localhost:3000/app1/index.html
successfully, and HMR is working properly here. However, if I visit the second app http://localhost:3000/app2/index.html
it opens but HMR is not working and looking at the console it gives me the following error:
GET http://localhost:3000/app2/640a44b6b47b67436af2.hot-update.json 404 (Not Found)
[HMR] Cannot find update (Full reload needed)
[HMR] (Probably because of restarting the server)
Another thing I've noticed is that changing the order in which I apply my apps webpack configs in server.js from:
[config1, config2].forEach((config) => {...})
to:
[config2, config1].forEach((config) => {...})
switches the problem to app1, now HMR works for app2 but not app1.
Any help is appreciated, thanks.
To enabling HMR in your project, you need to let your application know how to handle hot updates. You can do so by implementing the module. hot API exposed by Webpack. Once the hot update is accepted, the HMR runtime and the loaders will take over to handle the update.
Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways: Retain application state which is lost during a full reload. Save valuable development time by only updating what's changed.
The problem was that both apps used the same path for hot reloading (I think it's /__webpack_hmr
by default).
So I had to use a different one for each:
in webpack.config.js I did:
entry: [
// ...
'webpack-hot-middleware/client?path=/__webpack_hmr_'+appName,
// ...
]
and in server.js:
app.use(require('webpack-hot-middleware')(compiler, {
path: '/__webpack_hmr_'+appName
}));
Now it's working properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With