How to Set up a React App from Scratch

Uses Webpack, Babel, React

Why not just use Create-React-App?

Modern tools like create-react-app are great for beginners to get quickly into developing a React app. It is an environment that comes with all the tools needed to learn developing a single page application. Since most of the configurations are included for the developer, it is impossible to know what is going on behind the scenes. This tutorial's main goal is to introduce the reader with the tools needed to create a React app and serve it on a development server.

Getting Started

Let's create a project folder for our application.

$ mkdir react-app
$ cd react-app

Once in the directory let's initialize a project with npm.

$ npm init -y
  • The -y option generates an npm project without asking any questions. Running the ls command will output the contents of our directory, and we see that there is a package.json file that npm has created for us. For more information, on that check out the docs.

Install React and React-DOM

In order to create a React app, we need to install the react package which contains only the functionality necessary to define React components. It is typically used together with a React renderer like react-dom for the web. Go ahead and execute the following commands to install these two packages from npm.

$ npm install react react-dom

Let's look at our package.json file again. Here is what the contents of the file should be.

/package.json
{
  "name": "react-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^16.13.1",
    "react-dom": "^16.13.1"
  }
}

As you can see, we have react and react-dom included in our dependencies.

Installing Webpack

Webpack is a static module bundler for moder Javascript applications. What this means is Webpack allows you to use Javascript modules which it then bundles all into an output file. One of the problems that Webpack solves is that it manages dependencies for us and then includes a single import file to our HTML page. Without it we would have to write individual script tags to include all of our Javascript files in our HTML page. This also saves the browser from making multiple requests for our resources, and just requests the ouput from Webpack. It will connect for you once you see Webpack in action.

In order to use Webpack, we will first need to install the following packages.

$ npm install webpack webpack-cli --save-dev

This command installs webpack and webpack-cli, and saves it in our package.json file as dev dependencies. For now, we don't need to create a configuration file for Webpack.

Prior to Webpack 4, it was a requirement to have a webpack.config.js file in the main directory of a web app. Since version 4, it is optional to have a configuration file. We will see shortly that creating the configuration file is useful for many reasons.

Finally, let's add a webpack command inside our package.jsonfile inside scripts.

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

Installing Babel and required Plugins

In order to work with modern javascript features, we need Babel to transpile our modern javascript into a syntax that older browsers can understand. In order to get a glimpse of how Babel transpiles our javascript code you can visit https://babeljs.io/en/repl, and write a modern javascript snippet on the left side and see live the way that Babel transpiles our code on the right side of the screen.

For our purposes, we need Webpack to talk to Babel, and that is done through a loader called babel-loader. We also need Babel presets in particular the following two presets :

  • babel preset env - used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript.

  • babel preset react - For converting JSX into regular Javascript.

Go ahead and install these dependencies:

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

Now we need to configure Babel. Create a .babelrc file in the main directory of your project, and add the following lines to the file.

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

This tells Babel, which presets we will be using for transforming our code.

Setting up a Git Repository

At this point it is a good idea to include a version control system to our project. I will be using Git to do that. Here is a cheatsheet if you need to brush up your knowledge on Git.

Before setting up a Git repository let's create a .gitignorefile. This file is a plain text file where each line contains a pattern for files/directories to ignore. Generally, this is placed in the root folder of the repository, and that's what I recommend. However, you can put it in any folder in the repository and you can also have multiple .gitignore files. After creating the file add the following lines to it.

node_modules
dist

We can now initialize our Git repository. For that, run the following commands in order.

$ git init
$ git add .
$ git commit -m "Initial Commit"

Configure Webpack

We are ready to configure Webpack in order for it to do its magic. Let's create a file named webpack.config.js in our main directory and include the following code inside the file.

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

The above tells Webpack to go through our source files, and for every file with extension .js or .jsx pipe the code with the use of babel-loader to Babel, so it can transform our code. Observe that, we exclude the node_modules folder for obvious reasons.

Writing Javascript Source Code

At this point, we are ready to write our first Javascript code. There is many ways to structure our app, but I prefer creating a srcdirectory and keeping the source code there. Inside our srcfolder let's create a componentsfolder to store our first React component there.

$ mkdir src
$ cd src
$ mkdir components
$ cd components
$ touch SimpleComponent.jsx

Create the first component inside SimpleComponent.jsx . First we will import React and create a functional component that returns a divwith a certain text in it. Here is how that code looks like.

/src/components/SimpleComponent.jsx
import React from 'react';

