Prerequisite

Before we get carried away with this blog, lets set the stage here. We will be diving deep into React and how does it work behind the scenes.

So its advisable for the readers to be versed with JavaScript, React.etc

Introduction

You all must have been familar with create-react-app right? Its like the step 1 for creating a new React project, for many developers. You might still be using this or if not, you must have used this at least once. (I mean the official react docs used to recommend this tool, so yeah its quite popular)

If you are not familar with this, its an open source tool by Facebook, to create new react apps. You can check out here.

Current Scenario

Anyways just like any other react project, we were also using create-react-app (CRA) to build and run our client (made with React). But this comes with its set of own problems.

And to counter these problems, we need to dive deeper into the working of CRA and how its builds app.

Working of CRA

Okay so CRA consists of various other tools helping us to build our react app. It has various dependencies working under the hood. Some of them are:

Babel

Babel is a JavaScript compiler, which converts the new generation JavaScript, which is usually what we write, into the browser compatible JavaScript. One use case can be to add polyfills to the code. To quote MDN

A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.

Babel is integrated in CRA helping developers to write modern JavaScript code without worrying about browser compatibility, and to enhance experience. For more info you can visit here

Jest

Jest is a framework used for testing the JavaScript code written. It is used by developers to write comprehensive unit tests for components, execute quick checks on member functions, and assess the functionality of React components, among other aspects, to ensure the proper functionality of the tool. There’s no need to install this seperately as it comes integrated with CRA, helping developers test the tool. For more info you can visit here

ESLint

Before diving into this, let me quote from Wikipedia

Lint is the computer science term for a static code analysis tool used to flag programming errors, bugs, stylistic errors and suspicious constructs

So in-short a Linter helps in pointing out errors in the code from the console, or sometimes from your text editor (like in my case, VSCode). ESLint is a JavaScript Linter, helping you to fix your JavaScript code, if any errors encountered. For more info, you can check out here

CSS-Loader

We all are familiar with CSS, right? and so when you want to include some external links/stylesheets to it, you may have seen people using url(), and @imports directly in the .css files. So CSS loader helps in interpreting them, and resolving them first, i.e loading them/importing them first before using the stylesheet. Its also used for managing CSS dependencies, and allows developers to easily import these files into their React components. For more info, you can visit here

Webpack

Apart from the above listed dependencies, there are a lot more dependencies which are used by CRA, to run a react app. But here’s a question, there are so many dependencies to take care of, how does CRA manage them?

Enters Webpack. Webpack is a module bundler, and it takes the files, configurations .etc from the code, and generate static assets. Bundling means getting all the files and their imports, and putting them together in one place according to the file type. The generated files are usually static files like “.js, .css, .jpg”. Apart from bundling, it can also run tasks like, Babel, CSS Loader.etc For getting a clear picture, look at the figure in the official website, here

As discussed above, when we run npm start or whatever the command you have defined for starting react, all the above tools take part. Webpack initiates other tools like Babel(also helping in converting jsx to js), PostCSS, CSS Loader, ESLint.etc

We now have various html,jss,css files, so Webpack bundles them together to generate static js, css and html files. It also resolves the imports, and external links.

The Problem

Now as you see, this process might take a lot of time, as it has to go multiple operations. Besides if your project has a large number of dependencies included, Webpack will try to resolve all of them (based on the imports), and so this can also contribute to increase build time.

And Since ours is considerably a “large project”, it was falling in all of the above cases (having large sets of dependencies, large code-base.etc). And yes, we were using CRA to build our client side, which was taking a lot of time to set up (locally).

Here’s a screenshot of the time it took for us to run the client on our local development server. webpack time taken 1st time build

As you can see from the docker log above, if we take the time difference between the two messages, it took roughly 22 seconds for the client to set up

Here’s the data I collected after multiple attempts (in hope of webpack caching some stuff, and reducing the build time). Strangely this worked, and kind of reduced the build time (local development time).

Attempt no. Build Time
1 23 s
5 12 s
8 5 s

Here’s another screenshot of timing webpack at probably 8th attempt I guess

webpack cached time

I’ve used time command to measure the time taken for the server to set up. The real time is the time taken for the server to set up, i.e 5.62 s. The user time is the time it waited for user inputs (if any). The sys time is the time taken by the system.

