Create React project without CRA(or any build tool)
Tags: react, javascript
Published: 2023-01-09 14:02:35

---
title: Create React project without CRA(or any build tool)
published: true
date: 2022-05-13 12:11:44 UTC
tags: React,JavaScript
canonical_url: https://www.codeentity.tech/create-react-project-without-cra/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/se9vz8mxbzx6i2rppnxd.jpg
---

#### But why? Can’t we use CRA or other similar tools.

While CRA can be a useful tool for quickly getting started with a new React project, creating a project from scratch has several advantages that can be valuable for developers who want more control, a deeper understanding of their project, or the opportunity to try out new technologies and approaches.

**Creating a React project from scratch has several advantages over using a tool like Create React App (CRA).**

One of the main advantages is that it gives you more control over the project setup and configuration. When you use CRA, the tool handles a lot of the setup and configuration for you, which can be convenient. However, this also means that you have less control over how the project is set up and how it is built.

On the other hand, when you create a project from scratch, you have the opportunity to fully customize the project setup and build process to suit your needs. This can be particularly useful if you have specific requirements or preferences for how your project should be set up, or if you want to use a particular build tool or configuration that is not supported by CRA.

Another advantage of creating a project from scratch is that it can help you better understand the underlying technologies and tools that are being used in your project. By setting up the project yourself, you will gain a deeper understanding of how the different pieces fit together and how they work, which can be valuable knowledge to have as you develop and maintain your project.

Finally, creating a project from scratch also gives you the opportunity to learn and experiment with new technologies and approaches. While CRA is a convenient tool that can help you get started quickly, it may not always support the latest technologies or best practices. By creating a project from scratch, you can try out new tools and approaches and see how they work in your project.

#### Before we start

Before starting, you need to set up the environment:

##### Installing Node.js

Node.js is an open-source, cross-platform runtime environment that helps us write JavaScript applications and execute them.

Node >=18.0.0 You can get it from: [https://nodejs.org/en/](https://nodejs.org/en/). This will also install the npm (node package manager).

##### IDE

To start coding with React, we can use the Visual Studio Code IDE which can be downloaded from: [https://code.visualstudio.com/download](https://code.visualstudio.com/download). I personally prefer vscode but you can use any text editor of your choice like atom, webstorm, sublime.

#### Let’s Start

**To generate a React project without using any tooling, you can follow these steps:**

1. Create a new directory for your project and navigate to it.

2. Initialize a new npm package by running `npm init` and following the prompts. This will create a package.json file in your project directory.

3. Install the React and ReactDOM packages by running npm install react react-dom. This will add the React and ReactDOM packages to your project as dependencies and update the package.json file.

4. Create an `index.html` file in your project directory and add the following content:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React CDN</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="index.js"></script>
  </body>
</html>
```

1. Create an `index.js` file in your project directory and add the following content:

```js
import "/node_modules/react/umd/react.development.js"
import "/node_modules/react-dom/umd/react-dom.development.js"

const element = React.createElement("h1", null, "Hello world!")
ReactDOM.render(element, document.getElementById("root"))
```

1. Run a local development server by installing a tool such as http-server and running http-server in your project directory.

2. Open your browser and navigate to the URL of your local development server to view your React app.

Now let’s enhance this by using `babel` to transpile ths `.jsx` syntax and `webpack` to generate dev and prod bundles.

**To enhance the project that using webpack and Babel, we can follow these steps:**

1. Install the webpack and webpack-cli packages by running `npm install --save-dev webpack webpack-cli`. This will add the webpack and webpack-cli packages to your project as development dependencies and update the package.json file.

2. Install the Babel packages by running`npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader`. This will add the Babel packages to your project as development dependencies and update the package.json file.

3. Create a `webpack.config.js` file in your project directory and add the following content:

```js
module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
    ],
  },
}
```

This configuration tells webpack to use the babel-loader to transpile your JavaScript code using the Babel presets for environment and React.

1. Modify the index.html file to include the bundle file generated by webpack:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React CDN</title>
  </head>
  <body>
    <div id="root"></div>
    <!-- Webpack will create build at this path -->
    <script src="dist/bundle.js"></script>
  </body>
</html>
```

1. Modify the `package.json` file to include the following scripts:

```js
"scripts": {
    "build": "webpack --mode production",
  }
```

1. Modify `index.js` to:

```js
import ReactDOM from "react-dom/client"

const element = <h1>Hello World</h1>
ReactDOM.createRoot(document.getElementById("root")).render(element) // React 18
```

This script allow you to build your project for production using npm run build.

1. Run `npm run build` to build your project. This will generate `dist` folder with `bundle.js` file.
2. Now run `index.html` using `http-server` module or you can use `live server` extension if you are using vscode.
3. Let’s include html template file in webpack configuration to generate a complete prod ready bundle.

To include the HTML template in webpack configuration, you will need to use a webpack plugin called `html-webpack-plugin`. This plugin allows you to specify an HTML template file that will be used to generate an HTML file for your application.

To use the `html-webpack-plugin`, you will first need to install it as a dependency for your project. You can do this by running the following command in your terminal:

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

Once the html-webpack-plugin is installed, you can add it to your webpack configuration by adding the following code to your webpack.config.js file:

```js
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
  // other webpack configuration goes here
  plugins: [
    new HtmlWebpackPlugin({
      template: "path/to/template.html",
      filename: "index.html",
    }),
  ],
}
```

This will tell webpack to use the specified HTML template file to generate an HTML file for your application. The generated HTML file will be placed in the output directory specified in your webpack configuration and will be served when your application is built and run.

