Tutorial

How To Set Up React Using Webpack 4 and Babel 7

Published on December 12, 2019
author

Ojini Chizoba Jude

How To Set Up React Using Webpack 4 and Babel 7

Introduction

A common way to learn React is to use create-react-app, which is a lightweight way to bootstrap any React project. But in order to achieve a particular purpose, it is sometimes necessary to configure your application from scratch. In this tutorial, we will be setting up React using Webpack and Babel.

Step 1 — Setting Up the Project

Before you can get started, make sure to have an installed editor and terminal on your machine. In addition, you will need an installed version of Node.js with npm. Make sure to have everything set up before you continue to read.

Before we start writing any code, let’s create a new directory where our project will stay. In any location on your computer, run the following in your terminal:

  1. mkdir webpack-babel-react-starter
  2. cd webpack-babel-react-starter

We need to initialize our project with a package.json file, since we are going to install some packages that are vital for the setup. Run the following:

  1. yarn init -y

Note: For this tutorial, we will be making use of yarn as our package manager. If you are using npm, make sure you run the corresponding command.

Step 2 — Setting up Webpack

Webpack is one of the most popular bundlers for web development. It internally builds a dependency graph when it processes your application. This graph maps every module your project needs and generates one or more bundles. Since version 4.0.0, webpack does not require a configuration file to bundle your project; nevertheless it is configurable to better fit your needs.

Let’s install it by running:

  1. yarn add webpack --dev

We also need to install the webpack CLI:

  1. yarn add webpack-cli --dev

After installing these two packages, you will notice a new addition to our project, the node_modules and devDependencies section in our package.json file.

Next thing to do is to add the webpack you just installed into the package.json file.

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

At this point you don’t need a configuration file to get started.

Step 3 — Setting up Babel

Modern JavaScript is written in ES6 or ES7, but not every browser understands this. Here we need babel to do the heavy lighting for us. Babel is a tool-chain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments. Checkout the Babel docs for more info about what they can do for you.

React components are mostly written in ES6, with the concept of imports, class, and other ES6+ features, which older browsers do not understand. Webpack on its own does not know how to transform or transpile the ES6 code to ES5 code. But it does have the concept of loaders: a webpack loader takes something like the input and produces something else as the output.

For our setup, we will use babel-loader, which is a webpack loader that will transpile our ES6 code for us. Before we start using babel-loader, we need to install some packages and set up the babel preset env, which will target the particular JavaScript version we want to transpile to.

Let’s install all the dependencies:

yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader --dev

We also need to set up our Babel config file, create a new file in the root directory called .babelrc, and write the following configuration to it:

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

This configuration will ensure that Babel transpiles our React code, which is JSX and any other ES6+ code we have to ES5 code.

Create a webpack.config.js file in the root directory and write the following configuration for it:

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

For every file with a .js or .jsx extension, excluding the node_modules folder and its content, Webpack uses babel-loader to transpile the ES6 code to ES5.

With this done, let’s head over to writing our React component.

Step 4 — Setting up React

We will be creating a React component that renders a text and a button, but in order to make use of React we need to install some dependencies: react and react-dom .

  1. yarn add react react-dom

After installing those, create a new folder in the root directory. Let’s call it src, and inside it create a index.js file.

In the index.js file, write the following code:

import React from "react";
import ReactDOM from "react-dom";

const Index = () => {
  return (
    <div className="full-screen">
      <div>
        <h1>
          React Page {" "}
        </h1>
        <br />
        <a
          className="button-line"
          href="https://github.com/deityhub"
          target="_blank"
        >
          Know more
        </a>
      </div>
    </div>
  );
};

export default Index;

It’s time to test things out. Open up your terminal once again and run:

yarn run build

You will see a dist folder created for us by Webpack, and inside it will be an index.js file, in which we have a minified version of our ES5 code. In our build script in package.json, we specified a --mode production flag after the webpack command; this makes Webpack generate a minified version of our ES5 code. To see a readable format of the transpiled code, you can swap the --mode production with --mode development.

The output shows that our code works, but we want our transpiled code to be visible in our browser. To do this, let’s set up HTML and CSS (SCSS) to work with Webpack.

Step 5 — Connecting React Component to the DOM

We need to set up an HTML file so that our React component can be rendered on the DOM. To achieve this, we need to install the package html-webpack-plugin:

  1. yarn add html-webpack-plugin --dev

Adjust your webpack.config.js file to look like this:

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

module.exports = {
  entry: path.join(__dirname, "src", "index.js"),
  output: {
    path: path.join(__dirname, "build"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: path.join(__dirname, "src", "index.html")
    })
  ]
};

We are adjusting the input and output so we have a bit more control over the naming and target of our files.

Next up is to create an HTML file inside the src folder; let’s call it index.html and then add the following code to it:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>React, Webpack, Babel Starter Pack</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <noscript> You need to enable JavaScript to run this app. </noscript>
    <!-- your react app will render here -->
    <div id="app"></div>
  </body>
</html>

Since we are in the src directory, let’s make some adjustments to our React component. First, create a new folder components, then inside this folder add two files app.js and app.scss. Make the following adjustments to our code.