As you can see it did make a litte bit difference, I think Webpack cached some files (I’m not sure of this entirely tho). But I thought this can be reduced further. And since the game was mostly on bundler’s hand, we had to change the bundler.

PS: When I say build time, I mean the time taken for the local react server to set up on my machine, (not to be confused with the time required to build/generate static files)

Vite to Rescue

Vite is a tool for building mainly Vue, and React apps, just like CRA. But unlike CRA, it has some new tools/dependencies backing up, making it faster to build React apps, as compared to CRA.

Here’s how Vite works:

  • It uses esbuild as its bundler, instead of Webpack (in case of CRA) for local development purposes. Earlier, JavaScript language didn’t have any standard modules, even the browsers couldn’t have recognized the ES modules then. So we had to bundle our files (all sorts of files) into the static assests which our browser could understand. But nowadays, ES modules have been standardized, and termed as official module system to JavaScript. With these coming in, we don’t require to bundle everything to native code.

  • Here’s something about bundling, quoted from the official Vite docs

    This is why we are all familiar with the concept of “bundling”: using tools that crawl, process and concatenate our source modules into files that can run in the browser.

    which basically says, a bundler crawls over to every piece of code written (even though its not related/imported to the current page)

  • Instead of the crawling through the entire code-base. Vite divides the modules into two parts: dependencies and source code

    Dependencies are basically the libraries or modules imported in any file. Mostly these are the external libraries/dependencies we install via npm/yarn install, and we do not change/update their code (usually).

    Source code, on the other hand is defined as the code you type. Like the React components you define by yourself in a jsx file. You often tend to change them, as you move forward with your work.

  • Since Vite has divided the modules into two parts. It builds the dependencies before hand (they call this “pre-building”), using esbuild, which is written in Go (relatively a faster language than JavaScript). Go helps in pre-building dependencies faster as compared to bundling (webpack).

  • As far as source code is concerned, instead of crawling over the entire code-base/modules, and import everything, Vite loads the source code which is currently required by the browser natively (they call this “native ESM based server”), basically it uploads all the modules directly on the browser, instead of bundling it to one piece, giving it the advantage to faster load.

  • Vite transforms and serve only specific part of the code, which the browser requests (to show on the screen).

So with limited code loading up in the browser, our build time gets efficiently reduced. Here are some screenshots of the build time after we migrated to Vite

vite build time 1 Attempt 1

And after seeing what happened there with Webpack, I thought of running this multiple times, in hope of some more time reduction, and here’s what I got

vite build time cached Attempt 8

Yayy, it worked!!…

somewhat :(

Anyways here’s a proper tabular/detailed data

Attempt no. Build Time
1 0.38 s
5 0.32 s
8 0.23 s

If I must say, this is somewhat 60x faster than the Webpack configuration, and yeah so after this, I think I have only a few words left for you Webpack, Look What You Made Me Do.

Apart from this, Vite also helped in updating the files with its Hot Module Replacement (HMR), and other stuff. Not that Webpack didn’t support HMR, Vite just made it faster.

If you wish to learn more about this, you can visit the official docs here

Jest in Vite?

Of course, testing was something of a pain as well. Not only did Jest does not come in-built with Vite, it was not even compatible with Vite. I mean its still experimental, and we don’t want to be the first guys out there, experiencing something of our own. I mean its fun, but now its just not the time.

Anyways I looked up, came across Vitest, which seems compatible for unit testing with Vite. So we migrated all the tests from Jest to Vitest. Also in the future if we require E2E(End to End) testing, we may have to rely on Cypress.

Bye Bye?

For now.. Yes :)

I guess we did talked a lot about CRA, and Vite, and how they differ, how they build and create our React apps. I’m not saying Vite is better, but in some cases it is. The thing is CRA is not being maintained/updated during the recent years. I mean they have Github Issues and Discussions about how they need a regular maintainer Create React App Gone From React.dev, What happens to it now? #13072, We need regular CRA maintainer #11768. So yeah I’ll be preferring Vite over CRA, unless CRA starts to release new stuff, and basically makes a comeback in the market with a bang!!

With this, we have reached the end of our 2nd Bi-weekly GSOC Blog. I hope you all enjoyed this, had fun. If you have any query, do reach out to me on LinkedIn, Email .etc

Next blog coming up soon. See you around :)