logo

React Toolchain, NPM, Webpack, and Babel

In this tutorial, we will be setting up the React toolchain from scratch, exploring the configurations that are handled by Create-react-app. By doing this manually, we will have a better understanding of what happens under the hood.

NPM

Introduction to NPM NPM, short for Node Package Manager, is responsible for managing all the third-party libraries we use in our project. It is installed by default with NodeJS.

Initializing NPM and Webpack Navigate to your empty project directory using the terminal and run npm init -y to create a new package.json file with default settings.

To add Webpack to your project, run npm install --save-dev webpack webpack-cli. This will update the package.json file and include a new section called devDependencies.

Creating the Index File Under the src directory, create a new file called index.js. application structure

All we need to do now is run Webpack: npx webpack

A new folder (dist) is generated with one file main.js

Babel

Babel is a JavaScript compiler that enables you to write modern JavaScript code that can still run on older browsers. To use Babel, you need to install some dev dependencies by running npm install -save-dev @babel/core @babel/cli @babel/preset-env. The @babel/core and @babel/cli are necessary for compiling files, while @babel/preset-env is a smart preset that handles syntax transformation without requiring specific environment management. To view code transformation, run npx babel ./src/index.js --presets=@babel/preset-env.

Adding Babel to Webpack

At the begining, we need to add new dev dependency npm install -D babel-loader and update webpack.config.js file to include the following changes

module: {
  rules: [
    {
      test: /\.js$/,
      loader: "babel-loader",
      exclude: /node_modules/,
      options: {
        presets: ["@babel/preset-env"],
      },
    },
  ]
}

Now when we run Webpack, it will bundle our transformed code.

Adding React preset

Now, let's transform our project to ReactJS by installing the following dependencies npm install -save react react-dom and add two new files:

App.js

import React from "react";

class App extends React.Component {
  render() {
    return <div>This is App Component</div>;
  }
}

export default App;

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));

Once we run Webpack we will get a syntax error saying that it is unable to tranform (JSX syntax) to normal JavaScript.

To solve this issue, we need to add a new preset for React npm i -D @babel/preset-react and update webpack.config.js file

module: {
  rules: [
    {
      test: /\.js$/,
      loader: "babel-loader",
      exclude: /node_modules/,
      options: {
        presets: ["@babel/preset-env", "@babel/preset-react"],
      },
    },
  ]
}

Adding HTML Loader

To auto-generate HTML file with the latest bundle we need to add new Depenecey npm i -D html-webpack-plugin and modify webpack.config.js file by adding new plugin as follow:

const HtmlWebpackPlugin = require('html-webpack-plugin')

 plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],

Adding webpack-dev-server

Webpack-dev-server will provide live reloading to our application. First install webpack-dev-server by npm i -D webpack-dev-server. And run npx webpack-dev-server. to customize Running port add devServer to Webpack configuration

devServer: {
  port: 3000,
},

Adding CSS loader

To load CSS files into JavaScript using Webpack and Babel we need a special presets for that npm i -D css-loader style-loader

Update Webpack configuration file by adding new rule under the modules section

{
   test: /\.css$/,
   use: ["style-loader", "css-loader"],
   exclude: /node_modules/,
},

Adding Babel Plugins

Now, change App.js file to the following:

import React from 'react'

class App extends React.Component {
  state = {
    count: 0
  }

  render() {
    return (
      <div>
        <h1>Hello World!</h1>
        <h2>Count: {this.state.count}</h2>
        <button onClick={() => this.setState(state => ({count: state.count + 1}))}>+</button>
        <button onClick={() => this.setState(state => ({count: state.count - 1}))}>-</button>
      </div>
    )
  }
}

export default App

Bable will now give us a new syntax error because defining a state outside constructor is not supported by javascript doesn't support such syntax. We need to add a new plugin to Babel ( Before we added html-webpack-plugin as Webpack plugin). Install npm i -D @babel/plugin-proposal-class-properties, and now we need to update Webpack configuration as following:

const path = require("path");
const webpack = require("webpack");

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.js",
  devServer: {
    port: 3000,
  },
  devtool: "source-map",
  output: {
    path: path.join(__dirname, "build"),
    filename: "bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-env", "@babel/preset-react"],
          plugins: ["@babel/plugin-proposal-class-properties"],
        },
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};