Better ways to Create React App
Tags: react, beginners, webdev, tooling
Published: 2022-08-30 04:25:24

If you've tried React, chances are you've used `create-react-app` at least once. In case you were lucky and you haven't, here's how it goes:

You run something along the lines of:
```sh
npx create-react-app my-app
```

And observe the following console output:
```sh
Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


added 1394 packages in 44s

209 packages are looking for funding
  run `npm fund` for details

Initialized a git repository.

Installing template dependencies using npm...

added 55 packages in 4s

209 packages are looking for funding
  run `npm fund` for details
Removing template package using npm...


removed 1 package, and audited 1449 packages in 3s

209 packages are looking for funding
  run `npm fund` for details

6 high severity vulnerabilities
```

Yup, you've got yourself almost 1.5 thousand packages and a dash of vulnerabilities.

Wanna see something scary? Check the folder size:
```sh
du -hc -s  node_modules
# 318M	node_modules
```

No wonder this came along:
![Heaviest objects in universe: node_modules folder wins](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0k2cahsp54dps6gkao3u.png)

I'm puzzled why is this the recommended way, but gladly it's not the only one. 

## All-in-one: Vite

[Vite](https://vitejs.dev/) is a batteries included bundler & development server with presets for multiple frameworks, including React with or without TypeScript.

To create an app with Vite run:
```sh
npm create vite@latest my-vite-react-app
# ✔ Select a framework: › react
# ✔ Select a variant: › react
#
# or
#
npm create vite@latest my-vite-react-app -- --template react
```

Navigate to the folder and install dependencies:
```sh
cd my-vite-react-app && npm install
```

That was much faster and less greedy:
```sh
added 87 packages, and audited 88 packages in 5s

8 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

And it needs almost ten times less space too:
```sh
du -hc -s  node_modules
# 37M	node_modules
```

You can stop reading right here if you need a replacement to create-react-app with all the features it offers. It doesn't get better than vite.

For those of you, eager to push it even further at the cost of simplicity I have one more alternative 😎

## Need for speed: esbuild

Let's dig a bit deeper and take a look on the insides of both create-react-app (CRA) and vite. Both of them are a set of various tools configured to work together. CRA relies on [webpack](https://webpack.js.org/) to bundle your files, while vite uses a bit more modern [rollup](https://rollupjs.org/guide/en/). However they all are written in JavaScript and hence are capped by the performance of NodeJS script itself.

Enter [esbuild](https://esbuild.github.io): written in Go and advertised to be 10-100 times faster than any other popular bundler.

There's a catch, however: it is just a bundler. It doesn't come with one-liner to create an app and needs a bit of tinkering to get development server up & running.

Let's start by creating a folder:
```sh
mkdir my-esbuild-app && cd my-esbuild-app
```

Next, install esbuild & react dependencies:
```sh
npm init -y && npm install esbuild --save-dev && npm i react react-dom --save
# added 7 packages, and audited 8 packages in 828ms
# found 0 vulnerabilities
```

Expectedly the size is the least of all:
```sh
du -hc -s  node_modules
# 14M	node_modules
```

Prepare yourselves: it's time for the promised tinkering 🧑‍🔬

Create a folder with your public files:
```sh
mkdir public &&
echo '<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Esbuild + React</title>
    <link rel="stylesheet" href="/dist/main.css" />
  </head>
  <body>
    <div id="root"></div>
    <script src="/dist/main.js"></script>
  </body>
</html>' > public/index.html 
```

And some source files:
```sh
mkdir src &&
echo ':root {
  font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-text-size-adjust: 100%;
}

a {
  font-weight: 500;
  color: #646cff;
  text-decoration: inherit;
}
a:hover {
  color: #535bf2;
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}

h1 {
  font-size: 3.2em;
  line-height: 1.1;
}

button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}
button:hover {
  border-color: #646cff;
}
button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}

#root {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
}' > src/index.css &&

echo 'import React, { useState } from "react";
import ReactDOM from "react-dom/client";
import "./index.css";

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div className="App">
      <h1>Esbuild + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);' > src/main.jsx
```

And finally, run the development server:
```sh
./node_modules/.bin/esbuild src/main.jsx --servedir=public --outdir=public/dist  --bundle
```
And it works 😄 
If you're up for a little bit challenge - I encourage you to add some assets to the page, e.g. an SVG logo from one of the previous apps. You'll need to set up a loader for that 😉.

I must add though: at the moment there isn't a fast and easy way to get hot module replacement to work. To be honest, out of the box you are to refresh the page manually on every change, but live reload is a bit easier to setup.

## Conclusion

Create-react-app is slow & heavy and Vite provides much smoother developer experience and works out of the box. However if you're building a huge project or need the smallest possible footprint - esbuild is worth looking into.