This file serves as a repository of common problems setting up React Hot Loader, and solutions to them. Know a problem? Feel free to send a PR with edits.
If you don't see some of the messages, or some of the requests, or if some of the requests fail, this may be a symptom of an incorrect configuration. Comparing your setup with React Hot Boilerplate may help you find the mistake. If hot loading appears to be working but you still do not see all of the above messages, you may need to check your dev server's clientLogLevel setting. Depending on what it is set to, you may not see all of these messages, so you may need to adjust this setting to ensure that your configuration is correct.
If you're a TypeScript user then to get set up with HMR then it's not unusual to alias module
as an any
like so:
const anyModule = module as any;
if (anyModule.hot) {
anyModule.hot.accept('./app', () => render(App));
}
DON'T DO THIS. It will result in full page reloads each time you make a change. Instead do something like this:
if ((module as any).hot) {
(module as any).hot.accept('./app', () => render(App));
}
or this:
declare const module: any;
if (module.hot) {
module.hot.accept('./app', () => render(App));
}
Then you should see the expected messages / get the expected behaviour:
[HMR] Updated modules:
// ...
[HMR] App is up to date.
If you're using a precompiled React instead of react
npm package, React Hot Loader configuration will need a few tweaks. See Usage with External React.
Make sure you have '.js'
in resolve.extensions
section of Webpack config, or Webpack won't be able to find any JS files without explicitly specifying extension in require
.
If you're using React Hot Loader together with Babel (ex 6to5), make sure React Hot Loader stays to the left of Babel in loaders
array in Webpack config:
{ test: /\.jsx?$/, loaders: ['react-hot', 'babel'], include: path.join(__dirname, 'src') }
Webpack applies loaders
right to left, and we need to feed Babel's output to React Hot Loader, not vice versa.
If you're using a relative output path in your Webpack config, wrap it in a call to path.resolve()
:
var path = require('path');
module.exports = {
...,
output: {
path: path.resolve('./my-relative-path'),
...
}
};
If you used WebpackDevServer CLI mode and after switching to Node it crashes with Error: Invalid path ''
, you probably didn't have path
specified in output
at all. You can just put path: __dirname
there, as it won't matter for development config.
Most likely you used npm link
or yarn link
to use a development version of a package in a different folder, and React Hot Loader processed it by mistake. Read the guide about linking package in README linking section
Make sure you have exclude: /node_modules/
or, better, include: path.join(__dirname, 'src')
(path depends on your application) in loader configuration just like on this line. You never need to process node_modules
with React Hot Loader. If you use other loaders such as jsx?harmony
or babel
, most likely they also need to have include
specified.
Generally, the best way to fix this class of errors is to compare your setup to React Hot Boilerplate very carefully and see what's different.
WebpackDevServer CLI mode behaves slightly differently from its Node API. When in doubt, I suggest you use Node API like React Hot Boilerplate does.
If you are seeing an error like this:
[HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves.
You may have NODE_ENV
set to either production
or test
. Setting NODE_ENV
to either of these will cause react-hot-loader
to compile in production mode. Try setting NODE_ENV
to something like development
.
When using WebpackDevServer CLI flag --hot
, the plugin new HotModuleReplacementPlugin()
should not be used and vice versa, they are mutually exclusive but the desired effect will work with any of them.
If you're trying to access Webpack Dev Server from a URL served on another port, you may try:
- Changing
WebpackDevServer
options to include CORS header:
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
});
- Making sure that
webpack-dev-server
client host and port inwebpack.config.js
matches those of your development server:
entry: [
'webpack-dev-server/client?http://localhost:3000', // WebpackDevServer host and port
'webpack/hot/only-dev-server',
'./src/app',
];
If you get this warning when editing a root component, this may be because you don't export anything from it, and call React.render
from there. Put your root component in a separate file (e.g. App.jsx
) and require
it from index.js
where you call React.render
.
You also get this warning in v1.x if you write your root component as stateless plain function instead of using React.Component
. This problem is already solved completely in the upcoming v3.x.
This warning may also appear if you edit some non-component file which is require
d from files other than components. This means hot update bubbled up, but the app couldn't handle it. This is normal! Just refresh.
If you get this warning together with a 404 for hot-update.json
file, you're probably using an ancient version of webpack-dev-server
(just update it).
If you're running Node 0.11.13, you might want to try updating to 0.12. Some people reported this helped solve this problem. Also make sure that your require
s have the same filename casing as the files. Having App.js
and doing require('app')
might trip the watcher on some systems.
OS X also has a rarely-occuring bug that causes some folders to get 'broken' with regards to file system change monitoring. Here are some suggested fixes.
If you have several entry points in entry
configuration option, make sure webpack/hot/only-dev-server
is in each of them:
entry: {
app: ['./src/app', 'webpack/hot/only-dev-server'],
editor: ['./src/editor', 'webpack/hot/only-dev-server'],
...,
client: 'webpack-dev-server/client?http://localhost:3000'
}
You will have to include "client.js" in your host page for the hot updates to work. For example:
<script src="/static/bundle-client.js"></script>
<script src="/static/bundle-app.js"></script>
<script src="/static/bundle-entry.js"></script>
The entry points that don't have webpack/hot/only-dev-server
(or webpack/hot/dev-server
if you fancy occasional reloads) won't know how to apply hot updates.
If you combine WebpackDevServer with an existing server like Express and get this error message on hot updates, it is because Webpack is configured to request hot updates from the current hostname. So if your Express server is on 8000
and publicPath
in Webpack config is /build/
, it will request hot updates from http://localhost:8000/build/
, which in your case is served by Express. Instead, you need to set publicPath
to point to the port where WebpackDevServer is running. For example, it could be http://localhost:9000/build/
.
Verify that if you have enough available watchers in your system. If this value is too low, the file watcher in Webpack won't recognize the changes:
cat /proc/sys/fs/inotify/max_user_watches
Arch users, add fs.inotify.max_user_watches=524288
to /etc/sysctl.d/99-sysctl.conf
and then execute sysctl --system
. Ubuntu users (and possibly others): echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
.
First, make sure you have recent versions of Webpack and Webpack Dev Server (>= 1.7 is fine). Earlier versions use 404 code when no updates were available, so it wasn't technically an error.
Now, take a look at the path where they are requested. Webpack uses output.publicPath
from Webpack config to determine this path. If you forget to specify it, Webpack will request updates from a relative path to the current one, so any client-side routing will break it.
Normally you want it to be '/'
if you're serving scripts from root, something like '/scripts/'
if you have a virtual path for scripts, and something like 'http://localhost:port/scripts/
if you're using Webpack only for scripts but have another primary server like Express. This config variable must also match publicPath
option specified when creating WebpackDevServer
instance. Take a look at React Hot Boilerplate to get an idea.
Make sure you have include
limited to your app's modules in loader configuration just like on this line. You never need to process node_modules
with React Hot Loader.
Make sure you have separate configs for development and production. You don't need react-hot
in loaders
or webpack-dev-server/client
or webpack/hot/only-dev-server
in production config. They are only for development. For easier maintenance, you can set an environment variable before invoking Webpack and read it in config.
Also make sure you have these plugins in production config:
// removes a lot of debugging code in React
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
// keeps hashes consistent between compilations
new webpack.optimize.OccurrenceOrderPlugin(),
// minifies your code
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
},
});
Oh, and don't forget to remove devtool: 'eval'
from a production config. Otherwise Uglify won't uglify anything at all.
The problem is that by default WebpackDevServer doesn't deal with HTML5 History correctly and the server won't route the url as it should. You can fix this issue by setting historyApiFallback: true
. Here's a full example:
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
var port = 4000;
var ip = '0.0.0.0';
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
historyApiFallback: true,
}).listen(port, ip, function(err) {
if (err) {
return console.log(err);
}
console.log('Listening at ' + ip + ':' + port);
});
After this you should be able to access your SPA via any url that has been defined in it.
The problem is that after hot module update some branches of React Tree differs from the previous versions. As result React-hot-loader will not update these branches at all, and you may lose internal components state.
The equality
of Components are defined as:
- They have same variable names in the same files. Ie they are both MyComponent from MyComponent.js
- They have same displayName and similar code.
Note: similar code is not equal code. RHL will stand some small changes in code, or even adding a new method in class.
Hot module replacement is a tricky thing. Just double check that you are not exporting anything else from the
modules with hot
exported components – functions, constants, anything NOT REACT.
hot
function setups module self-acceptance. And it may be a dangerous thing.
hot
function is not tested in these environments, yet. Please use old school
AppContainer and setup HRM manually.
React Hot Loader rely on a Babel transformation that register all exports in a global. That's why dependencies included in Webpack DLL will not work.
React-hot-loader found an Element without instrumentation due to a wrong configuration. To fix this issue - just require RHL before React.
Example of a wrong configuration:
import * as React from 'react';
import { hot } from 'react-hot-loader'; // React is not patched
Example of correct configurations:
import { hot } from 'react-hot-loader';
import * as React from 'react'; // React is now patched
import React from 'react';
import { hot } from 'react-hot-loader'; // React is now patched