Set up React Toolchain from the Ground up
Tags: react, webpack, babel
Published: 2018-09-18 16:00:33

---
title: Set up React Toolchain from the Ground up
published: true
description: Setting up a React application is a unsettling challenge. Facebook gives us a boilerplate to get started immediately create-react-app it uses Babel and webpack under the hood, but you don't need to know anything about them.
tags: react, webpack, babel
cover_image: https://thepracticaldev.s3.amazonaws.com/i/4ew2qb0mv1em3809irh3.png
---

This guide is designed for those who want to get their hands dirty to get up and running with a React application from scratch with no preconfigured environment, or hidden magic behind the scenes, or at least have some idea of what’s going on under the hood. To get the most out of this guide I highly encourage you to follow along step by step.

The puzzle
----------

A React application build typically is a set of tools that is used to perform a complex tasks, and its consists of three main tools: **Package manager** [Yarn](https://yarnpkg.com/en/) or [Npm](https://www.npmjs.com/), **Bundler** [webpack](https://webpack.js.org/) or [Parcel](https://parceljs.org/), and a **Compiler** such as [Babel](https://babeljs.io/) (new JavaScript features).

Prerequisites
-------------

*   Node version: >= 8.0.0
*   Package manager [Yarn](https://yarnpkg.com/en/docs/install)

> 📌 Snippets below uses `$` to represent a shell prompt in a UNIX-like OS, though it may have been customized to appear differently.

Creating a project directory
----------------------------

```shell
$ mkdir app && cd $_
$ yarn init -y
```

The commands above is pretty straightforward as you can see; it does three things:

*   Creates a new “app” folder within the current directory,
    *   then it changes the current working directory into our recently created project (second statement execution).
*   Initializing yarn as our package manager (interactively create a package.json file). The flag `-y` (or `--yes`) generates a package.json based on your [defaults](https://yarnpkg.com/en/docs/cli/init#toc-setting-defaults-for-yarn-init)

Project directory structure
---------------------------

Before we dig-into installation, configuration and all the yucky things! let’s first structure our project directory to have the whole picture of our start and end points.

> 📌 for Windows OS users, you gotta use `type null >> file` instead of the `touch` command. The `mkdir -p src/{...}` command won’t work either, you might find this [equivalent solution](https://stackoverflow.com/questions/905226/what-is-equivalent-to-linux-mkdir-p-in-windows) helpful or create these sub/directories separately.

```shell
$ mkdir -p src/components tests
$ touch src/index.html src/index.js
$ touch .babelrc .eslintrc.yml jest.config.js webpack.config.js
```

Above we executed commands that will result the following folder structure:

```
app/
├── src/
│ + components/
│ └── index.html
└── index.js
├── tests/
├── .babelrc
├── .eslintrc.yml
├── jest.config.js
└── webpack.config.js
```

> 💡 Tip: for Linux and Macintosh users, use `ls -R` command line to list all files & subdirectory contents

Dependencies
------------

I prefer to use brace expansion (_snippets below_) for installing similarly named packages; its hackable, prettier, and time saver.

**React**: [react](https://yarnpkg.com/en/package/react), [react-dom](https://yarnpkg.com/en/package/react-dom), [react-hot-loader](https://yarnpkg.com/en/package/react-hot-loader)

```shell
$ yarn add react react-{dom,hot-loader}
```

Type checking for React props
-----------------------------

As of React v15.5, using `React.PropTypes` is deprecated as mentioned in the [official documentations](https://reactjs.org/docs/typechecking-with-proptypes.html) and suggested to install and use the standalone \`prop-types\` library instead. Guess what? You don’t have to!

**Two birds one stone**; as of today React v16.0 uses prop-types as one of its dependencies (_might be removed in future releases_) and by installing [react](https://yarnpkg.com/en/package/react) you should get [prop-types](https://yarnpkg.com/en/package/prop-types) out-of-the-box.

![](https://thepracticaldev.s3.amazonaws.com/i/g4c68n8n2upf49336odm.png)

**Babel**: [@babel/core](https://yarnpkg.com/en/package/@babel/core), [@babel/preset-env](https://yarnpkg.com/en/package/@babel/preset-env), [@babel/preset-react](https://yarnpkg.com/en/package/@babel/preset-react), [babel-eslint](https://yarnpkg.com/en/package/babel-eslint), [babel-jest](https://yarnpkg.com/en/package/babel-jest), [babel-loader](https://yarnpkg.com/en/package/babel-loader)

```shell
$ yarn add @babel/{core,preset-env,preset-react} -D
$ yarn add babel-{loader,eslint,jest} -D
```

The (@) prefix on node modules called “scoped packages". Scopes are a way of grouping related packages together.

![](https://thepracticaldev.s3.amazonaws.com/i/185obe422mwg7kxnipih.png)

**Webpack**: [webpack](https://yarnpkg.com/en/package/webpack), [webpack-cli](https://yarnpkg.com/en/package/webpack-cli), [webpack-dev-server](https://yarnpkg.com/en/package/webpack-dev-server), [html-webpack-plugin](https://yarnpkg.com/en/package/html-webpack-plugin)

```
$ yarn add webpack webpack-{cli,dev-server} -D
$ yarn add html-webpack-plugin -D
```

**Linting** (optional): [eslint](https://yarnpkg.com/en/package/eslint), [eslint-plugin-react](https://yarnpkg.com/en/package/eslint-plugin-react)

```shell
$ yarn add eslint eslint-plugin-react -D
```

**Testing** (optional): [jest](https://yarnpkg.com/en/package/jest), [react-test-renderer](https://yarnpkg.com/en/package/react-test-renderer)

```shell
$ yarn add jest react-test-renderer -D
$ yarn add babel-core@7.0.0-bridge.0 -D
```


Configuration & Setup
---------------------

**Webpack**: webpack.config.js

```js
const HtmlWebPackPlugin = require('html-webpack-plugin');

const HtmlWebpackPluginConfig = new HtmlWebPackPlugin({
  template: './src/index.html',
  filename: './index.html'
});

module.exports = {
  module: {
   rules: [
      {
        test: /\.js|jsx$/,
        exclude: /node_modules/,
        use: { loader: 'babel-loader' }
      }
    ]
  },
  mode: 'development',
  devServer: {
    historyApiFallback: true,
    compress: true,
    port: 3030,
    open: true
  },
  plugins: [
    HtmlWebpackPluginConfig
  ]
};
```

Breaking down the webpack config:

*   **rules**: we attached babel as our loader, with rules which are matched to requests when modules are created
*   **mode**: webpack 4 introduces production and development mode, for defining webpack dev server and other stuff. We set the production mode later inline in package.json script
*   **devServer**: a set of basic [options](https://webpack.js.org/configuration/dev-server/#devserver)
*   **plugins**: used to serve our webpack bundles, and generates `./dist/index.html` from template file under `./src`
*   **entry**: As you might notice we have no entry point in our config, fortunately webpack 4 provides us with default entry point out-of-the-box `./src/index.js` (_you can override it_)

**Babel**: .babelrc

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

**Jest**: jest.config.js

```js
module.exports = {
  verbose: true,
  moduleDirectories: ['node_modules', 'src/components', 'tests']
};
```

I specified ’src/components’ as my module directory for tutorial’s purpose, but as your app grows you'll have to override that setting based on your needs.

**Eslint**: .eslintrc.yml

```
parser: "babel-eslint"
env:
  browser: true
  node: true
  jest: true
  es6: true
extends:
  - eslint:recommended
  - plugin:react/recommended
settings:
  react:
    version: "16.0"
```

*   **parser**: specify the JavaScript syntax we need to support, in our case we set Babel (for modern JavaScript language use)
*   **env**: an [environment](https://eslint.org/docs/user-guide/configuring#specifying-environments) defines global variables that are predefined
*   **extends**: a set of enabled rules from base configurations
*   **settings**: shared [settings](https://eslint.org/docs/user-guide/configuring#adding-shared-settings) it will be supplied to every rule that will be executed.

I use YAML extension here for Configuration File to specify configuration information for an entire directory, but you’re absolutely free to use whatever you like, such as a JavaScript, or JSON.

**Scripts**: package.json

```js
"scripts": {
  "start": "webpack-dev-server --hot",
  "lint": "eslint ./src",
  "test": "jest --colors -b -e --logHeapUsage",
  "build": "webpack --mode production"
},
```

**React**: src/index.html render container

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8”>
    <meta name="viewport" content="width=device-width">
    <title>App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
```     

**React**: create src/components/App.js as our initial component

```js
import React from 'react'
import PropTypes from 'prop-types';
import { hot } from 'react-hot-loader';

const App = ({message}) =><h1>Hello from {message}</h1>; 

App.propTypes = { 
  message: PropTypes.string 
}; 

export default hot(module)(App);
```

The App component is a stateless component that represents our application, and wrapped by hot a loader that tweaks in real time.

**React**: open and edit our entry point src/index.js

```js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

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

Run boy run
-----------

Before we keep moving on, we need to make sure that everything is working properly (scripts - package.json:)

```shell
$ yarn start
```

**Expected behavior**:

✓ A new tab should be opened in your default browser w/ localhost:3030 address 
✓ DevTools verify that our Hot Module Replacement is enabled 
✓ Webpack, Compiled successfully 


![](https://thepracticaldev.s3.amazonaws.com/i/n8swp1r9uqmc5lmukwcj.png)

* * *

Testing
-------

We’re not going to deep dive into testing details w/ jest. We'll create a minimal Snapshot Test, to make sure that our testing configurations is working correctly. Under tests/ directory create App.test.js file.

**Jest**: create tests/components/App.spec.js

```js
import React from 'react';
import renderer from 'react-test-renderer';
import App from 'App';

describe('App Component Test Suite', () => {
  it('Should render properly to DOM', () => {
    const wrapper = renderer.create();
    expect(wrapper.toJSON()).toMatchSnapshot();
  });
});
```

…and then run test script:


```shell
$ yarn test
```

The first time this test is run, Jest creates a snapshot file.

Last but not least
------------------

We're now ready to bundle our React application in production mode and optimizes the build for the best performance, all we need is run the following command:

```shell
$ yarn build
```

This will build the app for production to the dist/build folder.

Good job 🙌
-----------

Once you are done with that, and everything works as expected you now have taken care of the basic techniques to set up your own React application from scratch. You can take this even further by:

*   Extend webpack loaders, for example: [Style Loader](https://github.com/webpack-contrib/style-loader), [CSS Loader](https://github.com/webpack-contrib/css-loader), or [Sass Loader](https://github.com/webpack-contrib/sass-loader) to your webpack config
*   Add Git Hooks with Yarn/Npm scripts: `precommit`, `prepush`. For instance run linter before make a new commit
*   ...and tons of more stuff you can play with

* * *

If you enjoyed this post, I’d be very grateful if you’d help it spread by emailing it to a friend, or sharing it on Social Media. Thank you!

> [Set up React Toolchain from the Ground up](https://elmahdim.com/react-webpack-babel/) - Mahmoud Elmahdi