You can also use the html-webpack-plugin to customize the generated HTML file by specifying various options such as the title of the page, the favicon, and any metadata that should be included in the head of the HTML file. For more information on the options available for the html-webpack-plugin, you can refer to the [plugin’s documentation](https://webpack.js.org/plugins/html-webpack-plugin/).

1. Run `npm run build` to build your project. This will generate `dist` folder with `bundle.js` and `index.html` file.
2. You can run this `index.html` similarly using `http-server` module or you can use `live server` extension.
3. There’s something still pending in this config which is we can not import css files to project.
4. To setup this install style loader and css loader by running `npm install --save-dev style-loader css-loader`.
5. Now add this to webpack config by making following changes.

```js
// Add this to rules array in module object.
{
  test: /\.css$/,
  use: ["style-loader", "css-loader"],
}
```

1. Create a `style.css` file and add some styles in it.
2. Import this file in `index.js`
3. Repeat step 8 & 9. You will see the css changes applied. But this will add changes in js bundle and webpack will inject these as style tag on run time.
4. To extract css into separate file we can use [MiniCssExtractPlugin](https://webpack.js.org/plugins/mini-css-extract-plugin/).

But it’s not practical to build the project after making a single change. So we will setup a dev mode using `webpack-dev-server`

1. Install Webpack Dev Server using `npm install --save-dev webpack-dev-server`.
2. Create a `webpack.config.dev.js` and add following code.

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

module.exports = {
  entry: "./index.js",
  output: {
    filename: "bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
    }),
  ],
  devServer: {
    historyApiFallback: true,
  },
  devtool: "source-map",
}
```

1. We have some extra properties in this config.

2. This configuration file can be used with the `webpack-dev-server` to start a development server for project. To use this add following script to `package.json`.`"start": "webpack-dev-server --mode development --config webpack.config.dev.js"`

3. Run `npm run start` or `npm start` to start the development server and view your React app. Webpack will automatically transpile your code using Babel and reload the page when you make changes.

**Now we can change the folder structure a bit so that we can make it similar to conventional react project.**

1. Create a folder with name `public` at root and move `index.html` to this folder.

2. Create a folder with name `src` at root and move `index.js` and `styles.css` to this folder.

3. Also we need to change these paths webpack and webpack dev config.

**After this activity your folder structure should look like:** [![Folder Structure](https://codeentity.tech/static/52a71b7a0324402bddeddd1f463b9d82/ffa0f/folder.png "Folder Structure")](/static/52a71b7a0324402bddeddd1f463b9d82/ffa0f/folder.png)

##### Now we need to have a way to copy static assets like fonts and images to the bundle folder

1. To copy static assets such as images, fonts, or other media files using webpack, you can use the `copy-webpack-plugin` and the `file-loader`.

Here is an example of how to use the copy-webpack-plugin to copy static assets in your webpack configuration file:

```js
const CopyWebpackPlugin = require("copy-webpack-plugin")

module.exports = {
  // your webpack configuration goes here
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: "public",
          to: "assets", // This will be the path you will use to import the file. For eg. /assets/image.png
          globOptions: {
            ignore: ["**/index.html"], //Ignore index.html file
          },
        },
      ],
    }),
  ],
}
```

This configuration will copy all files from the `public` directory to the assets directory in the output directory. Now you can import the files present in public folder using absolute path directly in `image src or in css url`

1. Copy an `image.png` file to `public folder`
2. Change element variable in `index.js` to

```js
const element = (
  <>
    <h1>Hello World</h1>
    {/* Src path will be the path you will give in `to` property in config */}
    <img src="/assets/image.png" />
  </>
)
```

1. Restart the server and you will see and image in browser.

> copy-webpack-plugin is not designed to copy files generated from the build process; rather, it is to copy files that already exist in the source tree, as part of the build process.

This means that if we want to import images dynamically into `.js` or `.css` we can not use this. For that we need to use `file-loader`

`npm install --save-dev file-loader`

Copy following code to `webpack.config.dev.js` rules array.

```js
{
  test: /\.(png|jpg|gif|svg)$/,
  use: {
  loader: "file-loader",
  options: {
    name: "[name].[ext]",
    outputPath: "assets/",
    },
  },
}

```

Now you can import image file to js file using import syntax. Let’s try it out

1. Copy a image file `image2.png` to src folder.
2. Import file in `index.js` using following syntax.

```js
import image from "./image.png"
```

1. Modify `img` tag to use the imported file

```js
const element = (
  <>
    <h1>Hello World</h1>
    <img src={image2} />
  </>
)
```

Now you can see the result in browser.

To get a bit clarity how this works add a new image tag with src path from assets and run `npm run build`.

Check the dist folder to how webpack is generating the final build.

##### At last

Now as a final step we can modify `webpack.config.js` a bit to include versioning in the build process. Webpack provides versioning support out of the box.

In `webpack.config.js` modify `output.filename` to `bundle.[hash].js`.

Delete the dist folder and run `npm run build`. Webpack will generate bundle with a hash code.

If you are pushing the code to git add `.gitignore` file at root level and add following code

```bash
node_modules
dist
```

This will ignore the node\_modules and dist folder as we don’t need to push these.

#### What Next

- We can add `sass` or `postcss` support using loaders.
- Extract out css to separate bundles and hash css bundles also.
- Add [svgr](https://react-svgr.com/docs/webpack/) to import svg as react components.

[![](https://img.shields.io/github/forks/iamvishal345/react-from-scratch?label=Fork%20Complete%20Project&style=social)](https://github.com/iamvishal345/react-from-scratch)