How to build code generated by create-react-app with esbuild
esbuild is js bundler that is getting more and more traction because of it impressive build speed. 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:
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
:
<!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:
"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
:
$ 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:
import React from "react";
Links
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, and the repository here