Vite

Vite 25,978 (French for "quick", pronounced "veet") first appeared in 2020 and is now the foundation of Nuxt 37,147 , SvelteKit 36,701 , Astro 17,728 , React Router 139,386 and SolidStart 269,718 , as well as Vitest 102,989 and Storybook 3,824 . Vite 8, released in March 2026, replaced its two internal bundlers (esbuild 126 for development, Rollup 141,981 for production) with Rolldown 181,166 , a single Rust bundler, which the Vite team reports makes production builds up to 10 to 30 times faster; Linear's build time fell from 46 s to 6 s.

A project from scratch

npm 2,036 create vite@latest runs the create-vite scaffolder, which has templates for vanilla JavaScript, React 7,897 , Vue 5,482 , Svelte 36,701 , Solid 269,718 , Preact 268,577 , Lit 310,034 and Qwik 453,955 , each also in TypeScript.

Scaffolding and running a vanilla Vite projectShell
npm create vite@latest hello-vite -- --template vanilla
cd hello-vite
npm install
npm install date-fns
npm run dev
Output
  VITE v8.3.0  ready in 1901 ms
  ➜  Local:   http://localhost:5173/

The template's entry point is index.html at the project root, which loads src/main.js; files in public/ are copied as-is. Replace src/main.js with a small app that uses a library:

src/main.js: a counter and a live timestampJavaScript
import './style.css';
import { formatDistanceToNow } from 'date-fns';
import { setupCounter } from './counter.js';
const opened = new Date();
document.querySelector('#app').innerHTML = `
  <h1>Hello, Vite</h1>
  <button id="counter" type="button"></button>
  <p id="since"></p>`;
setupCounter(document.querySelector('#counter'));
setInterval(() => {
  document.querySelector('#since').textContent =
    `Page opened ${formatDistanceToNow(opened, { includeSeconds: true })} ago`;
}, 1000);

Save style.css with the page open and the new styles appear without a reload. Then build the production version (npm run preview serves dist/ locally for a final check):

Output of 47
$ npm run build
vite v8.3.0 building client environment for production...
✓ 310 modules transformed.
dist/index.html                  0.45 kB │ gzip: 0.29 kB
dist/assets/index-BhPnBMYB.css   0.09 kB │ gzip: 0.10 kB
dist/assets/index-DTvthzAM.js   10.64 kB │ gzip: 3.83 kB
✓ built in 1.19s

Rolldown read 310 modules, mostly date-fns 36,647 files, and tree shaking cut a 20 MB library folder down to 3.83 kB of gzipped JavaScript. Upload dist/ to any static host.

Under the hood: native ESM in development
A bundle-first dev server rebuilds the app before serving it; Vite serves modules on demand
A bundle-first dev server rebuilds the app before serving it; Vite serves modules on demand

In development Vite does not bundle your source. At startup it pre-bundles dependencies, turning date-fns's 250 files into one cached module in node_modules/.vite/deps. The browser then requests /src/main.js, and Vite transforms that single file on demand, rewriting bare imports to real URLs: fetch http://localhost:5173/src/main.js and the date-fns import now reads from "/node_modules/.vite/deps/date-fns.js?v=13322008", preceded by an import of /@vite/client, the script that receives updates.

When you save a file, the server walks the module graph upward to the nearest module that accepts updates through import.meta.hot.accept(), and sends the new URL over a WebSocket; the browser re-imports just that module. Imported CSS and framework components (through the React and Vue plugins) accept updates automatically. If no module accepts the change, Vite reloads the page. Start-up and updates depend on the files you touch, not the size of the app.