DEV Community

Paul Allies
Paul Allies

Posted on

React Hot Loader with Web Dev Server

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
Enter fullscreen mode Exit fullscreen mode

Initialise Project Folder

npm init -y
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Include .babelrc file to configure babel compilation for this project

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}
Enter fullscreen mode Exit fullscreen mode

Install Application Dependencies

npm i -S react react-dom react-hot-loader
Enter fullscreen mode Exit fullscreen mode

Create src/assets/index.html

<!DOCTYPE html>
<html>

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

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

</html>
Enter fullscreen mode Exit fullscreen mode

Create the react application with react-hot-loader

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);
Enter fullscreen mode Exit fullscreen mode
import React from "react";
import { render } from "react-dom";
import App from './App'
render(<App />, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

Configure webpack through a webpack.config.js file

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: '.' }
            ],
        }),

    ]
};
Enter fullscreen mode Exit fullscreen mode

Add a “dev” and “build” script to the package.json

...
"scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
},
...
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)