Tutorial: How to set up React, webpack, and Babel 7 from scratch (2019)

You’re happy with create-react-app. But have you ever wondered how to set up React, webpack, and Babel from scratch? This tutorial has got you covered!

How to set up React, webpack 4, and Babel (2018)

How to set up React, Webpack, and Babel: what you will learn

In this tutorial you’ll learn:

  • how to install and configure webpack
  • how to install and configure Babel
  • how to install React
  • how to create two React components (Container / Presentational)
  • how to include the resulting bundle into an HTML page
  • how to install and configure webpack dev server

Enjoy the reading!

How to set up React, webpack, and Babel: setting up the project

Start off by creating a directory for the project:

mkdir webpack-react-tutorial && cd $_

Create a minimal directory structure for holding the code:

mkdir -p src

Inizialize the project by running:

npm init -y

and you’re good to go.

How to set up React, webpack, and Babel: setting up webpack

webpack it’s an incredibly powerful tool. While you can get by without touching a single line of configuration there will be a time for some custom setup of sort. Sooner or later you may want to learn webpack. Why not starting now?

Learning webpack is valuable not only for working with React but for configuring every frontend project.

webpack ingests raw React components for producing JavaScript code that (almost) every browser can understand.

Let’s install it by running:

npm i webpack --save-dev

You will also need webpack-cli. Pull it in with:

npm i webpack-cli --save-dev

Next up add the webpackcommand inside package.json:

"scripts": {
  "build": "webpack --mode production"
}

At this point there is no need to define a configuration file for webpack.

Older webpack’s version did automatically look for a configuration file.

Since version 4 that is no longer the case: you can start developing straigh away.

In the next section we’ll install and configure Babel for transpiling our code.

How to set up React, webpack, and Babel: setting up Babel

React components are mostly written in JavaScript ES6. ES6 is a nice improvement over the language but older browsers cannot understand the new syntax. Take the class keyword for example. Stateful React components are declared as classes (I guess it will be no longer the case sooner or later). So for getting ES6 to work in older browser we need some kind of transformation.

And that transformation is called transpiling. Webpack doesn’t know how to transform ES6 JavaScript to ES5 but it has this concept of loaders: think of them as of transformers. A webpack loader takes something as the input and produces something else as the output.

babel-loader is the Webpack loader responsible for taking in the ES6 code and making it understandable by the browser of choice.

Obsviusly babel-loader makes use of Babel. And Babel must be configured to use a bunch of presets:

  1. babel preset env for compiling Javascript ES6 code down to ES5 (please note that babel-preset-es2015 is now deprecated)
  2. babel preset react for compiling JSX and other stuff down to Javascript

Let’s pull in the dependencies with:

npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev

Don’t forget to configure Babel! Create a new file named .babelrc inside the project folder:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

At this point we’re ready to define a minimal webpack configuration.

Create a file named webpack.config.js and fill it like the following:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};

The configuration is quite simple.

For every file with a js or jsx extension Webpack pipes the code through babel-loader for transforming ES6 down to ES5.

With this in place we’re ready to write our React components.

Let’s head over the next section!

How to set up React, webpack, and Babel: writing React components

Let’s start with the right foot: we’ll create two React components following the Container / Presentational principle.

I suggest taking a look at container components and smart and dumb components by Dan Abramov for learning more. In brief, the Container / Presentational principle is a pattern for React components. The container component is the one that carries all the logic: functions for handling state changes, internal component state and so on.

In contrast a presentational component is merely used for displaying the intended markup. Presentational components are plain JavaScript functions receiving data from the container component as props.

You’ll see how they look like in the following example.

For this post’s scope I’d like to build a super simple React form with a single text input.

Before touching any code let’s pull in React by running:

npm i react react-dom

A question I get a lot is “should I install react and react-dom as dev dependencies or not?” It doesn’t matter for the final result. webpack will still produce a bundle with your JavaScript application. I have this bad habit of putting react and react-dom in devDependencies so you’ll find that style a lot in my tutorials.

Next up create a minimal directory structure for organizing the components:

mkdir -p src/js/components/{container,presentational}

Next up let’s create a container component that:

  • has its own state
  • renders an HTML form

Create the component:

touch src/js/components/container/FormContainer.jsx

The component will look like the following:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class FormContainer extends Component {
  constructor() {
    super();

    this.state = {
      title: ""
    };
  }

  render() {
    return (
      <form id="article-form">
      </form>
    );
  }
}

export default FormContainer;

The component does nothing at this moment. It’s just a skeleton for wrapping up child components. Let’s fix that.

Create the new component:

touch src/js/components/presentational/Input.jsx

Our first presentational React component will be a text input. We know that an HTML input takes the following attributes:

  • type
  • class
  • id
  • value
  • required

All of these will become props that the container component will pass down to its presentational child.

Since the input holds its own state we must be sure that React will take care of it. An HTML input becomes a controlled component in React.

Speaking of props, it is good practice to document your React components with Prop Types.

Install the package by running:

npm i prop-types --save-dev

Back to React, our presentational component for an HTML input will look like the following:

import React from "react";
import PropTypes from "prop-types";

const Input = ({ label, text, type, id, value, handleChange }) => (
  <div className="form-group">
    <label htmlFor={label}>{text}</label>
    <input
      type={type}
      className="form-control"
      id={id}
      value={value}
      onChange={handleChange}
      required
    />
  </div>
);

Input.propTypes = {
  label: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
  id: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  handleChange: PropTypes.func.isRequired
};

export default Input;

At this point we’re ready to update our container component to include the text input:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import Input from "../presentational/Input.jsx";

class FormContainer extends Component {
  constructor() {
    super();

    this.state = {
      seo_title: ""
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({ [event.target.id]: event.target.value });
  }

  render() {
    const { seo_title } = this.state;
    return (
      <form id="article-form">
        <Input
          text="SEO title"
          label="seo_title"
          type="text"
          id="seo_title"
          value={seo_title}
          handleChange={this.handleChange}
        />
      </form>
    );
  }
}

export default FormContainer;

And now it’s time to wire things up! webpack expects the entry point to be ./src/index.js. Create the file and place an import directive into it for requiring the container component:

import FormContainer from "./js/components/container/FormContainer.jsx";

With this in place we’re ready to create our bundle by running:

npm run build

Give Webpack a second and see the bundle come to life!

The bundle will be placed into

./dist/main.js

Now let’s bring our React experiment to life by including the bundle into an HTML page.

How to set up React, webpack, and Babel: the HTML webpack plugin

To display our React form we must tell Webpack to produce an HTML page. The resulting bundle will be placed inside a script tag.

Webpacks needs two additional components for processing HTML: html-webpack-plugin and html-loader.

Add the dependencies with:

npm i html-webpack-plugin html-loader --save-dev

Then update the webpack configuration:

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

module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader"
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: "./src/index.html",
      filename: "./index.html"
    })
  ]
};

Next up reate an HTML file into ./src/index.html (feel free to use whichever CSS library you prefer):

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" >
    <title>How to set up React, Webpack, and Babel</title>
</head>

<body>
    <div class="container">
        <div class="row mt-5">
            <div class="col-md-4 offset-md-1">
                <p>Create a new article</p>
                <div id="create-article-form">
                    <!-- form -->
                </div>

            </div>

        </div>
    </div>
</body>

</html>

One last thing is missing! We must tell our React component to hook itself into the id create-article-form

Open up ./src/js/components/container/FormContainer.jsx and add the following at the bottom of the file:

const wrapper = document.getElementById("create-article-form");
wrapper ? ReactDOM.render(<FormContainer />, wrapper) : false;

Close and save the file.

Now run the build again with:

npm run build

and take a look at the ./dist folder. You should see the resulting HTML.

With webpack there’s no need to include your Javascript inside the HTML file: the bundle will be automatically injected into the page.

Open up  ./dist/index.html in your browser: you should see the React form!

How to set up React, webpack, and Babel: webpack dev server

You don’t want to type npm run build every time you change a file.

It takes only 3 lines of configuration to have a development server up and running. Once configured webpack will launch your application inside a browser. Also, every time you save a file after a modification webpack wev server will automagically refresh the browser’s window.

To set up webpack dev server install the package with:

npm i webpack-dev-server --save-dev

Open up package.json to add the start script:

"scripts": {
  "start": "webpack-dev-server --open --mode development",
  "build": "webpack --mode production"
}

save and close the file.

Now, by running:

npm start

you should see webpack launching your application inside the browser.

Webpack Dev Server

Webpack Dev Server will automagically refresh the window upon every modification to a file!

How to set up React, webpack, and Babel: wrapping up

create-react-app is the way to go for starting off a new React SPA project. Almost everything is configured out of the box. But sooner or later you may want to extend or tweak webpack a bit.

And if you learn how to set up React, webpack, and Babel by hand you’ll be able to scratch your own itch, or even configure a frontend project from zero.

This knowledge is also valuable for situations where you don’t need a full blown SPA but you still want to build and distributed your ES6 code. By combining webpack and Babel it is possible to transform a bunch of React components into a bundle suitable for being distributed.

In the above guide we’ve seen:

  • how to install and configure webpack
  • how to install and configure Babel
  • how to install React
  • how to create two React components with the Container / Presentational principle
  • how to include the resulting bundle into an HTML page
  • how to install and configure webpack dev server

By the end you should be able to start from scratch with React, webpack and Babel.

For learning more about webpack check out webpack 4 tutorial, from zero conf to production mode.

And if you want to challenge yourself check out my React Redux Tutorial for Beginners: it builds on this webpack/babel foundation.

Thanks for reading and stay tuned!