Web Development

Vite: Build Tool Cepat untuk Web Development Modern

Tutorial lengkap belajar Vite β€” setup proyek, HMR super cepat, plugins ecosystem, optimasi build, SSR, environment variables, dan konfigurasi lanjutan

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 ServerBrowser memuat modul langsung via native ES Modules β€” tidak perlu bundling saat development
On-demand CompilationHanya file yang di-request yang dikompilasi β€” bukan seluruh proyek
Instant HMRHot Module Replacement bekerja dalam milidetik, tidak peduli seberapa besar proyek
esbuildPre-bundling dependencies menggunakan esbuild (ditulis di Go, 10-100x lebih cepat dari JS bundler)
Rollup ProductionBuild produksi menggunakan Rollup β€” bundler yang mature dan teroptimasi
Framework AgnosticTemplate 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 ToolRollup (prod)Webpack sendiriSWC/Rust
Pre-bundlingesbuild (Go)Tidak adaTidak ada
Native ESMβœ… Ya❌ Tidak❌ Tidak
Legacy SupportPluginBuilt-inBuilt-in
Diagram: Arsitektur Vite
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                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.

Bash β€” Setup Vite
# ====== 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

File Structure
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

HTML β€” 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
-->
JavaScript β€” main.jsx (Entry Point)
// ====== 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

JavaScript β€” HMR Examples
// ====== 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 Styles
/* ====== 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.

JavaScript β€” vite.config.js
// 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.

Bash & JavaScript β€” Essential Plugins
# ====== 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

JavaScript β€” Plugin Configuration
// 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

JavaScript β€” Custom Vite 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

JavaScript β€” Pre-bundling & Optimization
// ====== 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]',
      },
    },
  },
});
Diagram: Vite Build Process
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              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.

JavaScript β€” Environment Variables
// ====== .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.

JavaScript β€” Vite SSR
// ====== 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.

JavaScript β€” Advanced Vite Features
// ====== 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:

Pertanyaan 1: Mengapa Vite development server bisa start dalam hitungan milidetik?

a) Karena menggunakan WebWorker untuk semua processing
b) Karena menggunakan native ES Modules di browser sehingga tidak perlu bundling saat development
c) Karena menyimpan cache di localStorage
d) Karena menggunakan CDN untuk semua file

Pertanyaan 2: Apa kepanjangan dari HMR?

a) HTTP Module Response
b) Hot Module Replacement
c) High Memory Resolution
d) Host Module Rendering

Pertanyaan 3: Environment variable mana yang bisa diakses dari browser di Vite?

a) Semua variabel di .env
b) Hanya variabel yang diawali VITE_
c) Hanya variabel yang diawali PUBLIC_
d) Tidak ada yang bisa diakses dari browser

Pertanyaan 4: Apa fungsi dari import.meta.glob() di Vite?

a) Mengimpor satu file dengan path dinamis
b) Mengimpor banyak file sekaligus menggunakan pattern matching
c) Membuat API endpoint secara otomatis
d) Mengkonfigurasi environment variables

Pertanyaan 5: Bundler apa yang digunakan Vite untuk production build?

a) Webpack
b) esbuild
c) Rollup
d) Parcel
πŸ” Zoom
100%
🎨 Tema