1. Pengenalan Vite
Vite (dibaca "veet", bahasa Prancis untuk "cepat") adalah build tool generasi baru yang dikembangkan oleh Evan You (pencipta Vue.js). Vite menggabungkan development server berbasis ESM yang ultra-cepat dengan Rollup-based production build yang sangat teroptimasi.
Sebelum Vite, tool seperti Webpack membutuhkan waktu berdetik-sampai-menit untuk mem-bundle seluruh aplikasi sebelum development server bisa dimulai. Vite mengubah paradigma ini: ia menggunakan native ES Modules di browser, sehingga server bisa dimulai dalam hitungan milidetik, dan perubahan file di-refleksikan ke browser hampir seketika.
Mengapa Vite Sangat Cepat?
| Keunggulan | Penjelasan |
|---|---|
| ESM Dev Server | Browser memuat modul langsung via native ES Modules β tidak perlu bundling saat development |
| On-demand Compilation | Hanya file yang di-request yang dikompilasi β bukan seluruh proyek |
| Instant HMR | Hot Module Replacement bekerja dalam milidetik, tidak peduli seberapa besar proyek |
| esbuild | Pre-bundling dependencies menggunakan esbuild (ditulis di Go, 10-100x lebih cepat dari JS bundler) |
| Rollup Production | Build produksi menggunakan Rollup β bundler yang mature dan teroptimasi |
| Framework Agnostic | Template untuk React, Vue, Svelte, Lit, Preact, Solid, Vanilla JS, dan lainnya |
Vite vs Webpack vs Parcel
| Aspek | Vite | Webpack | Parcel |
|---|---|---|---|
| Dev Server Start | β‘ ~300ms | π ~10-30 detik | π‘ ~5-10 detik |
| HMR Speed | β‘ ~10ms | π‘ ~100-500ms | π‘ ~100ms |
| Config Complexity | π’ Minimal | π΄ Rumit | π’ Zero-config |
| Bundle Tool | Rollup (prod) | Webpack sendiri | SWC/Rust |
| Pre-bundling | esbuild (Go) | Tidak ada | Tidak ada |
| Native ESM | β Ya | β Tidak | β Tidak |
| Legacy Support | Plugin | Built-in | Built-in |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β VITE ARCHITECTURE β β β β ββββ DEVELOPMENT ββββββββββββββββββββββββββββββββ β β β β β β β Browser Vite Dev Server β β β β ββββββββββ ββββββββββββββββββββ β β β β βmain.js ββESM reqβββ β esbuild pre-bundlβ β β β β β(native)β β dependencies β β β β β ββββββββββ ββββββββββββββββββββ β β β β β β β β β β β βββββββββββββββββββββββ β β β β β βΌ β β β β ββββββββββββββββββββββββ β β β β β Native ESM serving β β Transform on- β β β β β β’ .vue β compiled β demand (bukan β β β β β β’ .ts β JS β bundling semua) β β β β β β’ .jsx β JS β β β β β β β’ .css β injected β β β β β ββββββββββββββββββββββββ β β β β β β β β β HMR WebSocket β perubahan file real-time β β β βββββββββββββββββββββββββββββββββββββββββββββββββ β β β β ββββ PRODUCTION βββββββββββββββββββββββββββββββββ β β β β β β β Source Files β Rollup Bundle β dist/ β β β β β’ Tree shaking β β β β β’ Code splitting β β β β β’ Minification β β β β β’ Asset optimization β β β β β’ CSS extraction β β β βββββββββββββββββββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Setup & Quick Start
Vite sangat mudah di-setup. Dengan satu perintah, Anda bisa membuat proyek baru dengan template untuk framework favorit Anda.
# ====== Buat proyek Vite baru ====== # Dengan npm npm create vite@latest belajar-vite # Dengan yarn yarn create vite belajar-vite # Dengan pnpm pnpm create vite belajar-vite # Dengan bun bun create vite belajar-vite # ====== Pilih template saat wizard ====== # β Select a framework: # β Vanilla β JavaScript murni tanpa framework # β Vue β Vue.js # β React β React.js # β Preact β Preact (React alternatif ringan) # β Lit β Lit (Web Components) # β Svelte β Svelte # β Solid β SolidJS # β Qwik β Qwik # β Select a variant: # β JavaScript # β TypeScript # ====== Atau langsung tentukan template ====== npm create vite@latest belajar-vite -- --template react-ts npm create vite@latest belajar-vite -- --template vue npm create vite@latest belajar-vite -- --template svelte npm create vite@latest belajar-vite -- --template vanilla-ts # ====== Jalankan proyek ====== cd belajar-vite npm install npm run dev # Output: # VITE v5.x ready in 300 ms # # β Local: http://localhost:5173/ # β Network: http://192.168.1.x:5173/ # β press h + enter to show help # ====== Commands yang tersedia ====== npm run dev # Development server dengan HMR npm run build # Build untuk production (output ke dist/) npm run preview # Preview hasil build secara lokal
Struktur Proyek Vite
belajar-vite/ βββ node_modules/ βββ public/ β File statis (copy langsung ke dist/) β βββ vite.svg β Tidak di-transform oleh Vite βββ src/ β Source code (di-process oleh Vite) β βββ assets/ β Asset yang di-import (di-optimasi) β β βββ react.svg β βββ components/ β Komponen UI β β βββ Counter.jsx β βββ styles/ β CSS/SCSS files β β βββ index.css β βββ App.jsx β Root component β βββ main.jsx β Entry point β βββ vite-env.d.ts β TypeScript declarations βββ index.html β Entry HTML (Vite meng-inject script) βββ vite.config.js β Konfigurasi Vite βββ package.json βββ tsconfig.json β (jika TypeScript) βββ .gitignore
Entry Point & Index HTML
<!-- index.html β di root proyek, BUKAN di dalam src/ --> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Belajar Vite</title> <!-- Vite otomatis meng-inject CSS & JS yang dibutuhkan --> </head> <body> <div id="root"></div> <!-- Entry point: Vite akan memproses script module ini --> <script type="module" src="/src/main.jsx"></script> </body> </html> <!-- Perbedaan dengan Webpack: β’ Di Webpack: index.html sering di dalam src/, di-generate oleh HtmlWebpackPlugin β’ Di Vite: index.html di root, langsung di-edit, dan Vite me-resolve semua dependency -->
// ====== src/main.jsx ======
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import './styles/index.css';
// Import asset β Vite akan menangani hashing, optimasi, dll.
import logoUrl from './assets/logo.svg';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>
);
// Vite mendukung berbagai jenis import:
import styles from './module.module.css'; // CSS Modules
import Worker from './worker.js?worker'; // Web Worker
import data from './data.json'; // JSON import
import rawSvg from './icon.svg?raw'; // Raw string import
import imgUrl from './photo.jpg?url'; // URL string import
3. Hot Module Replacement (HMR)
Hot Module Replacement (HMR) adalah fitur yang memungkinkan Anda mengedit kode dan melihat perubahan di browser tanpa full page reload. Vite menyediakan HMR yang sangat cepat β biasanya dalam 10-50 milidetik. HMR mempertahankan state aplikasi saat Anda mengedit, sehingga proses development menjadi sangat mulus.
HMR di Berbagai Framework
// ====== HMR di React (via Vite plugin) ======
// React Refresh otomatis aktif dengan @vitejs/plugin-react
// Edit komponen β state TIDAK hilang (kecuali hook order berubah)
// Component lifecycle: unmount lama β mount baru dengan state yang sama
// ====== HMR di Vue (via @vitejs/plugin-vue) ======
// Vue SFC otomatis mendapat HMR
// <template> changes β re-render tanpa unmount (state dipertahankan)
// <script> changes β component full re-mount
// <style> changes β style injection tanpa re-render
// ====== Manual HMR API (vanilla JS / custom modules) ======
// Cek apakah HMR aktif (selalu true di dev, false di production)
if (import.meta.hot) {
// Terima update untuk modul ini sendiri
import.meta.hot.accept((newModule) => {
// Modul ini baru saja di-update
console.log('Modul diperbarui:', newModule);
// Jalankan ulang logika yang diperlukan
});
// Terima update dari modul tertentu
import.meta.hot.accept('./utils.js', (newUtils) => {
console.log('Utils diperbarui:', newUtils);
// Gunakan newUtils yang baru
});
// Terima update dari modul dependencies (tanpa self-accept)
import.meta.hot.accept('./renderer.js', (newRenderer) => {
newRenderer.render(); // Re-render dengan modul baru
});
// Cleanup: bersihkan side effects saat modul di-unmount
import.meta.hot.dispose((data) => {
// data.persisted = objek yang akan dikirim ke versi baru modul
clearInterval(myTimer);
socket.close();
// Simpan state yang perlu dipertahankan
data.counter = currentCount;
});
// Terima data dari versi modul sebelumnya
if (import.meta.hot.data.counter) {
currentCount = import.meta.hot.data.counter;
}
// Paksa full reload jika ada error yang tidak bisa di-recover
import.meta.hot.on('vite:error', (err) => {
console.error('Vite HMR error:', err);
});
// Decline HMR: minta full page reload jika modul ini berubah
import.meta.hot.decline();
}
HMR untuk CSS & Asset
/* ====== CSS HMR ====== */
/* Semua perubahan CSS langsung di-inject tanpa reload */
/* Global CSS β import di main.js */
/* src/styles/global.css */
body {
font-family: system-ui, sans-serif;
background: #1e1e2e;
color: #cdd6f4;
}
/* CSS Modules β HMR dengan state pertahankan */
/* src/components/Button.module.css */
.button {
padding: 10px 20px;
border-radius: 8px;
background: var(--primary, #6366f1);
}
.button:hover {
background: var(--primary-hover, #4f46e5);
}
/* ====== SCSS/LESS HMR ====== */
/* Preprocessor langsung didukung, install preprocessor-nya: */
// npm install -D sass
// npm install -D less
/* src/styles/main.scss */
$primary: #6366f1;
$radius: 8px;
.card {
background: $primary;
border-radius: $radius;
}
// ====== CSS HMR behavior:
// β’ Perubahan style β instant injection (tidak reload)
// β’ Tambah/hapus CSS rules β instant injection
// β’ CSS Module changes β re-render komponen yang menggunakan
// β’ PostCSS transforms β instant
4. Konfigurasi Vite
Vite dikonfigurasi melalui file vite.config.js (atau .ts, .mjs). Konfigurasi Vite sederhana dan intuitif β sebagian besar proyek hanya memerlukan sedikit pengaturan.
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
// https://vitejs.dev/config/
export default defineConfig({
// ====== Plugins ======
plugins: [
react(),
],
// ====== Path Resolution ======
resolve: {
alias: {
// Alias @ ke folder src
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@assets': path.resolve(__dirname, 'src/assets'),
},
// Ekstensi file yang otomatis di-resolve
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
},
// ====== Development Server ======
server: {
port: 5173, // Port dev server
host: true, // Expose ke network (0.0.0.0)
open: true, // Buka browser otomatis
https: false, // Gunakan HTTPS (self-signed cert)
cors: true, // Enable CORS
// Proxy API β redirect request ke backend
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/socket.io': {
target: 'ws://localhost:3000',
ws: true,
},
},
// HMR config
hmr: {
overlay: true, // Tampilkan error overlay di browser
port: 24678, // Port HMR WebSocket (opsional)
},
// Watch config
watch: {
ignored: ['**/node_modules/**', '**/.git/**'],
},
},
// ====== Build Options ======
build: {
outDir: 'dist', // Output directory
assetsDir: 'assets', // Subdirectory untuk generated assets
sourcemap: false, // Generate source maps?
minify: 'esbuild', // 'esbuild' | 'terser' | false
target: 'es2020', // Target browser support
cssCodeSplit: true, // Split CSS per chunk?
// Rollup options
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
},
output: {
// Manual chunk splitting untuk optimasi caching
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-utils': ['lodash-es', 'date-fns'],
},
},
},
// Asset handling
assetsInlineLimit: 4096, // Inline asset < 4KB as base64
},
// ====== CSS Options ======
css: {
modules: {
localsConvention: 'camelCase', // CSS Module naming
},
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`,
},
},
postcss: '', // Path to postcss config atau inline config
devSourcemap: true,
},
// ====== Preview Server (npm run preview) ======
preview: {
port: 4173,
host: true,
open: true,
},
});
5. Vite Plugins
Ekosistem plugin Vite sangat kaya. Plugin Vite memanfaatkan hook API yang didesain berdasarkan Rollup, sehingga plugin Rollup juga kompatibel dengan Vite. Berikut plugin-plugin yang paling sering digunakan.
# ====== Instal plugin yang dibutuhkan ====== npm install -D @vitejs/plugin-react # React + Fast Refresh npm install -D @vitejs/plugin-vue # Vue 3 SFC npm install -D @sveltejs/vite-plugin-svelte # Svelte npm install -D vite-plugin-svgr # SVG as React component npm install -D vite-plugin-checker # Type checking di dev npm install -D unplugin-auto-import # Auto import npm install -D unplugin-icons # Icons as components npm install -D vite-plugin-pwa # Progressive Web App npm install -D vite-plugin-compression # Gzip/Brotli compression npm install -D rollup-plugin-visualizer # Bundle visualizer
// vite.config.js β Plugin yang sering digunakan
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import checker from 'vite-plugin-checker';
import autoImport from 'unplugin-auto-import/vite';
import compression from 'vite-plugin-compression';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
// ====== 1. Framework Plugin ======
react({
// Fast Refresh untuk React
fastRefresh: true,
// JSX runtime: 'automatic' (default) atau 'classic'
jsxRuntime: 'automatic',
}),
// ====== 2. SVG as React Component ======
svgr({
svgrOptions: {
icon: true,
dimensions: false,
},
}),
// import LogoIcon from './logo.svg?react';
//
// ====== 3. Type Checking ======
checker({
typescript: true,
eslint: {
lintCommand: 'eslint "./src/**/*.{ts,tsx}"',
},
overlay: {
position: 'tl',
initialIsOpen: false,
},
}),
// ====== 4. Auto Import ======
autoImport({
imports: [
'react', // auto import: useState, useEffect, useCallback, dll.
'react-router-dom',
],
dts: './src/auto-imports.d.ts', // Generate TypeScript declarations
dirs: [
'./src/hooks', // Auto import custom hooks
'./src/utils', // Auto import utility functions
],
}),
// ====== 5. Compression ======
compression({
algorithm: 'gzip',
ext: '.gz',
}),
compression({
algorithm: 'brotliCompress',
ext: '.br',
}),
// ====== 6. Bundle Analyzer ======
visualizer({
open: true,
gzipSize: true,
filename: 'bundle-analysis.html',
}),
],
});
Membuat Custom Plugin
// ====== Plugin untuk transformasi custom ======
function myCustomPlugin(options = {}) {
return {
// Nama plugin (wajib)
name: 'vite-plugin-my-custom',
// Plugin hooks yang bisa digunakan:
// 1. transformIndexHtml β modifikasi index.html
transformIndexHtml(html) {
return html.replace(
'<title>',
'<title>' + (options.titlePrefix || '')
);
},
// 2. configResolved β baca resolved config
configResolved(config) {
console.log('Mode:', config.mode);
console.log('Root:', config.root);
},
// 3. configureServer β tambah middleware ke dev server
configureServer(server) {
server.middlewares.use('/api/custom', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'Hello from plugin!' }));
});
},
// 4. transform β transform source code
transform(code, id) {
// Hanya proses .js/.ts files di src/
if (!id.includes('src/') || !id.match(/\.(js|ts|jsx|tsx)$/)) return;
// Contoh: ganti __BUILD_DATE__ dengan tanggal build
if (code.includes('__BUILD_DATE__')) {
return code.replace(
/__BUILD_DATE__/g,
JSON.stringify(new Date().toISOString())
);
}
},
// 5. handleHotUpdate β custom HMR handling
handleHotUpdate({ file, server, modules }) {
if (file.endsWith('.data.json')) {
// Khusus file data: trigger full reload
server.ws.send({ type: 'full-reload' });
return []; // Prevent default HMR
}
},
// 6. buildStart / buildEnd
buildStart() {
console.log('Build dimulai...');
},
buildEnd() {
console.log('Build selesai!');
},
};
}
// ====== Menggunakan plugin ======
// vite.config.js
export default defineConfig({
plugins: [
myCustomPlugin({ titlePrefix: 'BeebaneLabs β ' }),
],
});
6. Optimasi & Build
Vite menggunakan Rollup untuk production build, yang menghasilkan bundle yang sangat teroptimasi. Selain itu, Vite juga menggunakan esbuild untuk pre-bundling dependencies (mempercepat dev) dan minification (menggantikan Terser yang lebih lambat).
Pre-bundling dengan esbuild
// ====== Pre-bundling: Apa dan Mengapa ======
// Saat pertama kali npm run dev, Vite mem-bundle dependencies
// menggunakan esbuild. Ini karena:
//
// 1. Mengurangi HTTP requests β CJS/UMD modules menjadi ESM
// Contoh: lodash punya 600+ file β menjadi 1 file ESM
//
// 2. Menghindari ratusan modul request
// Browser tidak perlu request 600+ file terpisah
//
// 3. Caching β pre-bundled deps disimpan di node_modules/.vite
// ====== Konfigurasi Pre-bundling ======
// vite.config.js
export default defineConfig({
optimizeDeps: {
// Eksplisit include dependencies yang perlu di-prebundle
// Berguna untuk dependency yang tidak terdeteksi otomatis
include: [
'react',
'react-dom',
'lodash-es',
'date-fns/format',
'axios',
],
// Exclude dependencies dari pre-bundling
// Berguna untuk library yang sudah ESM atau perlu dimuat utuh
exclude: [
'your-local-package', // Monorepo package
],
// Force re-bundle (jika ada masalah cache)
// force: true,
},
});
// ====== Build Optimization ======
// vite.config.js
export default defineConfig({
build: {
// Target browser β tentukan compatibility level
target: 'es2020', // Bisa: 'es2015', 'es2017', 'es2020', 'esnext'
// Minification
minify: 'esbuild', // 'esbuild' (cepat) | 'terser' (lebih agresif) | false
// CSS code splitting
cssCodeSplit: true,
// Source maps
sourcemap: false, // 'true' | 'false' | 'inline' | 'hidden'
// Asset handling
assetsInlineLimit: 4096, // Bytes β inline kecil sebagai base64
// Chunk size warnings
chunkSizeWarningLimit: 500, // KB
// Rollup output options
rollupOptions: {
output: {
// Manual chunks β pecah vendor ke file terpisah
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('react')) return 'vendor-react';
if (id.includes('lodash')) return 'vendor-lodash';
if (id.includes('date-fns')) return 'vendor-date';
return 'vendor'; // Semua vendor lainnya
}
},
// File naming pattern
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash][extname]',
},
},
},
});
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β VITE BUILD PIPELINE β β β β SOURCE CODE β β βββββββββββββββ β β β src/**/* β .jsx, .ts, .vue, .svelte, .css β β ββββββββ¬βββββββ β β βΌ β β ββββββββββββββββ β β β Vite Plugin β Transform: .vueβJS, .tsβJS, dll β β β Transforms β CSS Modules, PostCSS, SCSS β β ββββββββ¬ββββββββ β β βΌ β β ββββββββββββββββ β β β Rollup β Build: module graph resolution β β β Bundler β Tree shaking, dead code removal β β ββββββββ¬ββββββββ β β βΌ β β ββββββββββββββββ β β β Code Split β Manual chunks + automatic splits β β β β Dynamic import β separate chunks β β ββββββββ¬ββββββββ β β βΌ β β ββββββββββββββββ β β β Minificationβ esbuild (default) atau terser β β β + Compress β CSS minification β β ββββββββ¬ββββββββ β β βΌ β β OUTPUT: dist/ β β βββ index.html β β βββ assets/ β β βββ main-abc123.js (app code) β β βββ vendor-def456.js (dependencies) β β βββ index-ghi789.css (styles) β β βββ logo-jkl012.svg (assets) β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
7. Environment Variables
Vite menggunakan .env files untuk environment variables dengan beberapa aturan penting tentang keamanan dan exposure ke client.
// ====== .env Files ======
// Vite memuat .env files berdasarkan mode:
//
// .env β Selalu dimuat
// .env.local β Selalu dimuat, di-gitignore
// .env.[mode] β Hanya dimuat di mode tertentu
// .env.[mode].local β Hanya dimuat di mode, di-gitignore
// ====== .env ======
VITE_APP_TITLE=BeebaneLabs Tutorial
VITE_API_BASE_URL=https://api.example.com
SECRET_KEY=rahasia123 // β TIDAK di-expose ke client!
// ====== .env.development ======
VITE_API_BASE_URL=http://localhost:3000
VITE_DEBUG=true
// ====== .env.production ======
VITE_API_BASE_URL=https://api.example.com
VITE_DEBUG=false
// ====== Aturan penting: ======
// β’ Hanya variabel yang diawali VITE_ yang di-expose ke client code
// β’ SECRET_KEY TIDAK bisa diakses dari browser (aman!)
// β’ VITE_API_URL BISA diakses dari browser (sengaja di-expose)
// ====== Menggunakan di kode ======
console.log(import.meta.env.VITE_APP_TITLE); // "BeebaneLabs Tutorial"
console.log(import.meta.env.VITE_API_BASE_URL); // Sesuai mode
console.log(import.meta.env.VITE_DEBUG); // "true" atau "false"
// Built-in variables
console.log(import.meta.env.MODE); // 'development' atau 'production'
console.log(import.meta.env.BASE_URL); // '/' (sesuai base config)
console.log(import.meta.env.PROD); // true/false
console.log(import.meta.env.DEV); // true/false
console.log(import.meta.env.SSR); // true/false (saat SSR)
// ====== Type safety untuk TypeScript ======
// src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string;
readonly VITE_API_BASE_URL: string;
readonly VITE_DEBUG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// ====== Mengganti env di CLI ======
// Development mode (default):
// npm run dev β mode: 'development'
// Production build:
// npm run build β mode: 'production'
// Custom mode:
// npm run build -- --mode staging β mode: 'staging'
// Akan memuat: .env, .env.staging
// ====== Menggunakan dalam vite.config.js ======
import { loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// Load env untuk mode saat ini
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [react()],
server: {
port: Number(env.PORT) || 5173,
},
define: {
__APP_VERSION__: JSON.stringify(env.npm_package_version),
},
};
});
8. Server-Side Rendering (SSR)
Vite menyediakan API SSR bawaan yang memungkinkan framework seperti SvelteKit, Nuxt, dan Astro membangun SSR di atas Vite. SSR merender HTML di server terlebih dahulu, lalu mengirim HTML lengkap ke browser β meningkatkan SEO dan initial load time.
// ====== Manual SSR Setup dengan Vite ======
// server.js β Production SSR server
import express from 'express';
import { createServer as createViteServer } from 'vite';
const isProd = process.env.NODE_ENV === 'production';
async function createServer() {
const app = express();
let vite;
if (!isProd) {
// Development: gunakan Vite dev server sebagai middleware
vite = await createViteServer({
server: { middlewareMode: true },
appType: 'spa', // atau 'custom' untuk SSR manual
});
app.use(vite.middlewares);
} else {
// Production: serve static files
const { default: sirv } = await import('sirv');
app.use(sirv('dist/client', { gzip: true }));
}
// SSR middleware
app.use('*', async (req, res) => {
try {
const url = req.originalUrl;
let template, render;
if (!isProd) {
// Development: baca index.html dan transform
template = await vite.transformIndexHtml(url,
fs.readFileSync('index.html', 'utf-8')
);
// Load SSR entry point (tanpa bundle, langsung ESM)
render = (await vite.ssrLoadModule('/src/entry-server.js')).render;
} else {
// Production: baca build output
template = fs.readFileSync('dist/client/index.html', 'utf-8');
render = (await import('./dist/server/entry-server.js')).render;
}
// Render app ke HTML string
const appHtml = await render(url);
// Inject rendered HTML ke template
const html = template.replace('<!--ssr-outlet-->', appHtml);
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
} catch (e) {
vite?.ssrFixStacktrace(e);
console.error(e);
res.status(500).end(e.message);
}
});
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
}
createServer();
// ====== entry-server.js (React SSR) ======
import { renderToString } from 'react-dom/server';
import App from './App';
export function render(url) {
return renderToString(<App url={url} />);
}
// ====== entry-client.js (Hydration) ======
import { hydrateRoot } from 'react-dom/client';
import App from './App';
hydrateRoot(document.getElementById('root'), <App />);
9. Teknik Lanjutan
Berikut beberapa teknik dan fitur lanjutan Vite yang membantu dalam pengembangan proyek besar.
// ====== 1. Dynamic Import & Code Splitting ======
// Vite otomatis code-split dynamic imports
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const Chart = lazy(() => import('./Chart'));
// Named export dalam dynamic import
const { helper } = await import('./utils/helper.js');
// Dynamic import dengan webpackChunkName-like comment
const module = await import(
/* @vite-ignore */ dynamicPath // Skip Vite analysis
);
// ====== 2. Glob Import (import.meta.glob) ======
// Import banyak file sekaligus dengan pattern matching!
// Default: lazy imports (dynamic import)
const modules = import.meta.glob('./modules/*.js');
// Hasil: { './modules/foo.js': () => import('./modules/foo.js'), ... }
// Eager imports (langsung di-load, bukan lazy)
const eagerModules = import.meta.globEager('./modules/*.js');
// Custom glob pattern
const blogPosts = import.meta.glob('./content/blog/*.md', {
as: 'raw', // Import sebagai raw string
eager: true, // Load segera
});
// Contoh nyata: auto-import semua komponen di folder
const componentModules = import.meta.glob('./components/**/*.jsx', {
eager: true,
});
// Build component registry otomatis
const components = {};
for (const [path, module] of Object.entries(componentModules)) {
const name = path.split('/').pop().replace('.jsx', '');
components[name] = module.default;
}
// ====== 3. Web Workers ======
// Import worker dengan ?worker suffix
import MyWorker from './worker.js?worker';
const worker = new MyWorker();
worker.postMessage({ type: 'calculate', data: [1, 2, 3] });
worker.onmessage = (e) => console.log('Result:', e.data);
// Shared Worker
import SharedWorker from './shared-worker.js?sharedworker';
// Worker dengan URL
import WorkerUrl from './heavy-task.js?worker&url';
console.log(WorkerUrl); // URL string
// ====== 4. Asset Import Modes ======
import imgUrl from './photo.jpg'; // URL dengan hash
import rawSvg from './icon.svg?raw'; // Raw SVG string
import svgComponent from './icon.svg?react'; // React component (dengan plugin)
import cssText from './style.css?inline'; // CSS string (untuk inject inline)
import workerUrl from './worker.js?url'; // URL string
// ====== 5. CSS Modules ======
import styles from './Card.module.css';
// styles = { card: 'card_abc123', title: 'title_def456' }
// <div className={styles.card}><h2 className={styles.title}>...</h2></div>
// ====== 6. JSON Named Import ======
// Tree-shakeable JSON import!
import { name, version } from './package.json';
// Hanya name dan version yang masuk ke bundle, bukan seluruh JSON
// ====== 7. Dev-only code ======
if (import.meta.env.DEV) {
console.log('Ini hanya di development');
}
if (import.meta.env.PROD) {
// Production-only code
analytics.init();
}
10. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Vite: