Vite: Modern Build Tool
Vite: Modern Build Tool
Vite (French for "fast") is the standard build tool for modern JavaScript projects. It starts your development server instantly, handles hot module replacement so fast you barely notice saves, and produces optimized production builds. It replaced webpack in most new projects.
Why Vite
Before Vite, tools like webpack would bundle your entire codebase even during development — which got slower as your app grew. Vite uses a different approach:
- Development: serves files as native ES modules, no bundling needed
- Production: bundles with Rollup for optimal output
- HMR: replaces only changed modules in milliseconds (not page reload)
Setting Up a New Project
# Create a new project
npm create vite@latest my-app
# Choose from:
# ○ Vanilla
# ○ Vue
# ○ React
# ○ Preact
# ○ Lit
# ○ Svelte
# ○ Solid
# ○ Qwik
cd my-app
npm install
npm run dev # starts at http://localhost:5173
npm run build # production build → dist/
npm run preview # preview production build locally
Vite Project Structure
my-app/
├── public/ # static assets (copied as-is)
│ └── favicon.ico
├── src/
│ ├── main.js # entry point
│ ├── App.jsx # root component (for React)
│ └── assets/ # assets processed by Vite (hashed filenames)
├── index.html # HTML entry (Vite uses this, not webpack's htmlplugin)
├── vite.config.js # Vite configuration
└── package.json
vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"), // import from "@/components/..."
}
},
server: {
port: 3000, // dev server port
open: true, // open browser on start
proxy: {
"/api": { // forward /api/* to backend
target: "http://localhost:8000",
changeOrigin: true
}
}
},
build: {
outDir: "dist",
sourcemap: true, // source maps for debugging
rollupOptions: {
output: {
manualChunks: {
vendor: ["react", "react-dom"], // split vendor bundle
}
}
}
},
test: { // Vitest configuration (test runner)
globals: true,
environment: "jsdom"
}
});
Environment Variables
Vite has a specific way to handle environment variables:
# .env — loaded always
# .env.local — loaded always, git-ignored
# .env.development — loaded in dev only
# .env.production — loaded in production only
# .env
VITE_API_URL=https://api.example.com
VITE_APP_NAME=My App
SECRET_KEY=not-exposed # NO VITE_ prefix = not exposed to client
// Access in your code — only VITE_* variables are exposed
const apiUrl = import.meta.env.VITE_API_URL;
const appName = import.meta.env.VITE_APP_NAME;
const isDev = import.meta.env.DEV; // true in development
const isProd = import.meta.env.PROD; // true in production
const mode = import.meta.env.MODE; // "development" or "production"
Importing Assets
// Images — returns URL string
import logo from "./assets/logo.png";
const img = document.createElement("img");
img.src = logo; // "/assets/logo-2a3f4b.png" (hashed in production)
// SVG as URL
import iconUrl from "./icons/star.svg";
// SVG as React component (with @vitejs/plugin-react)
import StarIcon from "./icons/star.svg?react";
// CSS
import "./styles/main.css"; // injected into page
// CSS Modules
import styles from "./Button.module.css";
element.className = styles.primary;
// Raw text
import template from "./email-template.html?raw";
// JSON
import data from "./data.json"; // fully typed in TypeScript
// Web Workers
const worker = new Worker(new URL("./worker.js", import.meta.url));
Vitest — Testing with Vite
Vitest shares your Vite config and is ultra-fast:
npm i -D vitest @vitest/ui jsdom
// math.test.js
import { describe, it, expect, vi } from "vitest";
import { add, multiply } from "./math.js";
describe("math utilities", () => {
it("adds numbers correctly", () => {
expect(add(2, 3)).toBe(5);
});
it("handles negative numbers", () => {
expect(add(-1, 1)).toBe(0);
});
});
// Mock modules
vi.mock("./api", () => ({
fetchUser: vi.fn().mockResolvedValue({ id: 1, name: "Alice" })
}));
npx vitest # watch mode
npx vitest run # single run
npx vitest --ui # browser UI for tests
Production Build
npm run build
# Output: dist/
# ├── index.html
# ├── assets/
# │ ├── index-Bx3yKz1A.js # hashed filename (cache busting)
# │ ├── vendor-C9mxPqL2.js # separate vendor chunk
# │ └── index-Dn4mVqR7.css
The hash in filenames enables permanent caching — if the file changes, the hash changes, and the browser fetches the new version.
Vite vs webpack
| Feature | Vite | webpack |
|---|---|---|
| Dev start | ~300ms | 5-60+ seconds |
| HMR | Instant | Seconds |
| Config | Simple | Complex |
| TypeScript | Native | Plugin needed |
| ESM | First-class | Via babel |
| Ecosystem | Growing fast | Massive |
For new projects in 2026: always use Vite. For existing webpack projects: migration is possible and usually worth it for large projects.
Next lesson: Project — Interactive Todo App — putting JavaScript fundamentals to work.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises