Enabling hot reload in React web app

Dong Chen
4 min readSep 23, 2017

Hot reload allows developers to see result of code change in browser without page refresh. This greatly improves developer productivity and experience, especially when the changing feature is multiple steps away from the launch screen. For example, I was working on a feature at the end of a use flow. Every time a single bit of code changes, I have to refresh page and click through all the steps in the flow to check my change. With hot reload, the app state is preserved and shows the change at the spot. This is really helpful in react apps as we can change component without losing its state.

Tools available

This is the most confusing part as I looked into the problem. Since Javascript technology is evolving super rapidly, many tools have come and gone yet tutorials about these tools still exist; multiple tools may be developed around the same time for the same problem; no single best practice exists; and all too often, documentation is not complete. For example, a quick search shows the following tools all related to hot reload:

To understand the role of these tools and how they should be configured in our app, I feel it important to understand how hot reload works. The solution with webpack is called hot module replacement (HMR).

How webpack HMR works

The graph from Raja Rao DV’s article is really helpful in understanding the whole process in more details. On a high level, there are four phases in HMR:

  1. Generate hot chunks. When a file changes, hot chunks must be generated that contain the changed part.
  2. Serve hot chunks. The generated chunks must be served by some server.
  3. Fetch hot chunks. The web page in browser must be connected with server via WebSocket so that it can be notified that new hot chunks are available. The client then fetches the chunks.
  4. Implement hot chunks. The client side then needs to decide what to do with the update chunks.

Configuring tools for webpack HMR

  1. Generate hot chunks. webpack and webpack.HotModuleReplacementPlugin generate hot chunks. So in webpack.config.js we need to add:

2. Serve hot chunks. webpack-dev-server is the out-of-box solution to serve files emitted from webpack. It is an express node server using webpack-dev-middleware under the hood. You can run it through CLI directly

Here, the option --hot is actually telling webpack-dev-server to serve hot chunks. The option --inline is actually doing the third step: injecting code into client to stay communicated and fetch hot chunks.

You can also configure through webpack.config.js

You can read more about using webpack-dev-server here.

However, webpack-dev-server becomes tricky when you have your own node server for your web application. In that case you have to run two servers, and proxy api calls to webpack-dev-server to your own node server (read this for more details).

An alternative is to use webpack-dev-middleware directly in your node server. This uses your existing node server to serve the files emitted from webpack. You also need webpack-hot-middleware to enable hot reload. Just use them like normal middleware:

3. Fetch hot chunks. We need to inject websocket client code into the app. With webpack-dev-server CLI solution, we don’t need to do anything. The option --inline already help inject the code. If it is configured via webpack.config.js, add in the configuration file:

With webpack-dev-middleware and webpack-hot-middleware solution, add this to webpack.config.js

4. Implement hot chunks. Up to now the client actually already gets the new chunks of code, thanks to the awesome webpack. What to do then with the new chunks is actually out of the scope of webpack. Webpack HMR has API module.hot.accept(“./someFileName”, callbackToRunWhenThatFileIsRecompiled) that provides a callback to developers after update file is accepted. We can manually implement those callbacks, or use some existing tools. For example, style-loader implements that API internally and thus allow css hot reload. Efforts like react-hot-loader and react-transform all do the same thing, in an attempt to hot reload react components. It just becomes more complex when trying to preserve react component state.

Dan Abramov well explains the challenges with react hot reload in his article. In fact, we can actually implement hot chunks without any tools:

And we can implement hot chunks for redux with plain webpack HMR:

This will replace redux (without changing the store state) and re-render the root component (thus all components it includes). See more discussions on using vanilla HMR API here.

However, a problem is that the NextApp is actually not the same component as App ; so whenever code changes, react unmounts the old component. This causes the loss of component internal state (although the external store state is preserved).

react-hot-loader and react-transform are two different attempts made by Dan Abramov. Each solves different problems, but neither is perfect. The upcoming react-hot-loader v3 looks promising, and is intended to replace the other two. It is currently in beta. To use react-hot-loader v3, follow their instruction. I also refer to this in implementing the module.hot.accept callback.

Summary

In summary, this is what my configuration looks like to enable hot reload.

Webpack configuration:

Mount webpack middleware to serve hot chunks:

And finally to implement hot reload for react:

Babel configuration (required by react-hot-loader v3)

--

--

Dong Chen

Web engineer @robinhood; PhD in Human-Computer Interaction