Migrating a 150K LOC codebase to Vite and ESBuild: is it worthwhile? (part 3/3)
Tags: vitejs, esbuild, react, webpack
Published: 2021-05-26 06:59:37


A fairer comparison between Webpack and Vite, some Vite caveats, and the overall Developer Experience.

---

This is part of a three-article series about migrating our React+TypeScript codebase from Webpack to Vite. [Part 1](https://dev.to/noriste/migrating-a-150k-loc-codebase-to-vite-and-esbuild-why-part-1-3-2idj) is about why we decided to migrate, [Part 2](https://dev.to/noriste/migrating-a-150k-loc-codebase-to-vite-and-esbuild-how-part-2-3-1c08) is about how we did it.

## Putting Webpack on a diet

As said in the previous articles, Vite is faster than Webpack, but it does fewer things. Earlier in this series, I told that our custom Webpack configuration leverages babel-loader, ts-loader, and [fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin) that compiles TypeScript and runs ESLint at the same time. On the other hand, ESBuild (that’s at the core of Vite) doesn’t check types neither runs ESLint.

**How fast is Webpack without TypeScript and ESLint?** Is it fast enough to outstand Vite? The answer is no, but it gets closer. Keep on reading.

## Webpack ESBuild Loader

Now that our codebase is ESBuild-ready, we can use it through Webpack, too. [webpack-esbuild-loader](https://github.com/privatenumber/esbuild-loader) it’s the solution (discovered in a [discussion on Twitter](https://twitter.com/VLecrubier/status/1375731336330248196?s=09)). By removing fork-ts-checker, TypeScript, and ESLint burden from Webpack, we can run a fairer comparison between Vite and Webpack.

|                                                  Tool | 1st yarn start, app loads in | 2nd yarn start, app loads in | browser reload (with cache), app loads in | React component hot reload \*\* | server-data change "hot" reload \*\* |
| ----------------------------------------------------: | ---------------------------- | ---------------------------- | ----------------------------------------- | ------------------------------- | ------------------------------------ |
| Webpack<br />(babel-loader + ts-loader + fork-ts-checker) | 185s                         | 182s                         | 7s                                        | 10s                             | 18s                                  |
|                              Webpack<br />(esbuild-loader) | 56s                         | 52s                         | 7s                                        | 10s                             | 16s                                  |
|                                                  Vite | 48s                          | 31s \*                       | 11s                                       | 1s                              | 14s                                  |

*\* Vite has an internal cache that speeds up initial loading*
*\*\* Means from CTRL+S on a file to when the app is ready*

That’s quite interesting, the conclusions are

* We can boost Webpack through ESBuild loader.

* Even in this case, Vite is faster. In particular, React Fast Refresh makes a huge difference.

We aren’t interested that much in the build time (we are trying to improve the everyday DX), but for completion’s sake, below you can find the build’s performance.

|                                                      Tool | Build |
| --------------------------------------------------------: | ----- |
| Webpack<br />(babel-loader + ts-loader + fork-ts-checker) | 170s  |
|                             Webpack<br />(esbuild-loader) | 42s   |
|                                                     Vite\* | 58s   |

*\* Turning off Brotli compression*

## Vite’s issues

I like Vite, but I don’t demonize Webpack. I care about the DX, not the tool itself. That’s why I try to objectively report the issue we’ve found until now while working with Vite:

* Save after save, the Devtools’ Source Panel lists the same file multiple times. Not a big deal, but sometimes you choose the wrong one.

![The Sources panel of the Chrome DevTools that shows multiple time the same file. The correct one is recognizable because it doesn’t have a querystring parameter.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hpu2ueya6mtoe0fgmipb.jpg)

* Going back and forth in the browser history loads stale files if the cache is enabled. At the same time, disabling the cache makes Vite slower.

* Vite moves workload from the bundle to the browser: Vite consumes a fraction of RAM compared to Webpack, but the browser’s job will be more CPU-intensive. The fans testify.

* After a lot of Hot Reloads, you better reload the whole app.

* There is a small portion of files that we can’t breakpoint through the Devtools, and we still have to understand why.

* The development version of the front-end app is significantly slower than the built one.

## In the end: Vite or Webpack?

The answer comes from the developers who use them the most: **Vite**!

Vite’s performances and fluidity win over Webpack. The overall DX is an order of magnitude better, even considering the above issues.

I’m going to remove every Webpack dependency, the configuration, and all the scripts in the future😊 (or, at worst, when a Webpack release requires a lot of frontend-ops work).

That’s all! I hope tracking our journey would be helpful for you too. Feel free to leave comments to share your experience or suggesting more improvements.

## What's next

I need to try [Webpack's file-system cache](https://twitter.com/alexander_akait/status/1398031559723261952) again. We discarded it because of an old problem, but things could have changed in the meantime.

Then, I also shared how to get the best of the "old" bundling experience and the new one by enabling Rollup watch-mode inside Vite in my [Speed up E2E tests for Vite-based apps](https://dev.to/noriste/speed-up-e2e-tests-for-vite-based-apps-3k4l) article.

## Post scriptum

Speaking about **ESLint**, we won’t run it anymore in watch mode while working. The rationales behind this decision are similar to the motivations behind Vite:

* VSCode runs ESLint every time you save a file

* Through lint-staged, staged files pass through ESLint

There is no reason to have ESLint actively running anymore. Let’s remove it from Webpack too. And if you run ESLint in watch mode, remember to [turn on its cache](https://twitter.com/NoriSte/status/1354445830523146248).