⚛️How to create a React Web Application without create-react-app CLI
Tags: webdev, react, javascript, programming
Published: 2024-04-11 12:21:59

In this post we'll build a React web application using webpack, Babel, React, and React DOM without relying on create-react-app

##❓What is create-react-app

> create-react-app is a CLI provided by facebook to make it easier for users to get started building with React. 

It is ideal for beginners to run a single command to get your environment ready to get started, but it has two major flaws


- It **restricts customization** for build configuration. For example you might want to use SWC (Speedy Web Compiler) for your deployment pipeline instead of pre-installed Babel for compilation of JS/TS codebase.

- It **abstracts a lot of the inbuilt tools** that makes React functional like processes of Transpilation, Minification, Bundling which one should know about while making Web applications

## ℹ️ Some Terminologies

1. **Transpiler** - Converts one form of JS code to another form of JS code. Convert ES6(ECMA Script 2015) into code that browsers can understand. Example **Babel**

2. **Module Bundler** - Takes different files HTML,JS, Style Sheets(CSS). And bundles them into a single file. Helps managing dependencies relations (Including loading modules in correct order), To improve performance, To organize your code, To reduce the number of HTTP requests Example **Webpack, Parcel, and Rollup.**

3. **Minification** - The process of removing unnecessary characters from programming languages or markup languages without changing its functionality. It is also known as minimization. Minification can include: Removing whitespace, Removing comments, Removing semicolons, Using shorter variable and function names, and Removing unused code.

## 🛠️ Tools used

1. **Babel** - A **transpiler**that converts **JSX -> JS, JS(ES6) -> JS(ES5)**

2. **Webpack** - A **module bundler**. Converts all assets to single file which is code optimized, minified.


> This combination allows developers to write code using the latest language features and ensure it's efficiently packaged for deployment.

**

##❓Why use so many tools required to run react locally

Before we start with the walkthrough there is one important question we need to answer

**_why do we need these specific tools such as vite or node(npm) to run React locally. Why can't we just use normal HTML, CSS and JS?_**

As we use JSX(Javascript XML) syntax very frequently which can't be understood by the browser. We need the presence of special build tools (Here Babel for Transpiling JSX into JS)



```js
/*
Function returning an HTML tag giving an error.
For using this type of syntax inside react we need a 
special build tool Babel (a Transpiler)
*/

function test(){
    return(
        <div>
            <h1>Hello world!</h1>
        </div>
    )   
}
```

### Output - 
![Output of above code on Web page console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uliazx44u6456abb14h.png)






For converting JS files using the syntax of JSX to the files that can be understood by the browser, 

We need special setup like **Vite** etc (Includes Build tools which Transforms and optimizes code eg remove unnecessary whitespaces, Handles imports etc)

## Note🗒️ 
You can skip the setup of having build tools by not using JSX syntax. **You can use React without JSX if you don't want to set up compilation in your build environment**. However Writing React without JSX can be more verbose than writing React with JSX.


<u>We have built our base fundamentals and answered some cruicial questions</u>. Now we are ready to start coding ⌨️

## Lets start coding 🖮

Open your terminal and run the following commands in order as they appear.

```
npm init -y
```
Initiates the NPM project with default configs

```
npm i react
```
Install the React library (Ofcourse)

```
npm i react-dom
```
This package **acts as a glue between React and the webpages DOM**. DOM is just a programming Interface for webpages. To know more about on what is it and how its useful in web-dev click here [MDN DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction)


## 🧊 Install webpack and its dependencies 

```
npm i webpack --save-dev
```

Install our module bundler **webpack**. Only needed as a dev dependency and not while our app is running on production.

```
npm i webpack-cli --save-dev
```

Provides a faster way  to initialize and configure a webpack project through the cli. (Also watches for file changes).

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

A utility complementing webpack. Provides a single line to setup a Live reload dev server using webpack.

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

Simplifies HTML file creation to serve our webpack bundles. Assists with adding our bundled files to `index.html` file.


## **🅱️** Install Babel and its utilities 

```
npm i @babel/core --save-dev
```

The main core babel transpiler

```
npm i babel-loader --save-dev
```

- **Loader** - Is what webpack uses to handle and process different file types. It dictates how certain file types are processed as they are imported into the project.

In this case transpile the js files from ES6 to ES5 before minifying them

**As there are different files hence there are difference loaders**

**For example**