In ./src/index.js:

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

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

In ./src/components/app.js

import React from "react";
import "./app.scss";

const App = () => {
  return (
    <div className="full-screen">
      <div>
        <h1>
          React Page {" "}
        </h1>
        <br />
        <a
          className="button-line"
          href="https://github.com/deityhub"
          target="_blank"
        >
          Know more now
        </a>
      </div>
    </div>
  );
};

export default App;

In ./src/components/app.scss:

body {
  background: linear-gradient(253deg, #0cc898, #1797d2, #864fe1);
  background-size: 300% 300%;
  -webkit-animation: Background 25s ease infinite;
  -moz-animation: Background 25s ease infinite;
  animation: Background 25s ease infinite;
}

.full-screen {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
//you need to setup file-loader in webpack before you can use images
  background: url("../../assests/image/background.png");
  background-size: cover;
  background-position: center;
  width: 100%;
  height: 100%;
  display: -webkit-flex;
  display: flex;
  -webkit-flex-direction: column;
  //_ works with row or column_

  flex-direction: column;
  -webkit-align-items: center;
  align-items: center;
  -webkit-justify-content: center;
  justify-content: center;
  text-align: center;
}

h1 {
  color: #fff;
  font-family: "Open Sans", sans-serif;
  font-weight: 800;
  font-size: 4em;
  letter-spacing: -2px;
  text-align: center;
  text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.6);

  &:after {
    display: block;
    color: #fff;
    letter-spacing: 1px;
    font-family: "Poiret One", sans-serif;
    content: "React project powered by webpack and babel with support for sass";
    font-size: 0.4em;
    text-align: center;
  }
}

.button-line {
  font-family: "Open Sans", sans-serif;
  text-transform: uppercase;
  letter-spacing: 2px;
  background: transparent;
  border: 1px solid #fff;
  color: #fff;
  text-align: center;
  font-size: 1.4em;
  opacity: 0.8;
  padding: 20px 40px;
  text-decoration: none;
  transition: all 0.5s ease;
  margin: 0 auto;
  display: block;

  &:hover {
    opacity: 1;
    background-color: #fff;
    color: grey;
  }
}

@-webkit-keyframes Background {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

@-moz-keyframes Background {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

@keyframes Background {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

We will be adding some styling in addition to the HTML and React component that we will render in the DOM. Before we run our code to test it, we need to configure our Webpack so it will know how to handle any .css or .scss file being passed through it.

  1. yarn add css-loader sass-loader mini-css-extract-plugin node-sass --dev

sass-loader being installed here is used by Webpack to convert our .scss to a .css file that the browser understands, and under the hood it makes use of node-sass to achieve this. Then mini-css-extract-plugin abstracts all our CSS files into a single CSS file, instead of the normal behavior that Webpack offers, which is to bundle your CSS file with the final .js output file, which then injects the CSS into your rendered HTML output when you run the code.

Open up your Webpack config file and adjust your code to look like this:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: path.join(__dirname, "src", "index.js"),
  output: {
    path: path.join(__dirname, "build"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.(css|scss)$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: path.join(__dirname, "src", "index.html")
    }),
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ]
};

Note: The order of your loaders in the Webpack config file matters, because Webpack processes the loaders from right to left. Using the test for CSS files, for example, will run sass-loader first, then css-loader, and finally MiniCssExtractPlugin.

Now let’s install webpack dev server. This will create a development server for us and monitor our files for any changes during development.

  1. yarn add webpack-dev-server --dev

Then open your package.json file and make the following adjustments in your scripts tag:

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

Let’s test our code by running yarn run dev.

Testing the code with

You will see something like this in your browser:

React project in the browser

Step 6 — Extending Features

Now, let’s add two more features to this project to demonstrate that you can extend or add more features when working on a more advanced React project than this.

Open your terminal and install these packages:

  1. yarn add file-loader @babel/plugin-proposal-class-properties --dev

file-loader will handle all the scenarios where we want to import an image or an SVG, while @babel/plugin-proposal-class-properties will handle the React class components and static class properties.

In webpack.config.js adjust it to look like this:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: path.join(__dirname, "src", "index.js"),
  output: {
    path: path.join(__dirname, "build"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.(css|scss)$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      },
      {
        test: /.(jpg|jpeg|png|gif|mp3|svg)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[path][name]-[hash:8].[ext]"
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: path.join(__dirname, "src", "index.html")
    }),
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ]
};

In .babelrc file, also adjust it to look like this:

{
  "presets": ["@babel/env", "@babel/react"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

Finally, run yarn run dev to make sure everything is stile working.

Conclusion

With this as a base for your React app, you can extend the configuration and build something from it. If you get stuck, check out the GitHub link to the complete code.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Ojini Chizoba Jude

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
2 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Excellent guide, thanks you! Now one question, how do I go about and deploy it to Digitalocean, using nginx? I have a built project with a setup almost identical to this but also using react-router. I know how to deploy it to Netlify/Heroku, but I want to use DigitalOcean with Ubuntu for this. Thanks!

This comment has been deleted

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Featured on Community

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more