const SimpleComponent = () => {
    return (<div> Hello, this is React </div>);
}

export default SimpleComponent;

We export the component and should import it in the entry point of our app. Webpack will assume the entry point is in src/index.jsby default, and we will not change that convention. So let's go back a directory, to inside the srcdirectory and create a new file index.js.

$ cd ..
$ touch index.js

Inside our entry point we need to import the React component from /src/components/SimpleComponent.jsxHere is how that looks.

/src/index.js
import SimpleComponent from './components/SimpleComponent.jsx';

At this point we are ready to tell Webpack to build our bundle. This is called the output produced by Webpack. By default Webpack will create a /dist/main.jsin our main directory. We can change that inside webpack.config.jsif we so desire. Go ahead and tell Webpack to create the first bundle with the following command.

$ npm run build

If you have done everything as described so far, you should see the main.js bundle created by Webpack. At this point our project structure looks as follows.

Here Comes the HTML

At this point you might wonder why haven't we created an HTML file yet. I chose to structure the tutorial in this way, to show that Webpack by itself, does not have anything to do with HTML. All it does is, given an entry point Javascript file, it will take the file, recursively find all the dependencies of our /src/index.jsentry point file, bundle all this code together, and output it in a single file, in our case /dist/main.js. We can then take this file and include it in an HTML file with the help of <script>tag. However there is another approach, which I will take in this tutorial.

You should not manually include the bundled output to your HTML file. We can tell Webpack to do this for us. The reason that this approach is encouraged is due to the fact that sometimes we won't know ahead of time what the file name of Webpack's output will be. This is especially useful for webpack bundles that include a hash in the filename which changes after every compilation. The latter is useful for caching purposes.

Running the following command will install the HtmlWebpackPlugin.

$ npm install html-webpack-plugin --save-dev

Now, modify the Webpack configuration file as shown below.

/webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

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

    plugins: [new HtmlWebpackPlugin()]
};

And finally, run the command:

$ npm run build

Go to the /distfolder created by Webpack, and you will now see an index.htmlcreated by Webpack. This HTML file, has been linked to the bundled main.jsfile for us. Here is the contents of the autogenerated file /dist/index.html.

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
</head>

<body>
    <script src="main.js"></script>
</body>

</html>

However as it stands, this is not what we want. The dist/index.htmlfile that was created is not meaningful. It does connect to our dist/main.js, however if we open the HTML file in the browser we will see that it is blank. We will fix that in the next section.

React-DOM Render

So far in our /src/index.jsfile we have only been using React components without rendering them to a DOM. Let's create an index.htmlinside the srcfolder. Note that this is different than the autogenerated index.htmlinside the distfolder. In fact, later we will tell Webpack to use the /src/index.htmlas a template for generating the /dist/index.html. Assuming that we are in the main directory of our project go ahead and execute the following commands.

$ cd src/
$ touch index.html

Now copy and paste the following code into your /src/index.htmlfile.

/src/index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React App From Scratch</title>
</head>

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

</html>

The above is a simple HTML file with a single divwith an id of "root". This is where we will tell React to render our components. To do that, open the index.js from inside the /srcfolder and copy and paste the following code in there.

/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

import SimpleComponent from './components/SimpleComponent.jsx';

ReactDOM.render(<SimpleComponent />, document.getElementById('root'));

HTML Loader

We are almost done.The final step is to tell Webpack to use the /src/index.htmlas a template for creating the /dist/index.html. Before doing that, we need to tell Webpack, how to load .htmlfiles. We do this by the help of another loader called: html-loader. Navigate to the main folder of our app. Then run:

$ npm install --save-dev html-loader

As we did with babel-loaderwe need to alter the webpack.config.js, to use html-loader for processing files with extension .html.

/webpack.config.js

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

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

    plugins: [new HtmlWebpackPlugin()]
};

Finally, we include one more change in the above config file, to have webpack to use /src/index.htmlas a template for building the /dist/index.html.

/webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

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

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

Now go ahead and open the /dist/index.html file that Webpack has generated for us. The code looks as shown below.

/dist/index.html
<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>React App From Scratch</title>
</head>

<body>
    <div id="root"></div>
    <script src="main.js"></script>
</body>

</html>

And opening the above file in the browser with the file:// protocol, will greet us with the following page.

I hope the tutorial was useful for you. If you have any suggestions feel free to contact me at levon.tumanyan@yahoo.ca.

Sources

Last updated