Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
16 minLesson 32 of 35
Node.js & Tooling

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

FeatureVitewebpack
Dev start~300ms5-60+ seconds
HMRInstantSeconds
ConfigSimpleComplex
TypeScriptNativePlugin needed
ESMFirst-classVia babel
EcosystemGrowing fastMassive

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

Get Notes Free →
!