logo

Setting up React Toolchain Manually - A Guide to Understanding NPM, Webpack, and Babel

In this tutorial, we will set up the React toolchain from scratch. Create-react-app does all of this for us. All these configurations can be shown when we eject react configuration. But it is worth to set up things manually to understand what is going under the hoods.

NPM

NPM stands for Node Package Manager. NPM manages all the third-party libraries that we will be using. NPM will be installed by default with NodeJS.

NPM & Webpack Initialization

First, let's navigate by terminal to our empty project directory. Now, run npm init -y This will create a new file called package.json with all default

To add Webpack to our project run npm install --save-dev webpack webpack-cli. The package.json file is updated as it includes a new section called devDependencies.

Create a new file called index.js under src directory. As following

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. It lets you write a modern JavaScript code that still works in older browsers.

First, we need to install some dev dependencies npm install -save-dev @babel/core @babel/cli @babel/preset-env both @babel/core and @babel/cli are required to compile files where @babel/preset-env is a smart preset used handle syntax transformation without doing micromanage for the environment.

To see code tranfromation 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",
    }),
  ],
};