Webpack with Hot Module Replacement
This article will teach you to use webpack feature "Hot Module Replacement". Without reloading the browser HMR can change the old module with the newer ones
Hello everyone, In previous article (Get up and running with webpack and react) we learnt about webpack and how to setup react app with webpack. Now we are going to dive into the next feature of webpack called Hot Module Replacement.
What is Hot Module Replacement?
Webpack has this amazing feature called Hot Module Replacement. It helps to change the old modules with the newer ones without reloading the browser.
You may be using it already but may not know exactly how it works. So in this article, I'll go over how it works.
Some things you have to note about HMR are as follows:
- HMR is one of optional features of webpack and needs to be turned ON explicitly.
- You need to use Webpack via webpack-dev-server to use HMR.
- It can only work with loaders that implement and understand HMR. Like ‘style-loader’, ‘react-hot-loader’ etc.
- It should only be used for development because webpack-dev-server is development server.
A Deeper Look with Code
First we have to install react-hot-loader
npm install react-hot-loader
Add react-hot-loader into your .babelrc file.
Put below line into your .babelrc file
{
...
"plugins": ["react-hot-loader/babel"]
}
Make your root component as hot-exported.
Create file App.js
touch src/App.js
Now add below code into App.js file
import React from "react";
import { hot } from "react-hot-loader";
const App = () => <h1>Hello ReactJs</h1>;
export default hot(module)(App);
And your index.js file
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
You have to add below line into your package.json file
"scripts":{
"dev":"webpack-dev-server --hot"
}
Use hot-loader react-dom:
@hot-loader/react-dom replaces the “react-dom” package the same version, but with additional patches to support hot reloading.
npm install @hot-loader/react-dom --save-dev
Use alias into your webpack.config.js file. So add below code into your webpack.config.js file:
resolve: {
alias: {
'react-dom': '@hot-loader/react-dom'
}
}
So, now your .babelrc file look like:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3,
"proposals": true
}
}
],
"@babel/preset-react"
],
"plugins": [
"react-hot-loader/babel",
"@babel/plugin-proposal-class-properties"
]
}
So, your Webpack.config.js file look like:
const webpack = require('webpack');
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const Dotenv = require("dotenv-webpack");
module.exports = {
//Entry Point
entry: {
app: "./src/index.js"
},
//Output
output: {
path: path.resolve(__dirname + "/dist"),
filename: "app.bundle.js",
publicPath: "/"
},
resolve: {
alias: {
"react-dom": "@hot-loader/react-dom"
}
},
//webpack dev server
devServer: {
compress: true,
port: 3000,
stats: "errors-only",
open: true
},
//Loader
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"]
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
}
][("css-loader", "sass-loader")]
},
{
// For images
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
//Using File-loader for these files
loader: "file-loader",
/*In options we can set different things like format
and directory to save*/
options: {
outputPath: "images"
}
}
]
},
{
//For fonts
test: /\.(woff|woff2|ttf|otf|eot)$/,
use: [
{
//using file-loader too
loader: "file-loader",
options: {
outputPath: "fonts"
}
}
]
},
{
test: /\.html$/,
use: "html-loader"
}
]
},
//plugin
plugins: [
new Dotenv(),
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "app.css",
disable: false,
allChunks: true
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ["dist"]
}),
]
};
So, your package.json file look like:
{
"name": "react_webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --hot",
"build": "webpack --mode production"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/preset-env": "^7.7.1",
"@babel/preset-react": "^7.7.0",
"@hot-loader/react-dom": "^16.11.0",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"file-loader": "^4.3.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
},
"dependencies": {
"dotenv-webpack": "^1.7.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.12.18"
}
}
If You are new to Webpack then you must have to read our first article.