Course:Internet & Tools/
Lesson

Before Vite, starting a development server on a large React project could take 30-60 seconds. Every file save triggered a re-bundleWhat is bundle?A single JavaScript file (or set of files) that a build tool creates by combining all your source code and its imports together. that felt painfully slow. Vite was built to fix this, and it approaches the problem in a fundamentally different way. When AI tools generate conflicting Vite configurations, understanding how Vite actually works lets you pick the right answer.

Why Vite is fast

Traditional bundlers like Webpack process your entire application before the dev server can start. If you have 500 files, all 500 get bundled before you see anything in the browser.

Vite skips that step entirely during development. It serves files on demand using the browser's native ES moduleWhat is es modules?The official JavaScript module standard using import and export - enabled in Node.js via "type": "module" in package.json. support. When the browser requests a file, Vite transforms just that one file and serves it. Files that are never requested are never processed.

Webpack:  Bundle all 500 files  →  start server  →  open browser  (30s)
Vite:     Start server instantly →  browser requests file  →  transform on demand  (<1s)

Think of it like a restaurant. Webpack pre-cooks every dish before opening. Vite takes your order and cooks only what you asked for. The second approach is obviously faster when you only need a few dishes.

02

Creating a Vite project

The fastest way to start is with the official scaffoldingWhat is scaffolding?Auto-generating the basic file structure and starter code for a project or feature so you don't have to write it from scratch. command:

# Create a new project (prompts you to choose a framework)
npm create vite@latest my-app

# Available frameworks:
# Vanilla, React, Vue, Svelte, Preact, Lit, Solid, Qwik

cd my-app
npm install
npm run dev
# → http://localhost:5173

Your project is running in seconds, not minutes.

03

Project structure

A fresh Vite + React project has a clean, minimal structure:

my-app/
├── index.html            ← entry point (HTML, not JS - this is unusual)
├── vite.config.ts        ← Vite configuration
├── package.json
├── tsconfig.json
├── public/static files copied as-is (favicon, robots.txt)
│   └── favicon.ico
└── src/
    ├── main.tsx          ← JavaScript entry point (loaded by index.html)
    ├── App.tsx           ← root React component
    ├── App.css
    └── assets/           ← images/fonts imported in code (processed by Vite)
        └── logo.svg

The key difference from other tools: Vite's entry point is index.html, not a JavaScript file. The HTML file contains a <script> tag pointing to your main.tsx:

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head><title>My App</title></head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
AI pitfall
Copilot sometimes generates a webpack.config.js alongside vite.config.ts when autocompleting config files. If you see both, delete the webpack one, the two tools are incompatible and having both will cause confusion.
04

The vite.config.ts file

Most Vite projects need very little configuration. Here is a typical React setup:

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],

  server: {
    port: 3000,            // default is 5173
    open: true,            // open browser on start
    proxy: {
      '/api': 'http://localhost:8080'   // proxy API calls to backend
    }
  },

  resolve: {
    alias: {
      '@': '/src'          // import from '@/components/...' instead of '../../'
    }
  },

  build: {
    outDir: 'dist',        // output directory for production build
    sourcemap: true        // generate source maps for debugging
  }
});

Each section handles a different concern. You only add the sections you actually need, an empty config file with just plugins: [react()] is completely valid.

Config sectionPurposeWhen you need it
pluginsAdd framework support (React, Vue, etc.)Always
serverDev server port, proxy, HTTPSWhen defaults don't work
resolve.aliasPath shortcuts (@/ instead of ../../)Medium+ projects
buildOutput dir, source maps, chunk splittingWhen deploying
cssPostCSS, preprocessors, CSS modules configWhen using Sass/Less
defineGlobal constants replaced at build timeFeature flags, versions
05

Hot Module ReplacementWhat is hot module replacement?A dev server feature that swaps updated code into your running app without a full page reload, preserving your current state. (HMR)

HMR is Vite's most immediately useful feature. When you save a file, Vite pushes only the changed moduleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. to the browser. Your component state is preserved, there is no full page reload, and you see the change in under 100ms.

You edit App.tsx  →  Vite detects the change (via file watcher)
                  →  Transforms only the changed file
                  →  Sends it to the browser via WebSocket
                  →  Browser swaps the module in place
                  →  Component state is preserved

This matters most when working on stateful UI, a multi-step form, a shopping cart, a game. Without HMR, every save resets you to the initial state.

06

Environment variables

Vite has a strict security rule: only variables prefixed with VITE_ are exposed to client-side code. Everything else is invisible to the browser, preventing accidental leaks of secrets.

# .env file
DATABASE_URL=postgres://secret@db:5432     # NOT exposed to browser
API_SECRET=sk-abc123                        # NOT exposed to browser
VITE_API_URL=https://api.example.com        # Exposed to browser
VITE_APP_TITLE=My App                       # Exposed to browser
// In your React code
console.log(import.meta.env.VITE_API_URL);    // "https://api.example.com"
console.log(import.meta.env.DATABASE_URL);     // undefined (intentional)
console.log(import.meta.env.VITE_APP_TITLE);   // "My App"
console.log(import.meta.env.DEV);              // true in dev, false in prod
console.log(import.meta.env.PROD);             // false in dev, true in prod
AI pitfall
Claude and ChatGPT frequently generate .env files with variables like REACT_APP_API_URL (the Create React App convention) instead of VITE_API_URL. If you are using Vite, the REACT_APP_ prefix does nothing, your variable will be undefined. Always use the VITE_ prefix.

After changing .env files, you must restart the dev server. Vite reads environment variables at startup, not on every request.

07

Common Vite errors and fixes

Error messageCauseFix
Cannot resolve module './Button'Wrong import path or case mismatchCheck spelling; Linux is case-sensitive
import.meta.env.VITE_X is undefinedMissing VITE_ prefix or server not restartedRename variable, restart dev server
[plugin:vite:react-babel] ...JSX in a .js file instead of .jsx/.tsxRename file to .jsx or .tsx
Pre-transform errorCircular dependency or invalid importCheck for import cycles
Port 5173 is already in useAnother Vite instance is runningKill the other process or change port
08

Quick reference

CommandWhat it does
npm create vite@latestScaffold a new Vite project
npm run devStart dev server with HMR (port 5173)
npm run buildCreate optimized production build in dist/
npm run previewServe dist/ locally to test the production build
javascript
// vite.config.ts, typical React project configuration
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],

  server: {
    port: 3000,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  },

  resolve: {
    alias: {
      '@': '/src'
    }
  },

  build: {
    outDir: 'dist',
    sourcemap: true
  }
});