Skip to content

Instantly share code, notes, and snippets.

@imdongchen
Created September 22, 2017 23:52
Show Gist options
  • Save imdongchen/f85758d873fd686325017674a2f22889 to your computer and use it in GitHub Desktop.
Save imdongchen/f85758d873fd686325017674a2f22889 to your computer and use it in GitHub Desktop.

Enabling hot reload in React web app

Hot reload and its benefits

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.

Roles of tools in webpack HMR

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

https://gist.github.com/f90dd3fc0c2556e40537cfdf7392c7a6

  1. 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

https://gist.github.com/0ded5f84bdc024bf58066e7b0ffa4e62

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

https://gist.github.com/68dc749688f6181ade32ebd5ecc77194

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:

https://gist.github.com/e1388b00eaab388a9037bdaed61d588e

  1. 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:

https://gist.github.com/e7f1da88d9082b3ee2dd4160cd3005f8

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

https://gist.github.com/26bd176f194429d17721297c27b0c63c

  1. 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:

https://gist.github.com/8c9e41e1e560cbfcfef0996529e4f057

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

https://gist.github.com/61764a690f7354a290afaab4dc32f839

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 https://gist.github.com/63c98d43c52925881cc9714d3fb6efa6

Mount webpack middleware to serve hot chunks

https://gist.github.com/2ee67141e6d9712ef473bd165a2a9932

And finally to implement hot reload for react

https://gist.github.com/617883f6860a49a38d435543de25349e

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

https://gist.github.com/b4c8e80ae5ce537d1f9b7aec63277bb7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment