From one giant chunk to 141 small ones.

The frontend still built with webpack on React 17. A production build took a median 12.3 minutes in CI, and the app shipped nearly all of its JavaScript in one vendor chunk that every visit loaded up front.

I moved it to Vite on my own, and took React to 19, MUI to 7 and added Tailwind on the way, removing about 40 packages. The numbers below are for that whole upgrade, measured months later by rebuilding the last webpack commit.

  • Vite
  • React 19
  • MUI 7
  • Tailwind
  • Build tooling

Builds were slow

Cause.
A production frontend build took a median 12.3 minutes in CI.
Fix.
Vite builds the same app in a median 3.3 minutes. In a local rebuild, the embedded app went from 141 s to 12 s.

Everything loaded at once

Cause.
webpack put nearly every dependency into one vendor chunk: 1.39 MB gzipped in a single file, and 1.76 MB of JavaScript loaded up front.
Fix.
Vite splits the output into 141 chunks. The first page now loads 34 of them, 359 KB in all, and routes load their own code when they're opened.

Results

CI frontend build, median
12.3 min12.3 min
CI, 21 and 25 runs
Main app, JS loaded up front
1,759 KB1,759 KB
gzipped, rebuilt
Embedded app, JS loaded up front
1,148 KB1,148 KB
gzipped, rebuilt
Largest JS file
1,388 KB1,388 KB
gzipped, rebuilt
CSS loaded up front
80 KB80 KB
gzipped, rebuilt
Total JS shipped
1,795 KB1,795 KB
gzipped, rebuilt

Then vs now, not Vite alone

The same upgrade moved React 17 to 19 and MUI 5 to 7, added Tailwind and removed about 40 packages, and the newer build carries six months of features. So these numbers are for the whole upgrade, not what Vite saved by itself. Total JavaScript barely moved (−11%); the win is what loads first.

What a first visit really loads

The 359 KB is what the page itself asks for. A first visit also loads the code for the route it opens, which puts a real first page closer to 500–600 KB gzipped: still about a third of before.

How it was measured

Build times are medians of GitHub's job timings: 21 webpack runs (Feb 20 – Mar 21) and 25 Vite runs (Sep 15 – Oct 8). No webpack-era bundle survived, so sizes come from rebuilding the last webpack commit and current master in Docker, with no cached layers. Fonts and images are the same in both and left out.

More case studies