Jelajahi arsitektur plugin Vite dan pelajari cara membuat plugin kustom untuk meningkatkan alur kerja pengembangan Anda. Kuasai konsep penting dengan contoh praktis.
Mendalami Arsitektur Plugin Vite: Panduan Global untuk Membuat Plugin Kustom
Vite, alat build secepat kilat, telah merevolusi pengembangan frontend. Kecepatan dan kesederhanaannya sebagian besar berkat arsitektur plugin-nya yang kuat. Arsitektur ini memungkinkan developer untuk memperluas fungsionalitas Vite dan menyesuaikannya dengan kebutuhan proyek spesifik mereka. Panduan ini memberikan eksplorasi komprehensif tentang sistem plugin Vite, memberdayakan Anda untuk membuat plugin kustom Anda sendiri dan mengoptimalkan alur kerja pengembangan Anda.
Memahami Prinsip Inti Vite
Sebelum mendalami pembuatan plugin, penting untuk memahami prinsip-prinsip fundamental Vite:
- Kompilasi Sesuai Permintaan: Vite hanya mengompilasi kode saat diminta oleh browser, yang secara signifikan mengurangi waktu startup.
- ESM Bawaan: Vite memanfaatkan modul ECMAScript (ESM) bawaan untuk pengembangan, menghilangkan kebutuhan untuk bundling selama pengembangan.
- Build Produksi Berbasis Rollup: Untuk build produksi, Vite menggunakan Rollup, sebuah bundler yang sangat dioptimalkan, untuk menghasilkan kode yang efisien dan siap produksi.
Peran Plugin dalam Ekosistem Vite
Arsitektur plugin Vite dirancang agar sangat bisa diperluas. Plugin dapat:
- Mengubah kode (misalnya, mentranspilasi TypeScript, menambahkan preprocessor).
- Menyajikan file kustom (misalnya, menangani aset statis, membuat modul virtual).
- Memodifikasi proses build (misalnya, mengoptimalkan gambar, menghasilkan service worker).
- Memperluas CLI Vite (misalnya, menambahkan perintah kustom).
Plugin adalah kunci untuk mengadaptasi Vite ke berbagai persyaratan proyek, dari modifikasi sederhana hingga integrasi yang kompleks.
Arsitektur Plugin Vite: Penjelasan Mendalam
Sebuah plugin Vite pada dasarnya adalah objek JavaScript dengan properti spesifik yang mendefinisikan perilakunya. Mari kita periksa elemen-elemen kuncinya:
Konfigurasi Plugin
File `vite.config.js` (atau `vite.config.ts`) adalah tempat Anda mengonfigurasi proyek Vite Anda, termasuk menentukan plugin mana yang akan digunakan. Opsi `plugins` menerima sebuah array objek plugin atau fungsi yang mengembalikan objek plugin.
// vite.config.js
import myPlugin from './my-plugin';
export default {
plugins: [
myPlugin(), // Panggil fungsi plugin untuk membuat instance plugin
],
};
Properti Objek Plugin
Objek plugin Vite dapat memiliki beberapa properti yang mendefinisikan perilakunya selama fase-fase yang berbeda dari proses build. Berikut adalah rincian properti yang paling umum:
- name: Nama unik untuk plugin. Ini wajib dan membantu dalam proses debugging dan resolusi konflik. Contoh: `'my-custom-plugin'`
- enforce: Menentukan urutan eksekusi plugin. Nilai yang mungkin adalah `'pre'` (berjalan sebelum plugin inti), `'normal'` (default), dan `'post'` (berjalan setelah plugin inti). Contoh: `'pre'`
- config: Memungkinkan modifikasi objek konfigurasi Vite. Properti ini menerima konfigurasi pengguna dan lingkungan (mode dan perintah). Contoh: `config: (config, { mode, command }) => { ... }`
- configResolved: Dipanggil setelah konfigurasi Vite sepenuhnya diselesaikan. Berguna untuk mengakses objek konfigurasi final. Contoh: `configResolved(config) { ... }`
- configureServer: Memberikan akses ke instance server pengembangan (mirip Connect/Express). Berguna untuk menambahkan middleware kustom atau memodifikasi perilaku server. Contoh: `configureServer(server) { ... }`
- transformIndexHtml: Memungkinkan transformasi file `index.html`. Berguna untuk menyuntikkan skrip, gaya, atau tag meta. Contoh: `transformIndexHtml(html) { ... }`
- resolveId: Memungkinkan intersepsi dan modifikasi resolusi modul. Berguna untuk logika resolusi modul kustom. Contoh: `resolveId(source, importer) { ... }`
- load: Memungkinkan pemuatan modul kustom atau modifikasi konten modul yang ada. Berguna untuk modul virtual atau loader kustom. Contoh: `load(id) { ... }`
- transform: Mengubah kode sumber modul. Mirip dengan plugin Babel atau plugin PostCSS. Contoh: `transform(code, id) { ... }`
- buildStart: Dipanggil di awal proses build. Contoh: `buildStart() { ... }`
- buildEnd: Dipanggil setelah proses build selesai. Contoh: `buildEnd() { ... }`
- closeBundle: Dipanggil setelah bundle ditulis ke disk. Contoh: `closeBundle() { ... }`
- writeBundle: Dipanggil sebelum menulis bundle ke disk, memungkinkan modifikasi. Contoh: `writeBundle(options, bundle) { ... }`
- renderError: Memungkinkan untuk merender halaman error kustom selama pengembangan. Contoh: `renderError(error, req, res) { ... }`
- handleHotUpdate: Memungkinkan kontrol yang lebih detail atas HMR. Contoh: `handleHotUpdate({ file, server }) { ... }`
Hook Plugin dan Urutan Eksekusi
Plugin Vite beroperasi melalui serangkaian hook yang dipicu pada berbagai tahap proses build. Memahami urutan eksekusi hook ini sangat penting untuk menulis plugin yang efektif.
- config: Memodifikasi konfigurasi Vite.
- configResolved: Mengakses konfigurasi yang telah diselesaikan.
- configureServer: Memodifikasi server dev (hanya pengembangan).
- transformIndexHtml: Mengubah file `index.html`.
- buildStart: Awal dari proses build.
- resolveId: Menyelesaikan ID modul.
- load: Memuat konten modul.
- transform: Mengubah kode modul.
- handleHotUpdate: Menangani Hot Module Replacement (HMR).
- writeBundle: Memodifikasi bundle output sebelum ditulis ke disk.
- closeBundle: Dipanggil setelah bundle output ditulis ke disk.
- buildEnd: Akhir dari proses build.
Membuat Plugin Vite Kustom Pertama Anda
Mari kita buat plugin Vite sederhana yang menambahkan banner ke bagian atas setiap file JavaScript dalam build produksi. Banner ini akan menyertakan nama dan versi proyek.
Implementasi Plugin
// banner-plugin.js
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
export default function bannerPlugin() {
return {
name: 'banner-plugin',
apply: 'build',
transform(code, id) {
if (!id.endsWith('.js')) {
return code;
}
const packageJsonPath = resolve(process.cwd(), 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
const banner = `/**\n * Proyek: ${packageJson.name}\n * Versi: ${packageJson.version}\n */\n`;
return banner + code;
},
};
}
Penjelasan:
- name: Mendefinisikan nama plugin, 'banner-plugin'.
- apply: Menentukan bahwa plugin ini hanya boleh berjalan selama proses build. Mengaturnya ke 'build' membuatnya hanya untuk produksi, menghindari overhead yang tidak perlu selama pengembangan.
- transform(code, id):
- Ini adalah inti dari plugin. Hook ini mencegat kode (`code`) dan ID (`id`) setiap modul.
- Pemeriksaan Kondisional: `if (!id.endsWith('.js'))` memastikan bahwa transformasi hanya berlaku untuk file JavaScript. Ini mencegah pemrosesan jenis file lain (seperti CSS atau HTML), yang dapat menyebabkan kesalahan atau perilaku tak terduga.
- Akses package.json:
- `resolve(process.cwd(), 'package.json')` membuat path absolut ke file `package.json`. `process.cwd()` mengembalikan direktori kerja saat ini, memastikan path yang benar digunakan di mana pun perintah dieksekusi.
- `JSON.parse(readFileSync(packageJsonPath, 'utf-8'))` membaca dan mem-parsing file `package.json`. `readFileSync` membaca file secara sinkron, dan `'utf-8'` menentukan pengkodean untuk menangani karakter Unicode dengan benar. Pembacaan sinkron dapat diterima di sini karena terjadi sekali di awal transformasi.
- Pembuatan Banner:
- ``const banner = `/**\n * Proyek: ${packageJson.name}\n * Versi: ${packageJson.version}\n */\n`;`` membuat string banner. Ini menggunakan template literal (tanda kutip terbalik) untuk dengan mudah menyematkan nama dan versi proyek dari file `package.json`. Urutan `\n` menyisipkan baris baru untuk memformat banner dengan benar. Tanda `*` di-escape dengan `\*`.
- Transformasi Kode: `return banner + code;` menambahkan banner di awal kode JavaScript asli. Ini adalah hasil akhir yang dikembalikan oleh fungsi transform.
Mengintegrasikan Plugin
Impor plugin ke dalam file `vite.config.js` Anda dan tambahkan ke array `plugins`:
// vite.config.js
import bannerPlugin from './banner-plugin';
export default {
plugins: [
bannerPlugin(),
],
};
Menjalankan Build
Sekarang, jalankan `npm run build` (atau perintah build proyek Anda). Setelah build selesai, periksa file JavaScript yang dihasilkan di direktori `dist`. Anda akan melihat banner di bagian atas setiap file.
Teknik Plugin Tingkat Lanjut
Di luar transformasi kode sederhana, plugin Vite dapat memanfaatkan teknik yang lebih canggih untuk meningkatkan kemampuannya.
Modul Virtual
Modul virtual memungkinkan plugin untuk membuat modul yang tidak ada sebagai file fisik di disk. Ini berguna untuk menghasilkan konten dinamis atau menyediakan data konfigurasi ke aplikasi.
// virtual-module-plugin.js
export default function virtualModulePlugin(options) {
const virtualModuleId = 'virtual:my-module';
const resolvedVirtualModuleId = '\0' + virtualModuleId; // Awali dengan \0 untuk mencegah Rollup memproses
return {
name: 'virtual-module-plugin',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export default ${JSON.stringify(options)};`;
}
},
};
}
Dalam contoh ini:
- `virtualModuleId` adalah string yang merepresentasikan identifier modul virtual.
- `resolvedVirtualModuleId` diawali dengan `\0` untuk mencegah Rollup memprosesnya sebagai file nyata. Ini adalah konvensi yang digunakan dalam plugin Rollup.
- `resolveId` mencegat resolusi modul dan mengembalikan ID modul virtual yang telah diselesaikan jika ID yang diminta cocok dengan `virtualModuleId`.
- `load` mencegat pemuatan modul dan mengembalikan kode modul jika ID yang diminta cocok dengan `resolvedVirtualModuleId`. Dalam kasus ini, ia menghasilkan modul JavaScript yang mengekspor `options` sebagai ekspor default.
Menggunakan Modul Virtual
// vite.config.js
import virtualModulePlugin from './virtual-module-plugin';
export default {
plugins: [
virtualModulePlugin({ message: 'Halo dari modul virtual!' }),
],
};
// main.js
import message from 'virtual:my-module';
console.log(message.message); // Output: Halo dari modul virtual!
Mengubah Index HTML
Hook `transformIndexHtml` memungkinkan Anda untuk memodifikasi file `index.html`, seperti menyuntikkan skrip, gaya, atau tag meta. Ini berguna untuk menambahkan pelacakan analitik, mengonfigurasi metadata media sosial, atau menyesuaikan struktur HTML.
// inject-script-plugin.js
export default function injectScriptPlugin() {
return {
name: 'inject-script-plugin',
transformIndexHtml(html) {
return html.replace(
'