Hot Module Replacement in Redux
Hot module replacement is one of the most useful features offered by Webpack. It allows all kinds of modules, including JSON, CSS, and JS files, to be updated at runtime without needing a full refresh.
In this article, Toptal Freelance JavaScript Developer Shaojiang Cai demonstrates how to use Hot Module Replacement in Redux.
Hot module replacement is one of the most useful features offered by Webpack. It allows all kinds of modules, including JSON, CSS, and JS files, to be updated at runtime without needing a full refresh.
In this article, Toptal Freelance JavaScript Developer Shaojiang Cai demonstrates how to use Hot Module Replacement in Redux.
Shaojiang Cai
Shaojiang is a veteran front-end developer, skilled in JavaScript technologies. He’s also a GitHub developer and StackOverflow reviewer.
Previously At
This is a minimal example of hot module replacement (or HMR) in a Redux application. The working demo code is hosted on GitHub. We only include those settings essential to support HMR, making you easy to apply HMR in your own Redux application.
If you cannot wait to apply HMR, jump to this section to set up HMR for your project within five minutes!
Run the Example
Get your hands dirty first! Before you run the commands to start this example application, please ensure that Git, Node.js, and Yarn are installed correctly on your machine.
$ git clone https://github.com/Front-end-io/articles.git
$ cd articles && git checkout redux-hmr
$ yarn install
$ yarn start
Then visit http://localhost:3000/ to see if it works.
Upon writing your code, hot module replacement is able to update the page without a full refresh. More importantly, the Redux state is kept while other resources have been updated in place.
Hot Module Replacement
Hot module replacement is one of the most useful features offered by Webpack. It allows all kinds of modules, including JSON, CSS, and JS files, to be updated at runtime without needing a full refresh.
Here is how it works internally:
- The application asks the HMR runtime to check for updates.
- The runtime asynchronously downloads the updates and notifies the application.
- The application then asks the runtime to apply the updates.
- The runtime synchronously applies the updates.
HMR boosts productivity when developing a Redux application. Redux is a predictable state container for JavaScript apps. It’s a very popular state-of-art framework based on React. Redux, by definition of the first principle of Redux, is a singular shared data store, described by its documentation as a “Single source of truth.” The data store (a plain JavaScript object updated by reducers
) will be updated as the user operates on the application. Every user operation, such as clicking a button, loading back-end data, etc., will likely update the store multiple times. It’s not easy to fix a bug when the bug happens only with a particular snapshot of the state.
HMR allows us to update the page without re-initializing the global store. During Redux development, we may want to inspect the store after a series of operations. A very common scenario is, a bug occurs only after we have added a particular (maybe complex) item to the store. Without HMR, we have to do the following steps:
- Modify the code that potentially causes the bug.
- Refresh the page, add the particular item to the store.
- If the bugs persist, repeat Step 1.
The above iteration will be repeated again and again if the bug is difficult to find. In the real world, the bug may only appear after even more operations. HMR helps us to compile and apply the modified code while keeping the current store value unchanged. We do not need to repeat Step 2. It boosts the efficiency of development.
Feature in This Example
We want to keep the feature minimal, just to demonstrate the HMR capability. So in this application, we do not incorporate common features in a React application, including redux-logger, react-router-redux, redux-thunk, redux-devtools, etc. Meanwhile, we keep only one reducer, two actions, and 1 page.
Our application keeps only a counter value in the store. We have only one page called home, which displays the counter value and two buttons to increase/decrease the counter value.
To confirm that HMR works, simply increase/decrease the counter multiple times, then modify some code. For example, modify the title Counter to Counter in store. Then we will find that:
- The page is not refreshed.
- The displayed counter value is NOT CHANGED.
- The title has been changed to Counter in store.
Set Up HMR in Five Minutes
To set up HMR, follow these steps.
Essential Libraries
These libraries must be installed to support HMR:
- react-hot-loader@^4.2.0: Compile and update the React application in real time.
- webpack-dev-server@^3.1.4: Serves a Webpack app. Updates the browser on changes.
ES6
If you are using ECMAScript6 (Who isn’t, these days?), you need some more tools to compile ES6 in real time. First, this is the minimal ES6 config file .babelrc:
{
"env": {
"development": {
"presets": [
"react-hmre"
]
}
}
}
To support real-time compilation, this library is needed:
Webpack.config.js
We need to configure HMR in the Webpack configuration file webpack.config.js.
Firstly, enable the HMR plugin in the plugins section:
"plugins": [
…
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
]
The HMR plugin generates a Manifest, a JSON file listing the updated modules, and an Update, a JSON file containing the data to be applied. What to be noted is, HMR is an option provided by Webpack. Loaders like style-loader, which implement the HMR interface, receive an update through HMR and then replace the old code with the new code.
If we are using webpack-dev-server, then we need to turn on the hot flag in the devServer section:
"devServer": [
...
hot: true,
]
Hot Reload the Redux Reducers
Starting from Redux version 2.0.0, the reducers are not hot reloaded implicitly because the implicit hot reloading causes some problems. If your Redux state is reset to initial values when hot updated, try to enable hot update for the reducers:
import { createStore } from 'redux';
import rootReducer from '../reducers/index';
export default function configureStore(initialState) {
const store = createStore(rootReducer, initialState);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers/index');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
Advanced Settings
For more advanced settings of HMR, please refer to the HMR API.
Run
Finally, please run the application with:
$ ./node_modules/.bin/webpack-dashboard -- webpack-dev-server
Troubleshooting
HMR Simply Does Not Apply the Changes
HMR may fail silently without any warnings. When you update the code and save, the page simply does not update at all. This is probably because your system does not allow you to watch so many file changes.
On Ubuntu, you can run sysctl -a | grep inotify
to view the current user.max_inotify_watches
value. Try to increase this number by running: sudo sysctl fs.inotify.max_user_watches=524288
. Alternatively, append a new line fs.inotify.max_user_watches=524288
to file sudo vim /etc/sysctl.conf
and then run sudo sysctl -p /etc/sysctl.conf
to apply the change.
Understanding the basics
What is the Redux framework?
Redux is a JavaScript library used for managing application states by implementing predictable state containers. It is used to build user interfaces in a stable and consistent way.
What is hot loading?
Hot loading or hot swapping is the action of updating the application code while the application is running without reinitializing the application.