Vite replaced bundler-first dev servers like webpack-based Create React App with a fundamentally different model: serve native ES modules directly to the browser in development, and only bundle for production. This lesson covers why that model is so much faster and how esbuild and Rollup fit into the picture.
1Why Vite Replaced the Old Bundlers
Traditional dev servers like the one bundled with Create React App had to bundle the entire application with webpack before serving even a single file, which meant startup time grew directly with app size. Vite avoids that entirely in development, which is why it became the default starting point for new React projects that aren't using a full meta-framework.
2Native ES Modules in Development
Vite serves your source files directly to the browser using native <script type="module"> support, without bundling them first. The browser requests each imported module over HTTP as needed, so dev server startup time stays nearly constant regardless of how large the codebase grows.
3esbuild for Dependency Pre-Bundling
Packages in node_modules often ship as many small internal files, which would require hundreds of individual requests if served unbundled. Vite pre-bundles dependencies once using esbuild, a Go-based bundler that's dramatically faster than JavaScript-based tools, converting each package into a single efficient ESM module.
4Lightning-Fast Hot Module Replacement
Saving a file doesn't trigger a full rebuild ā Vite invalidates only the changed module in its existing module graph and pushes the update through Hot Module Replacement, typically in well under 50 milliseconds regardless of overall project size, while preserving component state where possible.
5Rollup for Production Builds
Native, unbundled ESM works well for development but would be inefficient for real users due to the number of network requests involved. For production, Vite switches to Rollup to bundle, tree-shake, and minify the app into a small set of optimized files, combining fast dev iteration with a lean shipped bundle.
6Step-by-Step Breakdown
Why Vite Replaced the Old Bundlers. Older React toolchains like Create React App bundled your entire app with webpack before the dev server could even start ā on a large app, that could mean waiting 30+ seconds just to see a change. Vite takes a fundamentally different approach to development, and it's now the default starting point for new React projects that don't use a meta-framework.
Native ES Modules in Development. Modern browsers can load JavaScript modules natively with <script type="module">. Vite leans on this directly: in development, it doesn't bundle your source files at all ā it serves them as-is, and the browser requests each module over HTTP as it's imported. Starting the dev server is nearly instant, no matter how large your app grows.
Why does Vite's dev server start almost instantly, even on a large codebase?
- āIt serves native ES modules on demand instead of pre-bundling the whole app
- āIt ships a smaller, stripped-down version of React
esbuild for Dependency Pre-Bundling. Third-party packages in node_modules often ship many small internal files, which would mean hundreds of browser requests if served one-by-one. Vite pre-bundles your dependencies once using esbuild ā written in Go and dramatically faster than JavaScript-based bundlers ā converting each package into a single, browser-ready ESM module.
Lightning-Fast Hot Module Replacement. When you save a file, Vite doesn't rebuild your whole app ā it invalidates only the changed module over the existing native ESM graph and pushes an update through Hot Module Replacement (HMR). Updates typically appear in well under 50 milliseconds, regardless of how many other files exist in the project.
When you save a single file while the Vite dev server is running, what does Vite typically do?
- āRe-transforms and pushes just that one module via HMR
- āRebuilds and re-bundles the entire application
Rollup for Production Builds. Native ESM-per-request is great for development, but shipping hundreds of separate network requests to real users would be slow. For production, Vite switches strategies and uses Rollup to bundle, tree-shake, and optimize your app into a small number of highly-compressed files ā you get instant dev feedback and an optimized production bundle from the same tool.
Mastery Achieved. You now understand why Vite became the default: native ESM serving for near-instant dev server startup, esbuild for fast dependency pre-bundling, sub-50ms HMR updates, and Rollup for a lean, tree-shaken production build. Next, you'll look at how a Vite React project is actually structured on disk.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Native ESM dev serving requires a browser with <script type='module'> support, which all modern browsers have.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Faster Local Iteration Supports More Accessibility Testing Cycles
Sub-50ms HMR means developers can test keyboard navigation, focus order, and screen reader behavior after small changes far more frequently, since each iteration cycle costs almost no wait time.
SEO Implications
- 1
Vite's Production Build Directly Affects Shipped Bundle Size
Rollup's tree-shaking and code-splitting in the production build reduce the JavaScript payload real users download, which affects load performance metrics that feed into Core Web Vitals and search ranking.
Best Practices
Keep node_modules Dependencies Reasonably Current
esbuild's pre-bundling step works best with packages that ship valid ESM; outdated or CommonJS-only packages can occasionally need extra Vite config (optimizeDeps) to pre-bundle cleanly.
Don't Assume Dev and Prod Behavior Are Identical
Since dev uses native ESM and production uses a Rollup bundle, always verify a change with npm run build && npm run preview before considering it fully tested, not just the dev server.
Frequent Bugs
A component works in the Vite dev server but breaks after npm run build.
Development mode (native ESM) and production mode (Rollup bundle) are genuinely different execution paths. Always test with vite preview against the actual production build output before shipping, since bundling can surface issues dev mode doesn't.
The dev server is slow to start the first time a new dependency is imported.
This is expected ā esbuild pre-bundles a new dependency the first time it's encountered and caches the result in .vite/deps. Subsequent starts are fast again since the cache is reused.
Real-World Examples
Migrating a Create React App Project to Vite
A team migrating a mid-sized CRA app to Vite saw local dev server startup drop from roughly 25 seconds to under 300 milliseconds, and HMR updates that previously took 2-3 seconds began appearing in under 50 milliseconds, significantly speeding up their iteration loop.
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
});