- [babel-loader](https://www.npmjs.com/package/babel-loader) - For JS files. This package allows transpiling JavaScript files using Babel and webpack.

- [sass-loader](https://www.npmjs.com/package/sass-loader) - Transpiles SAAS files to css

- [style-loader](https://www.npmjs.com/package/style-loader) - style-loader takes CSS you've imported in your JavaScript files, and injects them as **Style** tags into the DOM. It's particularly useful for inlining Critical CSS into the **Head** tag of your page. 

```
npm i @babel/preset-react --save-dev
```

Preset is a set of plugins that support language features. By default Babel has the plugin ES2015 which add support for ES5 javascript

**preset-react** - Adds support for JSX(Javascript XML)

```
npm i @babel/preset-env --save-dev
```

preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!


### Contents of `package.json` After installing all modules. 




```json
{
  "name": "create-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": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.24.4",
    "@babel/preset-env": "^7.24.4",
    "@babel/preset-react": "^7.24.1",
    "babel-loader": "^9.1.3",
    "html-webpack-plugin": "^5.6.0",
    "webpack": "^5.91.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.0.4"
  }
}
```

Your installed versions might be different(**higher**) if you are following this at a later time.

After the above steps your directory structure should look like this.

```
└── root/
    ├── node_modules/
    ├── package.json
    ├── package-lock.json
```

## Configure Webpack ⚒️

Create `webpack.config.js` in the root directory and add the following content

```js
const path = require("path");
// For injecting the generated minified bundle.js to the index.html
const HTMLWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.join(__dirname, "/dist"),
    filename: "bundle.js",
  },

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

  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
    ],
  },
};

```

- **entry**- Essentially tell webpack which file to use as as the root to create a dependency graph. used to resolve modules which are dependent on one another and also building the modules in order (For example build those modules first which are required as a dependency by other modules)

- **output** - As webpack is a module bundler. It takes in a group files and outputs a smaller minified group of files. We need to specify the final output javascript file name and its path that will be generated by webpack

- **module** - Informs webpack what kind of loader we'll be using. It holds the information on how the different kind of modules will be treated.

- **rules** - Informs webpack that we'll be using 'BABEL' to transpile our js files. 

- **test** - Which files would be covered under this rule. It's stated by the regex `/.js$/` i.e all files with extension js.

- **exclude** - Excludes `node_modules` from transpilation process. If we don't exclude those, Otherwise it Makes the process slower and also we don't need to transpile those as they are mostly already minified. Only under very specific conditions we want to transpile some of the `node_modules` but not in this case.

- **use** - Specifies the babel-loader' that would be used for transpiling. 

- **options** - Specifies the presets which would extend the loaders ability to intake JSX and ES6 syntax 


### 👓 Current directory structure

```
└── root/
    ├── node_modules/
    ├── package.json
    ├── package-lock.json
    ├── webpack.config.js
```

## ✍️ Create the files required

- Create `index.js`(root for webpack to create a dependency graph) in the `src` folder and add the contents.


```js
import React from "react";
import ReactDOM from "react-dom";
// Get the component from the file to be rendered (Will be created later)
import App from './components/App'

// Get root id from index.html (will be created later)
ReactDOM.render(<App />, document.getElementById("root"));
```

- Create a folder `components` inside `src` and a file `App.js` to store the component that will be rendered in `root` div

```js
import React, { Component } from "react";

/*
Extending the Component class gives us access to its life-cycle method one of which is render
*/
class App extends Component {
    render() {
        return(
            <div>
                <h1>Hello world!</h1>
            </div>
        )  
    }
}

export default App;
```

- Inside the `src` folder create 'index.html'

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <!-- Where are react component will be renderer -->
    <div id="root"></div>
    
</body>
</html>
```

### 👓 Current directory structure

```
└── root/
    ├── node_modules/
    ├── package.json
    ├── package-lock.json
    ├── webpack.config.js
    ├── src/
    │   ├── components/
    │   |    ├── App.js
    |   ├── index.html
    |   ├── index.js
```


## ➕ Add scripts to package.json 
```
"start": "webpack-dev-server --mode development --open --hot"
```

we are using `webpack-dev-server` for live reload. It provides a fast in-memory access to the webpack assets to accomplish this.

**Flags**

- `--mode development` - Enable production optimizations or development hints.

- `--hot` - Enables Hot Module Replacement(HMR).It exchanges, adds, or removes modules while an application is running, without a full reload

- `--open` - Open the application in a new tab

```
"build": "webpack --mode production"
```
It will create a production build for us to deploy. Bundle and minify all our js in `bundle.js` located on a folder `dist`. 

The **HTMLWebpackPlugin** will inject our output `bundle.js` in index.html

## Final content for `package.json`

```js
{
  "name": "create-react-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --mode development --open --hot",
    "build": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.24.4",
    "@babel/preset-env": "^7.24.4",
    "@babel/preset-react": "^7.24.1",
    "babel-loader": "^9.1.3",
    "html-webpack-plugin": "^5.6.0",
    "webpack": "^5.91.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.0.4"
  }
}
```

## ♾ Run the scripts
To start a development live reload server

```
npm run start
```
### Logs

![sadasdasd](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/538q07qp885gsps9mwct.png)

#### Output


![Logs of npm run start](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/goytb0y5hv9kcner28ql.png)

#### Try it on your own
Make an edit to `index.html` and change its contents from "Hello World!" to "Hello Dev.to!". Save the file and see if the page gets updated as soon as you save your file. This is **Hot Reload** provided by the module `webpack-dev-server`

```
npm run build
```
It will create a `dist` production build folder with minified `bundle.js` generated by webpack and `index.html` (Already injected with `bundle.js` thanks to the module `html-webpack-plugin`)


### 👓 Current directory structure

```
└── root/
    ├── dist/
    |   ├── index.html
|   |   ├── bundle.js
    ├── node_modules/
    ├── package.json
    ├── package-lock.json
    ├── webpack.config.js
    ├── src/
    │   ├── components/
    │   |    ├── App.js
    |   ├── index.html
    |   ├── index.js
```

### EXTRAS

- **Why use require("path") which is a Node function inside frontend development?**

If you try to run `const fs = require("fs")` on browser it will throw an error. meaning its a Node enabled function.

Its a common practice in the development cycle. Whenever there is a need for local control(`BUT ONLY DURING THE DEVELOPMENT PROCESS`) for handling local files, paths, creating servers locally to enable faster development. We use local Node runtime environment(Which also uses JS as coding language).

- **Node version?**

This tutorial was made on node version 20.12.2 LTS

## Closing✌️

Thanks for reading it thus far. This is my first time publishing to dev.to. Got recommended this website by a fellow developer, Let's see how it goes.

## About me

[Socials 🆔](https://linktr.ee/bhavukkalra)