How I decreased our React App build time by 96.26% 🚀 (Webpack + Esbuild) (Part 1)

Saurav Tiru
5 min readMar 21, 2023

--

Speeeeeeeed.

At Radius, we use Webpack, a popular module bundler that can also be used to optimize the build time of any React application. Out of the box, Webpack provides lots of configurable options to help you get the most minimized build possible, subject to how you configure your webpack.config.js.

In this article, I’ll take you on a 2 part short journey where I first optimized our build times to reduce deployment times from a staggering 40 minutes, yeah I know it isn't very good 😢 , to initially 10 minutes, and now after integrating Esbuild to Webpack, to as low as possible to ~5 mins!

P.S: This article is subjected to one’s due diligence and only to be taken as a piece of information in this vast sea of bundlers' and transpilers' knowledge. Any corrections or suggestions are gladly welcomed.

Optimization: Part 1

Maintenance keeps the engine running ⚙️

You should probably look at your webpack.config.js and just observe the configuration done in it. I know I did, and it gave me some interesting insights.

Webpack config is a JavaScript object that configures one of Webpack’s options. Most projects define their Webpack config in a top-level webpack. config. js file, although you can also pass the config as a parameter to Webpack’s Node. js API.

So basically it tells Webpack, “Hey buddy!, build this project for me using these parameters!”, and Webpack gives you a single file, in our case a minified Javascript file, let’s call it web.js , which is served when a user visits our React Application via browser.

//...rest of webpack.config.js

module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env", {
useBuiltIns: "entry",
corejs: "core-js@3",
},
],
"@babel/preset-react",
],
plugins: [
["babel-plugin-styled-components", {
pure: true,
displayName: true,
}],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-syntax-dynamic-import",
"react-loadable/babel",
],
},
},
},

//...rest of webpack.config.js

The above is a configurable section of the webpack.config.js, which explains Webpack, on how to transpile files ending with an extension ending with[file].js also [file].jsx .

We transpile JS & JSX code using a transcompiler called Babel, in conjunction with Webpack.

Babel is a free and open-source JavaScript transcompiler that is mainly used to convert ECMAScript 2015+ code into backwards-compatible JavaScript code that can be run by older JavaScript engines

Now the build process involved —

P.S. — The build process may differ from project to project, be advised.

We build web.jsfor the client-facing web application and node.js to build an express server for our in-house SSR-related processes.

For this article, we shall focus on building the web.js.

On running command —

yarn build_client:staging

We get this output on terminal

[BABEL] Note: The code generator has deoptimised the styling of 
/Users/rads/Desktop/WorkRepositories/radiusApp/node_modules/
bugsnag-js/dist/bugsnag.js as it exceeds the max of 500KB.

[BABEL] Note: The code generator has deoptimised the styling of
/Users/rads/Desktop/WorkRepositories/radiusApp/node_modules/
lodash/lodash.js as it exceeds the max of 500KB.

Noticed something?
Why is it trans-compiling node-modules? <--- NOT GOOD!

With the current state above webpack.config.js, if you have heavy third-party npm libraries like Moment.js or Agora SDK in your package.json , you can actually take a long sabbatical until your web application finishes building!

Now let’s see the performance benchmarking for this —

The build took —

19 minutes. eww.

Build running on —

Yay Work Laptop!

Now imagine what an AWS EC2 instance with the not-so-great specification has to go through if it's not strong enough to handle such high-intensive CPU usage.

Higher build times lead to Higher Deployment times, and also a very much possible Out of Memory event leading to the crashing of Cloud Instance 💣 where our React Web Application is served.

Solution

Let’s get this machine roaring.

Cool so we have to pretty much avoid node_modules to be trans-compiled right?

How do we do this?

module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // <----add this!
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env", {
useBuiltIns: "entry",
corejs: "core-js@3",
},
],
"@babel/preset-react",
],
plugins: [
["babel-plugin-styled-components", {
pure: true,
displayName: true,
}],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-syntax-dynamic-import",
"react-loadable/babel",
],
},
},
},

What does this do?

It is basically as mentioned excludes the node_modules from the build process.

Voila ~

Yay, can we get a clap here?

That's a WHOPPING 85.0594% decrease in build time!

This led to reducing our deployment time from ~40 mins to 10 mins!

P.S. :- Build times may vary with different system configurations!

However, there may be cases where you need to include specific packages from node_modules in your webpack build, for example, if you're using dynamic imports or other features that require access to those packages. In such cases, you can use webpack's externals configuration option to selectively include or exclude specific packages.

In summary, excluding node_modules during a webpack build is generally a good idea, but it's important to consider your specific project's needs and requirements before making a decision.

In the 2nd and final part of this Webpack optimization series, I shall show how further I reduced deployment time to ~4 mins and build time to crazy ~41 seconds! using Es-build.

Thanks for reading, keep hacking!

****************************************************************

This post was inspired by me getting frustrated at longer build and deployment times 😅

I’m Saurav Tiru, Front End Engineer, Optimizing UI at Radius.

I would be posting articles related to Front End Engineering, Photography, and Video Editing every week!

--

--