Summary
Vite is a next-generation frontend build tool created by Evan You (Vue.js creator) that revolutionizes the development experience through its no-bundle development server and lightning-fast Hot Module Replacement (HMR). It leverages native ES modules in the browser during development, eliminating the need for bundling, which results in instant server starts regardless of application size. Vite pre-bundles dependencies using esbuild (written in Go) making it 10-100x faster than JavaScript-based bundlers. For production, it uses Rollup to produce highly optimized static assets with automatic code-splitting and tree-shaking. With first-class TypeScript support, framework-agnostic architecture, and a rich plugin ecosystem, Vite has become the preferred choice for modern web development. This cheatsheet covers Vite fundamentals, configuration, optimization strategies, and best practices for technical interviews.
1. What is Vite?
Vite (French for "quick") is a modern frontend build tool that provides:
- Lightning-fast HMR (Hot Module Replacement)
- Native ES modules during development
- Pre-configured Rollup for production builds
- Framework agnostic with first-class support for Vue, React, Preact, etc.
Key Differentiators:
- No bundling in development (uses native ESM)
- Instant server start regardless of app size
- Pre-bundling dependencies with esbuild (10-100x faster than JS-based bundlers)
2. Installation & Project Setup
Create New Project
# With npm
npm create vite@latest my-app -- --template react
# With yarn
yarn create vite my-app --template react
# With pnpm
pnpm create vite my-app -- --template react
# Available templates:
# vanilla, vanilla-ts, vue, vue-ts, react, react-ts,
# preact, preact-ts, lit, lit-ts, svelte, svelte-ts
Add to Existing Project
npm install -D vite
Basic package.json Scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
3. Project Structure
my-vite-app/
├── index.html # Entry point (not in public/)
├── package.json
├── vite.config.js # Vite configuration
├── public/ # Static assets (copied as-is)
│ └── favicon.ico
└── src/
├── main.js # JavaScript entry
├── App.jsx
└── style.css
Important: index.html is the entry point and must include:
<script type="module" src="/src/main.js"></script>
4. Configuration (vite.config.js)
Basic Configuration
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
open: true
},
build: {
outDir: 'dist',
sourcemap: true
}
})
Environment-based Configuration
export default defineConfig(({ command, mode }) => {
if (command === 'serve') {
return {
// dev specific config
}
} else {
return {
// build specific config
}
}
})
Common Configuration Options
export default defineConfig({
// Project root
root: process.cwd(),
// Base public path
base: '/my-app/',
// Directory to serve as static
publicDir: 'public',
// Dependency optimization
optimizeDeps: {
include: ['lodash'],
exclude: ['@vueuse/core']
},
// Build options
build: {
target: 'es2015',
minify: 'terser',
cssCodeSplit: true,
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
nested: resolve(__dirname, 'nested/index.html')
}
}
}
})
5. Development Server
Server Options
server: {
host: '0.0.0.0', // Listen on all addresses
port: 3000,
strictPort: true, // Exit if port is in use
https: true, // Enable HTTPS
open: '/docs', // Open browser to specific route
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
HMR (Hot Module Replacement)
// Accept updates for this module
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Handle the updated module
})
// Clean up side effects
import.meta.hot.dispose(() => {
// cleanup code
})
}
6. Asset Handling
Importing Assets
// Import as URL
import imgUrl from './img.png'
// Import as string (with ?raw)
import shaderString from './shader.glsl?raw'
// Import as Worker
import Worker from './worker.js?worker'
// Import CSS as string
import style from './style.css?inline'
Public Directory
<!-- Reference public assets with absolute path -->
<img src="/logo.png" alt="Logo">
Dynamic Imports
const module = await import(`./locales/${locale}.js`)
// With Glob Import
const modules = import.meta.glob('./modules/*.js')
// Eager loading
const modules = import.meta.glob('./modules/*.js', { eager: true })
7. CSS Handling
CSS Modules
// style.module.css
import styles from './style.module.css'
<div className={styles.container}>
PostCSS
// postcss.config.js
export default {
plugins: {
autoprefixer: {},
'postcss-nested': {}
}
}
Preprocessors
# Install preprocessor
npm install -D sass
# Just use it
import './style.scss'
CSS-in-JS
// Works out of the box
import styled from 'styled-components'
const Button = styled.button`
color: blue;
`
8. TypeScript Support
Setup
# No configuration needed, just use .ts files
npm install -D typescript
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"types": ["vite/client"]
}
}
Type Declarations
// vite-env.d.ts
/// <reference types="vite/client" />
// For asset imports
declare module '*.svg' {
const content: string
export default content
}
9. Environment Variables
Define Variables
# .env
VITE_API_URL=https://api.example.com
# .env.local (ignored by git)
VITE_SECRET_KEY=secret123
Access in Code
// Only VITE_ prefixed variables are exposed
console.log(import.meta.env.VITE_API_URL)
// Built-in variables
import.meta.env.MODE // 'development' or 'production'
import.meta.env.BASE_URL // Base URL from config
import.meta.env.PROD // boolean
import.meta.env.DEV // boolean
TypeScript Support
// vite-env.d.ts
interface ImportMetaEnv {
readonly VITE_API_URL: string
}
10. Plugins
Essential Plugins
// React
import react from '@vitejs/plugin-react'
// Vue
import vue from '@vitejs/plugin-vue'
// Auto-import APIs
import AutoImport from 'unplugin-auto-import/vite'
// Auto-import components
import Components from 'unplugin-vue-components/vite'
Writing Custom Plugin
function myPlugin() {
return {
name: 'my-plugin',
// Called on config resolution
config(config, { command }) {
if (command === 'build') {
config.base = '/dist/'
}
},
// Transform code
transform(code, id) {
if (id.endsWith('.custom')) {
return {
code: transformCustom(code),
map: null
}
}
},
// Dev server specific
configureServer(server) {
server.middlewares.use((req, res, next) => {
// custom middleware
next()
})
}
}
}
11. Build Optimization
Code Splitting
// Dynamic imports create separate chunks
const Home = () => import('./Home.vue')
// Manual chunks
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'moment']
}
}
}
}
Tree Shaking
// Automatically enabled for ES modules
import { debounce } from 'lodash-es' // ✅ Tree-shakeable
import _ from 'lodash' // ❌ Not tree-shakeable
Build Analysis
# Install analyzer
npm install -D rollup-plugin-visualizer
# Configure
import { visualizer } from 'rollup-plugin-visualizer'
plugins: [visualizer()]
12. Performance Features
Dependency Pre-Bundling
// Force include/exclude
optimizeDeps: {
include: ['linked-dep'],
exclude: ['large-dep']
}
Lazy Loading Routes
// React Router
const About = lazy(() => import('./About'))
// Vue Router
{
path: '/about',
component: () => import('./About.vue')
}
Web Workers
// Import as worker
import MyWorker from './worker?worker'
const worker = new MyWorker()
13. Production Build
Build Command Options
vite build --base=/my-app/ --mode staging --sourcemap
Preview Production Build
vite preview --port 8080
Static Site Generation (SSG)
// vite.config.js for SSG
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: 'index.html',
about: 'about.html'
}
}
}
})
14. Common Patterns
Alias Configuration
resolve: {
alias: {
'@': '/src',
'@components': '/src/components',
'@utils': '/src/utils'
}
}
Global Variables
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
Library Mode
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
name: 'MyLib',
fileName: 'my-lib'
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
15. Advanced Patterns & Debugging
Server-Side Rendering (SSR)
// vite.config.js
export default defineConfig({
ssr: {
noExternal: ['vue-router'], // Dependencies to bundle for SSR
target: 'node',
format: 'cjs'
}
})
// server.js
import { createServer } from 'vite'
const vite = await createServer({
server: { middlewareMode: true },
appType: 'custom'
})
app.use(vite.middlewares)
Monorepo Setup
// Root vite.config.js
export default defineConfig({
resolve: {
alias: {
'@shared': path.resolve(__dirname, '../shared/src'),
'@components': path.resolve(__dirname, '../components/src')
}
},
optimizeDeps: {
include: ['@myorg/shared', '@myorg/components']
}
})
Debug Strategies
# Verbose logging
vite --debug
# Clear cache
rm -rf node_modules/.vite
# Profile build
vite build --profile
Common Issues & Solutions
| Issue | Cause | Solution |
|---|---|---|
| Slow dev server | Large dependencies | Add to optimizeDeps.include |
| Module not found | Incorrect alias | Check resolve.alias config |
| CORS errors | Backend on different port | Configure server.proxy |
| Memory errors | Large builds | NODE_OPTIONS='--max-old-space-size=4096' |
| HMR not working | Circular dependencies | Refactor imports |
| Build size too large | No code splitting | Add dynamic imports |
16. Key Interview Concepts
Vite vs Other Build Tools
| Feature | Vite | Webpack | Parcel | Snowpack |
|---|---|---|---|---|
| Dev Server Start | Instant | Slow (bundling) | Medium | Instant |
| HMR Speed | <50ms | 200ms-2s | 100ms-1s | <100ms |
| Build Tool | Rollup | Webpack | Parcel | Rollup/Webpack |
| Config Complexity | Minimal | Complex | Zero-config | Minimal |
| Bundle Size | Optimal | Good | Good | Good |
| Ecosystem | Growing | Mature | Medium | Small |
| TypeScript | Native | Plugin | Native | Native |
How Vite's Architecture Works
Development:
1. Browser requests index.html
2. Vite serves HTML with ES module scripts
3. Browser requests JS modules
4. Vite transforms and serves on-demand
5. Dependencies are pre-bundled with esbuild
Production:
1. Rollup bundles all assets
2. Code splitting for dynamic imports
3. CSS code splitting
4. Asset optimization and hashing
5. Legacy browser support via @vitejs/plugin-legacy
Dependency Pre-Bundling Deep Dive
// Why pre-bundling?
// 1. Convert CommonJS/UMD to ESM
const lodash = require('lodash') // CommonJS
// Becomes: import lodash from '/node_modules/.vite/lodash.js'
// 2. Reduce network requests
import { debounce } from 'lodash' // 600+ modules
// Becomes: single pre-bundled file
// 3. Cache for performance
// Stored in node_modules/.vite with strong caching
Performance Optimization Strategies
| Strategy | Impact | Implementation |
|---|---|---|
| Code Splitting | High | Dynamic imports, manual chunks |
| Tree Shaking | High | Use ES modules, mark sideEffects |
| Compression | Medium | vite-plugin-compression |
| Image Optimization | Medium | vite-imagetools |
| Bundle Analysis | Diagnostic | rollup-plugin-visualizer |
| CSS Purging | Medium | PurgeCSS plugin |
| Lazy Loading | High | Route-based splitting |
Common Vite Gotchas & Solutions
// Gotcha 1: Glob imports are eager by default
const modules = import.meta.glob('./modules/*.js') // Lazy ✅
const modules = import.meta.glob('./modules/*.js', { eager: true }) // Eager
// Gotcha 2: Environment variables must be prefixed
VITE_API_URL=http://api.com // ✅ Exposed
API_URL=http://api.com // ❌ Not exposed
// Gotcha 3: SSR requires different entry
// Client entry: main.js mounts app
// Server entry: main.js exports app factory
// Gotcha 4: Process is not defined
// Solution: Define in config
define: {
'process.env': process.env
}
17. Interview Preparation Checklist
- ✅ Core Concepts: No-bundle dev, native ESM, esbuild pre-bundling
- ✅ Configuration: vite.config.js, plugins, build options
- ✅ Asset Handling: Static assets, imports, public directory
- ✅ CSS: Modules, PostCSS, preprocessors, CSS-in-JS
- ✅ TypeScript: Zero-config support, type declarations
- ✅ Environment Variables: VITE_ prefix, import.meta.env
- ✅ HMR: How it works, accept/dispose patterns
- ✅ Build Optimization: Code splitting, tree shaking, chunks
- ✅ SSR/SSG: Server-side rendering setup
- ✅ Performance: Why Vite is fast, optimization techniques
Key Takeaway: Vite revolutionizes frontend development by leveraging native ES modules for instant dev server starts and lightning-fast HMR. Its combination of esbuild for development and Rollup for production provides the best of both worlds: incredible development experience and optimized production builds. Understanding Vite's no-bundle architecture, dependency pre-bundling, and optimization strategies is crucial for modern web development interviews.