How to build code generated by create-react-app with esbuild
Tags: esbuild, react
Published: 2021-07-12 21:23:04

[esbuild](https://esbuild.github.io/) is js bundler that is getting more and more traction because of it impressive build speed. [create-react-app](https://www.npmjs.com/package/create-react-app) (CRA) is well-established script to generate a new react application. In this article, we will take a look on what tweaks are needed to CRA output to pass build with esbuild.

# Alternatives
There are some react app generators that use esbuild out of the box:
* [npx esbuild-create-react-app my-app](https://github.com/awran5/esbuild-create-react-app#readme)
* [npx esbuild-react-app](https://github.com/IlmariKu/esbuild-react-app)

and those can be a good idea if you are starting a new project, but for already existing apps they probably will not be of much help. 

# Generting new application
To simplify our example, let's generate new application with CRA:
```
$ npx create-react-app esbuild-cra
                                             
Creating a new React app in /home/marcin/workspace/github/tmp/esbuild-cra.
                                             
Installing packages. This might take a couple of minutes.
...

We suggest that you begin by typing:

  cd esbuild-cra
  npm start

Happy hacking!
```

The next step is to install esbuild:
```
$ npm install --save-dev esbuild
added 1 package, and audited 1962 packages in 4s

146 packages are looking for funding
  run `npm fund` for details
...
```

# Adding test HTML
For testing the esbuild we will create a `dist` folder, and put there manually created `index.html`:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <title>React App</title>
    <link href="main.css" rel="stylesheet" />
  </head>
  <body>
    <div id="root"></div>
    <script src="main.js"></script>
  </body>
</html>
```

I created it based on html output of `npm run script`, and replace all dynamically created file references with static one that we will build in a moment.

# Build script
To build the application, I'll leave the original npm scripts as they were & add temporarily esbuild script for testing. I recommend doing the same if you decide to migrate your app - it will allow for a smooth testing before replacing original builds. Plus you will want to replace dev script too - something that is not covered in this article, and you will need to figure it out on your onw. 

To `package.json`, I add:
```json
  "scripts": {
    ....
    "esbuild": "esbuild src/index.js --bundle --outfile=dist/main.js --loader:.html=text --loader:.js=jsx --loader:.svg=dataurl"
  }
```

The build script parts means as follow:
* `src/index.js` - the entry point of our build. From there all our files are found
* `--bundle` - the files are all bundled into one, output file
* `--outfile=dist/main.js`  - the location where the output files should be saved
* `--loader:.html=text` - a loader that will read all HTML files are strings equal to the file content
* `--loader:.js=jsx` - the JSX load for JS files - as CRA uses this extension for JSX files
* `--loader:.svg=dataurl` - loader that includes SVG files as data url links (`data:image/svg;base64....`)

With this script in place we already can successfully run `npm run esbuild`:
```sh
$ npm run esbuild

> esbuild-cra@0.1.0 esbuild
> esbuild src/index.js --bundle --outfile=dist/main.js --loader:.html=text --loader:.js=jsx --loader:.svg=dataurl


  dist/main.js   902.9kb
  dist/main.css   1019b 

⚡ Done in 61ms
```

# Add explicit import
If you open the test page as it is now, you will see a white screen and the following error in console:
```
Uncaught ReferenceError: React is not defined
    App http://localhost/github/tmp/esbuild-cra/dist/main.js:20611
    renderWithHooks http://localhost/github/tmp/esbuild-cra/dist/main.js:12714
    mountIndeterminateComponent http://localhost/github/tmp/esbuild-cra/dist/main.js:14834
...
```

luckily it's easy to fix, we just need to import `React` in all places that are referencing it. In our case, just add to `src/App.js` this line as the first line:
```js
import React from "react";
```
# Links
* [my course about esbuild](https://bit.ly/esbuild-course)

# Summary
In this article, we have seen how to build esbuild an app generated with create-react-app. If you are interested in other articles on this topic, let me know in the comments.

You can see the application in action [here](https://marcin-wosinek.github.io/esbuild-cra/dist/), and the repository [here](https://github.com/marcin-wosinek/esbuild-cra)