Vite#

Vite is a frontend build tool and local development server. It sits between your source code and the browser, transforming files that the browser cannot understand (TypeScript, JSX, CSS modules, image imports) into plain assets it can.

The Core Mental Model#

At the end of the day, a browser still just wants an HTML file with a <script> tag pointing to some JS. That hasn’t changed since 1995. Vite’s entire job is:

Take your source code → do some transformations → output files the browser can load.

Everything else — hot reloading, TypeScript compilation, bundling, optimization — is in service of that one goal.

Two Modes: Dev vs Build#

Vite operates differently depending on what you need:

Development (``npm run dev``) starts a local HTTP server (typically localhost:5173) backed by a running Node process. It does not bundle your code — it serves files individually and uses native ES modules in the browser for speed. Changes to source files trigger instant hot module replacement (HMR): only the changed module updates in the browser without a full reload.

Production build (``npm run build``) bundles everything into an optimized dist/ folder using Rollup under the hood. It:

  • Merges all your source files into one (or a few) JS files

  • Tree-shakes unused code from libraries

  • Minifies — removes whitespace, renames variables to single letters

  • Hashes filenames for cache busting

  • Handles code splitting for lazy loading

The dist/ output is what gets deployed to Netlify. node_modules/, your source files, and all of Vite’s tooling never reach the user.

The Interception Layer#

Vite intercepts import statements and applies transformations before the browser sees anything. This is what makes patterns like this possible:

import logo from './logo.png'         // not valid JS — Vite handles it
import styles from './Button.module.css'  // also not valid JS
import data from './config.json'      // also not valid JS

These are instructions to Vite, not to the browser. Vite processes them during the build and replaces them with valid JS. The browser never sees the raw import — it receives the result.

This is a pattern you won’t find in Python or Java: some lines of code are consumed by the build tool and never execute. Coming from those ecosystems, this can feel like the rules are different — because they are.

Boundary Enforcement#

Vite knows which code is destined for the browser and enforces that boundary strictly. If your app code (browser-bound) tries to import a Node-only module like fs:

import { readFileSync } from 'fs'  // ❌ Node-only, not available in browser

Vite will fail the build with an error before producing any output. It refuses to ship code that would break at runtime. It does not silently delete the line — it stops and tells you to fix it.

Bundle Size#

Every library you add contributes its code to the final bundle. A heavy 3D library, a charting package, a full UI component library — bundles can easily reach multiple megabytes. On mobile data, that’s a real cost to users.

Vite addresses this through:

  • Tree shaking — if you import one function from a 500kb library, unused code is stripped from the bundle

  • Code splitting — the bundle is divided into chunks loaded on demand as the user navigates, not all upfront

  • Lazy loading — heavy components only load when the user actually needs them

For projects with heavy visualization libraries (Three.js, Plotly), code splitting so that visualizations only load on the relevant view is the right approach.

Note

node_modules/ size (developer disk) and bundle size (user download) are different things. node_modules/ might be 300mb — the bundle Vite produces from it might be 200kb.

Project Structure#

A standard Vite + React + TypeScript project looks like:

my-app/
├── dist/              ← build output, deployed to Netlify
├── node_modules/      ← installed packages, never committed
├── public/            ← static assets copied as-is to dist/
├── src/
│   ├── main.tsx       ← entry point, mounts React
│   ├── App.tsx
│   └── components/
├── index.html         ← shell, references the JS bundle via <script>
├── vite.config.ts
├── package.json
└── package-lock.json

See also

npm — installs Vite and all other dependencies before Vite can run. React — the UI library Vite most commonly builds. Node.js — the runtime Vite executes on.