Getting Started with React from Scratch Using Webpack
Published: 2020-04-27 08:51:06

---
title: Getting Started with React from Scratch Using Webpack
published: true
description: 
tags: 
---
>- [Understanding Webpack](#what-is-webpack)
   - [What is webpack?](#w-i-s)
   - [Why webpack?](#why-webpack)
   - [The bundling process](#bundling-process)
>- [Setup Project Directory](#setup-directory)
>- [Configure Webpack](#setup-webpack)
>- [Setup Babel](#setup-babel)
>- [Add React Components](#add-react)
>- [HTML plugin](#html-plugin)
>- [CSS setup](#setup-css)
>- [Build and Run](#build-run)

<a name="what-is-webpack"></a>
## Understanding Webpack

<a name="w-i-s"></a>

#### What is webpack?
Webpack simply put is a module bundler. In the context of React and JavaScript, it bundles JS files for usage in a browser. It ingests raw react components (other frameworks too) and produces JS code understandable by browsers.

<a name="why-webpack"></a>

#### Why webpack?
Web browsers are designed to consume HTML, CSS & JavaScript, and as a project grows, configuring and keeping track of these files can be complicated. Webpack steps in to solve for this. An alternative to using webpack would be using task runners such as Gulp and Grunt. Other JavaScript packers include, (but not limited to), Parcel, Browserify, Rollup, and JSPM.

Webpack treats your project as a dependency graph starting from the index.js file pulling in dependencies using imports. It does all the preprocessing of files and results in bundles, guided by the configurations provided.

<a name="bundling-process"></a>

#### The bundling process
Webpack relies on loaders and plugins to transform specific inputs to proper outputs, for example, the babel-loader aids in transforming ES2015+ down to common JS, and to process HTML webpack uses a html-loader. Webpack loaders take in input and process it into an output called a bundle.

The bundling process begins from user-defined modules, that can point to other modules through imports. When bundling a project using webpack, it traverses the imports creating a dependency graph and generates outputs based on configurations from the `webpack.config.js` file.

Webpack evaluates each user entry, matching them against loader configurations that tell webpack how to transform them. It tries to match the entry to the file system using an entry's resolve configuration (which you can configure aliases for certain files or extensions). 

Webpack evaluates matched loaders from bottom to top and from right to left. For example, 

```javascript
{
  use: ["style-loader", "css-loader"]
}
```

webpack will use the loaders from the right (last element in the array), so the order of how you add the loaders matter. 

Loaders are pure JavaScript functions, taking in input data, transforming that data and returning it. When you use 2 or more loaders, the output data from one loader is passed onto the next one as input.

After all the loaders are found, webpack evaluates matched loaders while running the module through each loader, resulting in an output that will be injected into the resulting bundle. Once the evaluation of every module is complete, webpack writes an output, which includes a bootstrap script that describes how to start executing the result on the browser.

Plugins are more powerful than loaders and allow you to intercept runtime events at different stages of the bundling process, but are harder to maintain

#### Sources:
- [Why would I use a Webpack](http://tinselcity.net/whys/packers)
- [What is webpack - intro](https://survivejs.com/webpack/introduction/)
- [What is webpack](https://survivejs.com/webpack/what-is-webpack/)

<b>Let's write some code</b>

<a name="setup-directory"></a>

## Setting up the Project Directory
Create a project folder and add an `src` folder (where all react code is going to go into).

```json
/my-react-project
	/src
```

Setup the project directory using npm and git:
- `npm init` or `yarn init` to create a `package.json` file that will contain the scripts need to run the code and dependencies needed for the app.
- `git init` to set up a new Git repository

Add a `.gitignore` file, for all the files you don't want to commit, and add node_modules to it

```json
/my-react-project
	/src
	package.json
	.gitignore
```

<a name="setup-webpack"></a>

## Configure Webpack

Install dev dependencies:  `webpack` and `webpack-cli`
`npm i webpack webpack-cli --save-dev`  or `yarn add webpack webpack-cli --dev`  (*I will be using yarn throughout*).

Create a `webpack.config.js` in the root directory.

<a name="setup-babel"></a>

## Setup Babel

Install Dev Dependencies:
`yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader` 

- **babel-core**: Transforms ES6 to ES5
- **babel-loader**: helps webpack in transforming JavaScript dependencies
- **babel-preset-env**: determines which transformations/plugins to use and also determines the polyfills to use to suit different browsers. 
- **babel-preset-react**: adds support for JSX

Create a `.babelrc` file in the root directory and add the 2 presets need to convert react into browser-friendly content

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

Add rules to the `webpack.config.js`, they instruct webpack to use the babel-loader to transform files with the `.js` or `.jsx` extensions to JavaScript code understandable by browsers.

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

<a name="add-react"></a>

## Add React Components

To write react components we need to install dependencies: `yarn add react react-dom`.

`react-dom` acts as a glue between the components you create and the DOM. It lets you render components on the DOM.

We will need to create a simple react component to test if we have set up the project correctly. Create a `components` folder under `src` and add a sample component file `form.jsx`. Create a simple component that takes user input and displays it in a paragraph.

```javascript
// form.jsx
import React, { Component } from 'react';

class Form extends Component {
  constructor() {
	super();
	this.state = {
  	  name: ''
	}
	this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
	const { value } = event.target;
	this.setState({ name: value })
  }

  render() {
	return (
  	  <form>
      	<input placeholder="Your name?" type="text" onChange={this.handleChange}/>
    	<p>{this.state.name}</p>
  	  </form>
	)
  }
}

export default Form;
```

<a name="html-plugin"></a>

## HTML plugin
To render the component we just created we need to hook it up to a HTML template. Webpack needs a loader to help it work with HTML and we need to add rules for that.

But first install dev dependencies: `yarn add html-webpack-plugin html-loader --dev`.

The `html-webpack-plugin` plugin generates a HTML file with the `<script>` tag injected, it writes this into the dist/index.html file and minifies the file.


Update the `webpack.config.js`:
```javascript
// webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        ...
      },
      {
        test: /.html$/,
        use: [
          { 
            loader: "html-loader"
          }
        ]
      }
    ],
    plugins: [
      new HtmlWebPackPlugin({
        template: ".src/index.html" // absolute path to the html template
      })
    ]
  }
}
```

Now create the HTML template in an `index.html` file in the `src` folder and add a div with an id `container`, this is where the component we created will be mounted

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Dashboard</title>
  </head>
  <body>
    <div id="container"></div>
  </body>
</html>
```

Finally, you need to mount the component on the DOM. Create an `index.jsx` file in the src folder.

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import Dashboard from './containers/Form';

const wrapper = document.getElementById('container');
wrapper ? ReactDOM.render(<Form/>, wrapper) : false;

```

Your final folder structure would be:
```json
/my-react-project
    /src
        /components
            Form.jsx
        index.html
        index.jsx
    .babelrc
    .gitignore
    package.json
    webpack.config.js
```

<a name="setup-css"></a>

## CSS Setup
Install dependencies: `yarn add css-loader node-sass sass-loader style-loader`

- **css-loader** (_translates CSS to JS strings_): reads CSS from the `.css` files and resolves the CSS correctly (such as the import and URL() statements)

- **style-loader** (_creates style tags from JS strings_): adds the CSS to the DOM so that styles are active and visible on the page

- **sass-loader** (_translates SASS to CSS_): reads from `.scss` files and pre-processes it to CSS.

- **node-sass** (_SASS compiler used by sass-loader_): a library that provides a binding for node.js to LibSass (the C version of SASS), allowing fast compiling of `.scss` files. 

Webpack needs loaders to understand CSS and sass.

Update the `webpack.config.js` file:
```javascript
// webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        ...
      },
      {
        test: /.html$/,
        ...
      },
      {
        test: /\.(css|scss)$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      }
    ],
    plugins: [
      ...
    ]
  }
}
```

#### Tie up some loose ends
To import elements from files without using file extensions, you would need to add a rule in the `webpack.config.js` file to resolve them.

Update the `webpack.config.js` file:

```javascript
// webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  module: {
    rules: [
      ...
    ],
    resolve: {
        extensions: ['.js', '.jsx']
    },
    plugins: [
      ...
    ]
  }
}
```

<a name="build-run"></a>

## Build and Run
We are ready to build our sample app.
In the `package.json` add a build script to do this:

```json
{
  ...,
  "scripts": {
    "build": "webpack --mode production"
  },
  ...
}
```
 
Run `yarn run build`. This should create a `dist` folder where you'll find a HTML file, open this on your browser, you should see the form we created.

However, you want to be able to view changes as you work on your app without having to build it every time. To do this we need a server that will build and reload anytime changes are made.

Install dev dependencies: `yarn add webpack-dev-server --dev`.

Add a script to start the app:
```json
{
  ...,
  "scripts": {
    "build": "webpack --mode production",
    "start": "webpack-dev-server --hot --open --mode development",
  },
  ...
}
```

The `--open` flag opens your default browser to display the running app.
The `--hot` flag only reloads the component changed, rather than doing a whole page reload ([Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/#src/components/Sidebar/Sidebar.jsx)).

Run `yarn start`, you should be able to view the form on your default browser.

You're all set up now! Go forth and create stuff!