Referensi cepat Vite build tool. Config, plugins, dev server, HMR, build optimization, SSR, library mode, environment variables, dan plugin API. Perfect buat frontend developer TypeScript.
Vite adalah build tool modern yang pakai native ES modules saat development dan Rollup untuk production build. Development server start hampir instan karena gak perlu bundle dulu. Berikut konsep inti yang perlu kamu pahami.
| Concept | Description |
|---|---|
| Dev Server | Serve modules on-demand via native ESM |
| HMR | Hot Module Replacement, update module tanpa full reload |
| Build | Production bundle dengan Rollup |
| Plugin | Extension yang hook ke Vite build pipeline |
| Optimize Deps | Pre-bundle dependencies pakai esbuild |
Bikin project Vite baru dengan template yang sesuai.
# Bikin project baru (interactive)
npm create vite@latest my-app
# Dengan template spesifik
npm create vite@latest my-app -- --template react-ts
npm create vite@latest my-app -- --template vue-ts
npm create vite@latest my-app -- --template vanilla-ts
npm create vite@latest my-app -- --template svelte-ts
# Templates yang tersedia:
# vanilla, vanilla-ts
# vue, vue-ts
# react, react-ts
# preact, preact-ts
# lit, lit-ts
# svelte, svelte-ts
# solid, solid-ts
# Jalankan dev server
npm run dev
# Build untuk production
npm run build
# Preview build production
npm run previewFile konfigurasi utama Vite. Semua pengaturan dev server, build, dan plugins ada di sini.
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
root: '.',
base: '/',
publicDir: 'public',
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@utils': path.resolve(__dirname, './src/utils'),
},
},
server: {
port: 3000,
open: true,
host: true,
cors: true,
},
build: {
outDir: 'dist',
sourcemap: true,
target: 'es2020',
minify: 'esbuild',
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash-es', 'date-fns'],
},
},
},
},
});Kamu bisa return function dari defineConfig untuk konfigurasi yang berbeda antara dev dan build.
import { defineConfig } from 'vite';
export default defineConfig(({ command, mode }) => {
if (command === 'serve') {
// Dev server config
return {
server: {
port: 3000,
},
};
} else {
// Build config
return {
build: {
outDir: 'dist',
},
};
}
});| Variable | Description |
|---|---|
command | serve saat dev, build saat build |
mode | development, production, atau custom |
isSsrBuild | true saat SSR build |
isPreview | true saat preview command |
Plugin extend kemampuan Vite. Beberapa plugin populer:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import vue from '@vitejs/plugin-vue';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import tailwindcss from '@tailwindcss/vite';
import { visualizer } from 'rollup-plugin-visualizer';
import { VitePWA } from 'vite-plugin-pwa';
import compression from 'vite-plugin-compression';
import mkcert from 'vite-plugin-mkcert';
export default defineConfig({
plugins: [
react(),
// vue(),
// svelte(),
tailwindcss(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'My App',
short_name: 'MyApp',
},
}),
compression({
algorithm: 'gzip',
ext: '.gz',
}),
visualizer({
open: true,
filename: 'stats.html',
}),
mkcert(), // HTTPS untuk localhost
],
});| Plugin | Description |
|---|---|
@vitejs/plugin-react | Fast Refresh untuk React |
@vitejs/plugin-vue | Vue SFC support |
@tailwindcss/vite | Tailwind CSS v4 integration |
vite-plugin-pwa | Service Worker dan PWA |
vite-plugin-compression | Gzip dan Brotli output |
rollup-plugin-visualizer | Visualisasi bundle size |
vite-plugin-mkcert | Local HTTPS certificate |
vite-plugin-svg-icons | SVG sprite dari folder |
Dev server Vite sangat cepat karena pakai native ESM. HMR update module secara targeted tanpa reload halaman.
// vite.config.ts
export default defineConfig({
server: {
port: 3000,
open: true,
host: '0.0.0.0', // expose ke network
https: true, // HTTPS di dev
strictPort: true, // error kalau port dipakai
// HMR config
hmr: {
protocol: 'ws',
host: 'localhost',
port: 3001,
clientPort: 3000,
},
// Watch options
watch: {
ignored: ['**/node_modules/**', '**/dist/**'],
},
},
});Komponen bisa accept HMR updates untuk hot reload yang targeted.
// React component dengan HMR (via @vitejs/plugin-react sudah otomatis)
import { useEffect } from 'react';
// Vanilla JS HMR
export function setupCounter(element: HTMLButtonElement) {
let counter = 0;
const setCounter = (count: number) => {
counter = count;
element.innerHTML = `count is ${counter}`;
};
element.addEventListener('click', () => setCounter(counter + 1));
setCounter(0);
}
// HMR accept manual
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
console.log('Module updated', newModule);
});
// Cleanup sebelum dispose
import.meta.hot.dispose(() => {
console.log('Module disposed, cleanup resources');
});
// Persist state across HMR
const data = import.meta.hot.data;
data.count ??= 0;
}Proxy berguna untuk avoid CORS issues saat development. Request ke API di-forward ke backend server.
// vite.config.ts
export default defineConfig({
server: {
proxy: {
// String shorthand
'/api': 'http://localhost:8080',
// Dengan options
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, ''),
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log('Proxying:', req.url);
});
},
},
// WebSocket proxy
'/socket.io': {
target: 'ws://localhost:8080',
ws: true,
},
},
},
});| Option | Description |
|---|---|
target | URL backend tujuan |
changeOrigin | Ubah Host header ke target URL |
rewrite | Modify path sebelum forward |
ws | Enable WebSocket proxying |
secure | Verify SSL certificate target |
bypass | Function untuk skip proxy |
Vite expose environment variables via import.meta.env. Hanya variables dengan prefix VITE_ yang di-expose ke client.
# .env
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My App
# .env.development
VITE_API_URL=http://localhost:8080
# .env.production
VITE_API_URL=https://api.example.com
# .env.staging
VITE_API_URL=https://staging-api.example.com// Akses di code
console.log(import.meta.env.VITE_API_URL);
console.log(import.meta.env.VITE_APP_TITLE);
// TypeScript type safety
// src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_APP_TITLE: string;
readonly VITE_DEBUG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}| Variable | Description |
|---|---|
import.meta.env.MODE | Mode saat ini (development, production) |
import.meta.env.BASE_URL | Base URL public saat deploy |
import.meta.env.PROD | true saat production |
import.meta.env.DEV | true saat development |
import.meta.env.SSR | true saat server-side build |
import.meta.env.VITE_* | Custom env variables |
| File | Kapan dipakai |
|---|---|
.env | Selalu dimuat |
.env.local | Selalu dimuat, di-ignore git |
.env.[mode] | Hanya saat mode match |
.env.[mode].local | Mode-specific, di-ignore git |
Vite pakai Rollup untuk production build. Berbagai strategi optimasi tersedia.
// vite.config.ts
export default defineConfig({
build: {
target: 'es2020', // Target browser JS
outDir: 'dist',
sourcemap: 'hidden', // Source maps tersembunyi
minify: 'esbuild', // esbuild (cepat) atau terser (lebih kecil)
cssCodeSplit: true, // Split CSS per chunk
assetsInlineLimit: 4096, // Inline asset < 4KB sebagai base64
chunkSizeWarningLimit: 500,
reportCompressedSize: true,
rollupOptions: {
input: {
main: 'index.html',
admin: 'admin.html',
},
output: {
// Manual chunking
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('react')) return 'react-vendor';
if (id.includes('lodash')) return 'lodash-vendor';
return 'vendor';
}
},
// Asset naming
chunkFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
entryFileNames: 'assets/js/[name]-[hash].js',
},
// External dependencies (untuk library mode)
external: ['react', 'react-dom'],
},
},
// Performance hints
esbuild: {
drop: ['console', 'debugger'], // Hapus console.log di production
legalComments: 'none',
},
});| Strategy | Description |
|---|---|
| Manual Chunks | Pisahkan vendor code ke file terpisah |
| Code Splitting | Lazy load routes dengan dynamic import |
| Asset Inline | Inline asset kecil sebagai base64 |
| CSS Split | Pisahkan CSS per chunk |
| Minify | esbuild (cepat) atau terser (lebih agresif) |
// Lazy load route
const AdminDashboard = lazy(() => import('./pages/AdminDashboard'));
// Prefetch saat idle
const button = document.querySelector('#load-chart');
button?.addEventListener('click', () => {
import('./chart').then((module) => {
module.renderChart();
});
});
// Preload critical chunks
const link = document.createElement('link');
link.rel = 'modulepreload';
link.href = '/assets/critical.js';
document.head.appendChild(link);Vite pre-bundle dependencies pakai esbuild untuk konversi CJS ke ESM dan reduce number of requests.
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: ['lodash-es', 'date-fns'],
exclude: ['my-local-package'],
esbuildOptions: {
target: 'es2020',
define: {
global: 'globalThis',
},
},
},
});| Option | Description |
|---|---|
include | Force pre-bundle dependency |
exclude | Exclude dari pre-bundling |
entries | Custom entry points untuk scanning |
Vite bisa build library yang publishable ke npm. Output bisa ESM, CJS, atau UMD.
// vite.config.ts
import { resolve } from 'path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'MyLib',
fileName: (format) => `my-lib.${format}.js`,
formats: ['es', 'cjs', 'umd'],
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
},
},
plugins: [
dts({
insertTypesEntry: true,
}),
],
});// package.json untuk library
{
"name": "my-lib",
"version": "1.0.0",
"type": "module",
"main": "./dist/my-lib.cjs.js",
"module": "./dist/my-lib.es.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/my-lib.es.js",
"require": "./dist/my-lib.cjs.js",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"]
}Vite punya built-in middleware untuk SSR development.
// vite.config.ts
export default defineConfig({
server: {
ssr: {
external: ['express'], // Pakai saat SSR
},
},
ssr: {
noExternal: ['my-component-lib'], // Bundle lib ini untuk SSR
},
});
// SSR development dengan middleware
import { createServer } from 'vite';
import express from 'express';
async function createApp() {
const app = express();
const vite = await createServer({
server: { middlewareMode: true },
appType: 'custom',
});
app.use(vite.middlewares);
app.use('*', async (req, res) => {
const template = await vite.transformIndexHtml(
req.originalUrl,
fs.readFileSync('./index.html', 'utf-8')
);
const { render } = await vite.ssrLoadModule('/src/entry-server.tsx');
const appHtml = await render(req.url);
const html = template.replace('<!--app-html-->', appHtml);
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
});
app.listen(3000);
}| SSR Concept | Description |
|---|---|
vite.ssrLoadModule() | Load module untuk SSR di dev |
vite.transformIndexHtml() | Transform HTML dengan HMR client |
ssr.external | Pakai versi Node untuk lib ini |
ssr.noExternal | Bundle lib ini untuk SSR |
Kamu bisa bikin plugin Vite sendiri. Plugin punya hooks untuk berbagai tahap build.
import type { Plugin, PluginOption } from 'vite';
function myPlugin(options: { msg: string }): Plugin {
return {
name: 'my-plugin',
// Hook lifecycle
config(config, { command }) {
console.log('Config resolved');
return {
// Merge config
};
},
configResolved(resolvedConfig) {
console.log('Final config', resolvedConfig);
},
options(rollupOptions) {
console.log('Rollup options');
},
buildStart() {
console.log('Build started', options.msg);
},
transform(code, id) {
// Transform source code
if (id.endsWith('.md')) {
return convertMarkdownToJs(code);
}
},
transformIndexHtml(html) {
// Modify index.html
return html.replace('</head>', '<script>injected</script></head>');
},
configureServer(server) {
// Custom dev server middleware
server.middlewares.use('/api/custom', (req, res) => {
res.end(JSON.stringify({ hello: 'world' }));
});
},
load(id) {
// Virtual modules
if (id === 'virtual:my-module') {
return 'export default "hello"';
}
},
buildEnd() {
console.log('Build finished');
},
};
}
// Pakai plugin
export default defineConfig({
plugins: [myPlugin({ msg: 'Hello' })],
});| Hook | Description |
|---|---|
config | Modify atau extend Vite config |
configResolved | Akses final resolved config |
buildStart | Dipanggil saat build mulai |
transform | Transform source code per file |
transformIndexHtml | Modify HTML entry |
configureServer | Custom dev server logic |
load | Resolve dan load module |
resolveId | Custom module resolution |
buildEnd | Dipanggil saat build selesai |
closeBundle | Dipanggil setelah semua bundles selesai |
Vite support CSS modules, preprocessor, dan PostCSS out of the box.
// vite.config.ts
export default defineConfig({
css: {
modules: {
// Generate class names
generateScopedName: '[name]__[local]___[hash:base64:5]',
localsConvention: 'camelCase',
},
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`,
},
less: {
javascriptEnabled: true,
},
},
postcss: {
plugins: [
// Atau pakai postcss.config.js
],
},
devSourcemap: true,
},
});// CSS Modules
import styles from './button.module.css';
export function Button() {
return `<button class="${styles.btn}">Click</button>`;
}// Import asset sebagai URL
import imgUrl from './assets/logo.png';
// imgUrl => '/assets/logo.2h3k4j.png'
// Import asset sebagai string
import svgString from './icon.svg?raw';
// Import sebagai Web Worker
import MyWorker from './worker?worker';
const worker = new MyWorker();
// Import dengan inline query
import logo from './logo.png?inline'; // Selalu inline sebagai base64
import wasmUrl from './module.wasm?url';Vite gak melakukan type checking saat build. Pakai tsc atau vue-tsc secara terpisah.
// package.json
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
}
}// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": ["vite/client"]
},
"include": ["src"]
}| Term | Definition |
|---|---|
| Base URL | Path prefix untuk public assets |
| Chunk | Bagian dari bundle output |
| Code Splitting | Memecah bundle ke lazy-loaded chunks |
| Dependency Pre-bundling | Pre-process node_modules dengan esbuild |
| HMR | Hot Module Replacement, update tanpa full reload |
| Library Mode | Build output sebagai library yang publishable |
| Manual Chunks | Custom split vendor code ke file terpisah |
| Optimize Deps | Pre-bundling dependencies untuk dev cepat |
| Plugin | Extension yang hook ke build pipeline |
| Rollup | Bundler yang dipakai untuk production build |
| SSR | Server-Side Rendering |
| Transform | Hook untuk modify source code per file |
| VITE_ | Prefix untuk env variables yang di-expose ke client |
Happy coding dengan Vite! ⚡
Login atau daftar akun gratis untuk membaca cheat sheet ini.