Vite Tutorial: Learn Build Tool from Scratch (2026)
Vite is a next-generation front-end build tool created by Evan You (creator of Vue.js). Instead of bundling your entire application before the dev server can start, Vite serves source files over native ES modules — the browser handles module loading, giving you instant server start and hot module replacement that stays fast regardless of project size.
For production builds, Vite uses Rollup under the hood with pre-configured optimizations. It works out of the box with vanilla JavaScript, TypeScript, React, Vue, Svelte, SolidJS, and most modern frameworks. Vite’s plugin system is compatible with Rollup plugins.
Instant Dev Server with ES Modules
Vite dev server leverages native ES module imports in the browser. Instead of bundling the entire app, Vite transforms a file only when the browser requests it. This means server startup is instant — no bundling, no parsing complete dependency graphs upfront.
Requests are transformed on-the-fly: TypeScript, JSX, Vue SFCs, and CSS are compiled per-file. Modules are cached and only re-transformed when they change. The browser’s cached ES module imports mean subsequent page loads are also fast.
# Start dev server
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev
# Output:
# VITE v6.0.0 ready in 245ms
# Local: http://localhost:5173/
# Even with 1000+ modules, Vite starts in ~200ms
# Traditional bundler with 1000+ modules: 5-30 seconds
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
}
}
}
});
Hot Module Replacement (HMR)
Vite’s HMR is fast because it invalidates only the exact module chain affected by a change. When you edit a file, Vite sends a WebSocket message to the browser with the updated module. The browser re-imports just that module, preserving application state.
Framework-specific HMR is handled by plugins: @vitejs/plugin-react (with React Fast Refresh), @vitejs/plugin-vue, and @sveltejs/vite-plugin-svelte. CSS HMR is instant.
// HMR API (in application code)
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Re-run when this module or its imports change
console.log('Module updated:', newModule);
});
import.meta.hot.dispose(() => {
// Cleanup when module is about to be replaced
console.log('Module being disposed');
});
// Decline HMR for this module
// import.meta.hot.decline();
}
// Vite's HMR respects the module graph
// Changing Counter.tsx only refreshes that component
// No full page reload, no state loss
// vite.config.js with SSR HMR
import { defineConfig } from 'vite';
export default defineConfig({
server: {
hmr: {
overlay: true, // Show errors as overlay
protocol: 'wss', // WebSocket secure
timeout: 3000,
}
}
});
Plugin System and Ecosystem
Vite plugins are based on Rollup’s plugin interface, extended with Vite-specific hooks. Plugins transform code, inject styles, optimize assets, and inject environment variables. @vitejs/plugin-react uses Babel for JSX transformation and React Fast Refresh.
Notable plugins: vite-plugin-pwa (service workers), vite-plugin-svgr (SVG as components), vite-plugin-mdx (MDX support), unplugin-auto-import, and unplugin-vue-components.
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import { VitePWA } from 'vite-plugin-pwa';
import Inspect from 'vite-plugin-inspect';
export default defineConfig({
plugins: [
react({
babel: {
plugins: ['babel-plugin-styled-components'],
},
}),
svgr({ svgrOptions: { icon: true } }),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'My App',
short_name: 'App',
start_url: '/',
display: 'standalone',
},
}),
Inspect(),
],
resolve: {
alias: {
'@': '/src',
'@components': '/src/components',
},
},
});
CSS and Asset Handling
Vite supports CSS imports, CSS modules (.module.css), PostCSS, and CSS preprocessors (SCSS, Less, Stylus). PostCSS is configured via postcss.config.js — Tailwind CSS works as a PostCSS plugin. CSS code splitting is automatic.
Asset imports return the hashed URL. Static assets in the public/ directory are served as-is. Vite optimizes images during production builds. The assetsInlineLimit option controls inlining small assets as base64.
// CSS imports (global)
import './styles/global.css';
// CSS Modules (scoped)
import styles from './Card.module.scss';
// PostCSS + Tailwind
// postcss.config.js
import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';
export default {
plugins: [tailwindcss, autoprefixer],
};
/* tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
// Asset imports
import logo from './assets/logo.svg?url';
import logoUrl from './assets/logo.svg';
import rawLogo from './assets/logo.svg?raw';
// JSON imports
import pkg from './package.json';
console.log(pkg.version);
// vite.config.js asset configuration
export default defineConfig({
build: {
assetsInlineLimit: 4096,
assetsDir: 'static',
cssCodeSplit: true,
},
});
Production Build Optimization
Vite’s production build uses Rollup with a pre-configured set of optimizations. Tree shaking removes dead code. Code splitting extracts shared dependencies into vendor chunks. CSS minification uses esbuild or lightning CSS. JavaScript minification uses esbuild or terser.
Manual chunks with the build.rollupOptions.output.manualChunks function let you fine-tune splitting. Preload directives generation is automatic. Dynamic imports are automatically code-split.
import { defineConfig } from 'vite';
export default defineConfig({
build: {
outDir: 'dist',
target: 'es2020',
minify: 'esbuild', // 'esbuild' (fast) or 'terser' (smaller)
cssMinify: 'lightningcss',
sourcemap: 'hidden',
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom', 'react-router-dom'],
ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
utils: ['date-fns', 'zod', 'zustand'],
},
},
},
chunkSizeWarningLimit: 500,
cssCodeSplit: true,
assetsInlineLimit: 4096,
},
optimizeDeps: {
include: ['react', 'react-dom', 'lodash-es'],
exclude: ['@large-lib/experimental'],
},
});
// npx vite build -> outputs to dist/
TypeScript, SSR, and Advanced Features
Vite supports TypeScript natively with esbuild transpilation. Vite’s SSR support handles React, Vue, and Svelte SSR through framework plugins. Library mode bundles a library instead of an application. Vite’s worker imports handle Web Workers.
The test integration with Vitest provides a Jest-compatible test runner built on Vite. vite-plugin-checker adds type checking in the dev server.
// SSR setup (basic)
// vite.config.js
export default defineConfig({
ssr: {
noExternal: ['some-dep'],
target: 'node',
},
});
// Library mode: vite.config.js
export default defineConfig({
build: {
lib: {
entry: './src/index.ts',
name: 'MyLib',
formats: ['es', 'cjs', 'umd'],
fileName: (format) => `my-lib.${format}.js`,
},
rollupOptions: {
external: ['react', 'react-dom'],
},
},
});
// Web Workers
const worker = new Worker(new URL('./worker.ts', import.meta.url));
worker.postMessage({ type: 'process', data: largeArray });
worker.onmessage = (event) => {
console.log('Result:', event.data);
};
// Vitest (vite.config.ts)
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: './test/setup.ts',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
});
Frequently Asked Questions
How does Vite compare to Create React App?
CRA is effectively deprecated. Vite offers faster dev startup (10-100x), HMR that’s instant even for large apps, and modern build optimizations.
Can Vite replace Webpack in production?
Yes. Vite’s production build uses Rollup, which produces smaller bundles than Webpack in most cases.
How does Vite’s HMR work?
Vite sends only the changed module to the browser via WebSocket. The browser re-imports the ES module. CSS changes apply instantly without any page reload.
Does Vite work with SSR frameworks?
Yes. Vite supports SSR for React (vike, vite-ssr), Vue (Nuxt uses Vite), and Svelte (SvelteKit uses Vite).
Originally published on Ayodhyyya. Last updated June 1, 2026.