React Hot Loader with Web Dev Server
Tags: react, javascript, webpack
Published: 2020-07-08 07:10:37

We’ll build a counter app to show hot module reloading while maintaining state using webpack-dev-server or express to update the modules

### React Hot Loader with Web Dev Server

#### Create Project

```
proj/
├─ dist/
├─ .babelrc
├─ package.json
├─ webpack.config.js
└─ src/
    └─ assets/
        └─ index.html
        └─ css/
        └─ js/
        └─ img/
        └─ fonts/
    └─ components/
    └─ pages/
    └─ services/ 
    └─ App.js
    └─ index.js
```

#### Initialise Project Folder
```
npm init -y
```
#### Install Development Dependencies
```
npm i -D \
webpack-dev-server \
webpack \
webpack-cli \ 
babel-loader \ 
@babel/core \
@babel/preset-env \
@babel/preset-react \
html-webpack-plugin 
```

#### Include .babelrc file to configure babel compilation for this project

```json
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}
```
#### Install Application Dependencies
```
npm i -S react react-dom react-hot-loader
```

#### Create src/assets/index.html

```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="/css/main.css">
</head>

<body>
    <div id="root"></div>
</body>

</html>
```
#### Create the react application with react-hot-loader
```js
import { hot } from 'react-hot-loader/root';
import React from 'react';
const App = () => {
    const [counter, setCounter] = React.useState(0)
    const [data, setData] = React.useState([])

    async function getData() {
        let res = await fetch("https://jsonplaceholder.typicode.com/todos");
        let jsonData = await res.json();
        setData(jsonData)
    }

    function increment() {
        setCounter(counter + 1)
    }

    return (
        <>
            <div>{`Awesome Counter:  ${counter}`}</div>
            <button onClick={increment}>Increment Now</button>
            <button onClick={getData}>Get API Data</button>
            <table border={1}>
                <thead>
                    <tr>
                        <th>UserId</th>
                        <th>Id</th>
                        <th>Title</th>
                        <th>Completed</th>
                    </tr>

                </thead>
                <tbody>
                    {data.map((item, i) => {
                        return (
                            <tr key={i}>
                                <td>{item.userId}</td>
                                <td>{item.id}</td>
                                <td>{item.title}</td>
                                <td>{item.completed}</td>
                            </tr>
                        )
                    })}
                </tbody>
            </table>
        </>
    );
}
export default hot(App);
```
```js
import React from "react";
import { render } from "react-dom";
import App from './App'
render(<App />, document.getElementById("root"));
```

#### Configure webpack through a webpack.config.js file

```js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
const path = require("path");

module.exports = {
    devtool: "source-map",
    mode: "development",
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.json']
    },
    module: {
        rules: [
            {
                test: /\.(js)x?$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader'
                },
            },
            {
                test: /\.(ts)x?$/,
                exclude: /node_modules/,
                use: {
                    loader: 'ts-loader'
                },
            },
            {
                // Preprocess your sass and scss files

                test: /\.s[ac]ss$/i,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader',
                ],
            },
            {
                // Preprocess your css files
                test: /\.css$/,
                exclude: /node_modules/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            }
        ]
    },
    devServer: {
        port: 4000,
        open: true,
        compress: true, //Enable gzip compression for everything served
        historyApiFallback: true,  //fallback to index.html in the event that a requested resource cannot be found.
        hot: true //Enable webpack's Hot Module Replacement feature
    },

    output: {
        filename: "js/main.[hash].js",
        publicPath: "/"
    },

    plugins: [
        new HtmlWebpackPlugin({
            title: "WebDevServer",
            filename: 'index.html',
            template: 'src/assets/index.html'
        }),
        new CopyPlugin({
            patterns: [
                { from: 'src/assets', to: '.' }
            ],
        }),

    ]
};
```

#### Add a “dev” and “build” script to the package.json
```json
...
"scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
},
...
```

When you run "npm run dev", webpack writes the project to memory and any further updates are pushed to memory without losing state.

When you run "npm run build", webpack compiles and writes the project to disk under the “dist” folder.