DEV Community

loading...
Cover image for Migrating a 150K LOC codebase to Vite and ESBuild: Why? (part 1/3)

Migrating a 150K LOC codebase to Vite and ESBuild: Why? (part 1/3)

Stefano Magni
Passionate, positive-minded Front-end engineer (working remotely) / Speaker / Instructor
・4 min read

What is Vite? Why did we consider it? Is it faster than Webpack? Is it mature enough?


This is part of a three-article series about migrating our React+TypeScript codebase from Webpack to Vite. Part 2 is about how we did it, Part 3 is about post-mortem considerations.

From Webpack’s slowness to Vite

It’s always the same story: you start working on a branch, run yarn start and wait for two minutes. Then you save a file and wait for 20 or 30 seconds before the app gets refreshed. Then you switch multiple times among the branches you’re working on, and you need to relaunch the dev server again. Such a terrible Developer Experience.

We reduced this problem by moving to Vite and ESBuild. Keep on reading.

The WorkWave RouteManager UI team works daily on a 150K LOC (and growing, ~250K LOC is the final size) codebase. Due to the nature of the Product and the technical constraints, there is nothing we can do to split the app into little chunks at the moment. 75% of the code is shared and used by all the app sections.

The app is based on React and TypeScript, spans a Web Worker, uses Webpack, babel-loader, ts-loader, and fork-ts-checker to bundle and validate the code. All the dependencies are updated weekly.

Recently, Vite 2.0 has been released. Its core idea is simple: serving the files “as are” to the browser leveraging ESModules. When the browser parses the source files and asks the webserver for an imported file, Vite does

  • convert NPM dependencies to ESModules and serve them

  • transpile your source code through ESBuild

  • serve the code to the browser

What does it mean? It means that Vite doesn’t bundle the code in advance. Instead, when the browser asks for a file, Vite transforms it. A picture is worth more than a thousand words.

The browser performs thousands of requests for the source files (.tsx, .ts), not for the bundled one as happens with Webpack.
The browser loading the thousands of unbundled .ts and .tsx files.

The files are cached, but Vite essentially removes the burden from the build tool, moving it to the browser. You can read more on Vite docs or on CSS-Tricks’ Comparing the New Generation of Build Tools article.

What about the build? Vite leverages Rollup to build the project, no worrying about browser compatibility of the final bundle.

Vite’s advantages

In contrast to Webpack, Vite is not a generic tool. Vite supports a few sweet spots. If your project falls in these spots, Vite offers

  • Better performances, thanks to the speed of ESBuild.

  • Less configuration.

  • Fewer dependencies: everything required for a React+TypeScript project like ours is managed directly by Vite, React Fast Refresh included.

But not all that glitters is gold! What does Vite not include?

  • TypeScript validation: to be short, ESBuild removes type annotations without validating them. You must run tsc on your own to validate types.

  • It depends on your configuration, but in our case, ESLint runs thanks to fork-ts-checker. Vite doesn’t care about ESLint.

Notice: I’m going to talk about these missings in the 3rd part of this series, including some objective considerations about Vite and Webpack and the overall Developer Experience.

Last but not least: are Vite and its ecosystem mature enough?

In the end: betting on Vite is not hazardous. Anyway, we decided to keep the codebase compatible with Webpack to swap between Vite and Webpack in case of troubles.

Benchmarks

To give you an idea of the performance improvements, take a look at our early benchmarks, the ones I shared with the rest of the team

Tool yarn start app loads in React component hot reload ** web-worker change "hot" reload **
Webpack* 150s 6s 13s 17s
Vite* 6s 10s 1s 13s

* Early benchmark where Webpack runs both ESLint and TypeScript while Vite doesn't
** Means from CTRL+S on a file to when the app is ready

Then, getting the codebase ESBuild-ready allowed us to put Webpack on a diet too, these are our final benchmarks.

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
(babel-loader + ts-loader + fork-ts-checker)
185s 182s 7s 10s 18s
Webpack
(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

Migrating the codebase

The 2nd part of this series deepens the technicalities under the migration of our codebase. The 3rd part is about the conclusions, the DX, and a more fair comparison with Webpack.

Discussion (0)