Build React JS application with ESbuild and node.

AlamedaDev
AlamedaDev

--

Recently we made a change in one of the projects for our client, we were tasked with changing the build loader of a ReactJS application from webpack to esbuild.

As we love to try new things in React, this was a great opportunity to test a new tool that is gaining popularity in the ecosystem. Fortunately we had the help of Kevin Burke https://www.linkedin.com/in/ekrub/ to guide us and solve this daunting task, he made the initial setup with ‘Make’; but out of curiosity we wanted to test doing it with node.

Based on Kevin’s work, we have adapted the code to work with Node. And here we will show you how to change the loader from Webpack to esbuild with node doing these easy steps.

With the change from Webpack to esbuild we could shave 24 seconds of the app build 😆
We now have faster deployments and this is great!!

Esbuild build: Done in 481ms
Webpack build: Done in 25.06s.

Basic setup

  1. Create a ‘build’ folder at the root of your project
cd your_project
mkdir build

2. Create an ‘index.html’ file in the ‘build’ folder

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="icon" href="favicon.png"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<link rel="manifest" href="/manifest.json"/>
<title>My App</title>
<link href="/static/css/index.css" rel="stylesheet">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/static/js/index.js"></script>
</body>
</html>

3. Add ‘esbuild’ package to you node_packages

yarn add esbuild  // or
npm install esbuild --save

4. Add ‘regenerator-runtime’ to your app. (This is needed for making fetch calls, don't add this if you don't need it).

yarn add regenerator-runtime // or
npm install regenerator-runtime —save

In your ‘src/index.jsx’, add at the top:

...
import "regenerator-runtime/runtime";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>
)
...

5. Create a ‘build.js’ file on the root of your project

const { build } = require('esbuild');
const fs = require('fs-extra');
const generateBuild = async () => {
await fs.rmdirSync('./build/static', { recursive: true });
await build({
entryPoints: ['./src/index.jsx'],
outdir: './build/static/js',
minify: true,
bundle: true,
sourcemap: true,
target: ['chrome58', 'firefox57', 'edge16'],
loader: { ".svg": "dataurl", ".png": "dataurl" },
define: {
'process.env.NODE_ENV': "'production'",
...your env variables...,
}
}).catch(() => process.exit(1));
await fs.move('./build/static/js/index.css', './build/static/css/index.css', (err) => {
if (err) return console.error(err);
console.log("success!");
return null;
}
);
};
generateBuild();

6. Add ‘fs-extra’ package to your packages.

yarn add fs-extra // or
npm install fs-extra —save

7. Run your build

node build.js

The generated files should be in the ‘build’ folder now.

8. You should change your build scripts to use this build command.

"scripts": {
...
"esbuild": "node ./build.js"
...
},

Extra Steps:

To use esbuild in development mode and watch for the changes in files, we are going to make some more configurations.

As we are serving the build from a different folder and with different configurations we need to start the server on this new folder and using new configurations.

The react-script starts the app by default in the current folder and looks by default for the ‘src/index.jsx’ file unfortunately we can’t change this default behavior without ejecting. So we are going to use a separate server (servor) to start from our new build folder.

In the terminal run

npx servor ./build/ index.html --reload

It will ask for install the ‘servor’ package. Accept and install the package.

Then it will run with the options passed, and serve from the ‘build’ folder.

Now that we have the server running we need a way to watch for file changes and refresh the page. Chokidar package is great for this.

Let's install ‘chokidar’ package

yarn add chokidar // or
npm install chokidar --save

Modify the ‘build.js’ script to add chokidar watcher.

const { build } = require('esbuild');
const chokidar = require('chokidar');
const fs = require('fs-extra');
const generateBuild = async () => {
await fs.rmdirSync('./build/static', { recursive: true });
await build({
entryPoints: ['./src/index.jsx'],
outdir: './build/static/js',
minify: true,
bundle: true,
sourcemap: true,
target: ['chrome58', 'firefox57', 'edge16'],
loader: { ".svg": "dataurl", ".png": "dataurl" },
define: {
'process.env.NODE_ENV': "'production'",
...your env variables...,
}
}).catch(() => process.exit(1));
await fs.move('./build/static/js/index.css', './build/static/css/index.css', (err) => {
if (err) return console.error(err);
console.log("success!");
return null;
}
);
};
chokidar.watch('.', {ignored:/build|node_modules|.git/}).on('all', (event, path) => {
console.log(event, path);
generateBuild();
});

Don’t forget

In one terminal you should have the server running

npx servor ./build/ index.html --reload

And In another terminal you should have the build script running

node build.js

Also, change your ‘env.’ variables accordingly.

Notice you can have one ‘build.js’ file and one ‘watch.js’ file for different configurations if you need.

And that’s all. Enjoy your extra time!

Big thanks to Kevin for helping us decipher this.

You can find the code for this tutorial is in our GitLab account https://gitlab.com/alamedadev/react-js-build-using-esbuild

AlamedaDev is a full life cycle software solutions company. We provide Modern Software Development and #AI integrations.

Founded in #barcelona

Website: www.alamedadev.com

--

--

AlamedaDev
AlamedaDev

AlamedaDev provides full-service end-to-end software. Experts in modern software development and AI solutions