Vite · Part 9 — Plugins
The Rollup-compatible plugin API: the hooks that matter (resolveId, load, transform), enforce (pre/post) and apply (serve/build) ordering, and writing your own virtual-module plugin. With a plugin hook timeline.
Hầu hết mọi thứ Vite làm ngoài JS/CSS thuần đều qua plugin — framework, hỗ trợ legacy, PWA, SVG-as-component, và biến đổi tùy chỉnh của bạn. Tin tốt: plugin Vite là plugin Rollup với vài hook thêm, nên kiến thức chuyển giao khắp hệ sinh thái.
Chạy một module qua pipeline plugin và xem mỗi hook kích hoạt theo thứ tự:
1. Plugin là một object
Hình dạng tối thiểu — một name và một hoặc nhiều hàm hook:
import type { Plugin } from "vite";
function myPlugin(): Plugin {
return {
name: "my-plugin", // required, used in errors/warnings
transform(code, id) {
// rewrite a module's code
return null; // null = leave unchanged
},
};
}
// vite.config.ts
export default defineConfig({ plugins: [myPlugin()] });
Bạn thêm vào plugins như bất kỳ cái nào khác. Đa số plugin là hàm trả object này để nhận tùy chọn.
2. Các hook quan trọng
Vite chạy hook khi xử lý từng module. Những cái bạn thực sự dùng:
| Hook | Khi | Dùng cho |
|---|---|---|
config / configResolved | khởi động | đọc/chỉnh config |
configureServer | chỉ dev | thêm middleware dev-server |
resolveId | mỗi module | nhận/chuyển hướng id import |
load | mỗi module | cấp source cho một id |
transform | mỗi module | viết lại code module |
handleHotUpdate | chỉ dev | tùy chỉnh hành vi HMR |
renderChunk / generateBundle | chỉ build | sửa output / phát file |
resolveId → load → transform là bộ ba cốt lõi cho mỗi module. transform là người làm chính.
3. enforce và apply — thứ tự & phạm vi
Thứ tự plugin có thể quan trọng. Vite chạy plugin theo ba nhóm:
function myPlugin(): Plugin {
return {
name: "my-plugin",
enforce: "pre", // "pre" → before core | undefined → with core | "post" → after
apply: "build", // "build" | "serve" | a function — limit when it runs
transform(code, id) {
/* ... */
},
};
}
- chạy trước plugin core của Vite.
- chạy sau core.
- chỉ chạy khi dev hoặc chỉ khi build.
4. Viết plugin virtual-module
Pattern hữu ích nhất để học: một virtual module — module import được nhưng không tồn tại trên đĩa, source do bạn sinh lúc build:
function buildInfoPlugin(): Plugin {
const id = "virtual:build-info";
const resolvedId = "\0" + id; // the \0 prefix marks it virtual (convention)
return {
name: "build-info",
resolveId(source) {
if (source === id) return resolvedId; // "I own this import"
},
load(thisId) {
if (thisId === resolvedId) {
return `export const builtAt = ${JSON.stringify(new Date().toISOString())};`;
}
},
};
}
// anywhere in your app
import { builtAt } from "virtual:build-info";
resolveId nhận id; load trả source được sinh. Tiền tố \0 là quy ước nói với Vite (và plugin khác) “đây không phải file thật, đừng đọc từ đĩa”. Đây là cách vite/client, chèn env, và nhiều tích hợp hoạt động.
5. Ví dụ transform
transform cho bạn viết lại file thật. Plugin đồ chơi thay một token:
function bannerPlugin(): Plugin {
return {
name: "banner",
transform(code, id) {
if (!id.endsWith(".ts")) return null;
return { code: `/* generated ${Date.now()} */\n${code}`, map: null };
},
};
}
Trả null để giữ module không đổi; trả { code, map } để viết lại (cung cấp source map khi có thể).
6. Lưu ý tương thích (Vite 8)
Vì Vite 8 dùng Rolldown (giữ API plugin tương thích Rollup), đại đa số plugin Vite và Rollup hiện có chạy không cần đổi. Khi viết plugin, nhắm các hook Vite/Rollup được tài liệu hóa và bạn an toàn tương lai.
7. Bài tập
1. Bộ ba hook nào xử lý một module từ chuỗi import tới code cuối, và cái nào là “người làm chính”?
Lời giải
resolveId → load → transform; transform là người làm chính viết lại code module.
2. Bạn muốn import config from "virtual:app-config" chạy mà không có file đó trên đĩa. Hai hook nào?
Lời giải
resolveId (nhận id, trả id có tiền tố \0) và load (trả source sinh ra).
3. Plugin của bạn phải biến đổi file trước plugin core của Vite, và chỉ khi dev. Đặt gì?
Lời giải
enforce: "pre" và apply: "serve".
Nâng cao:trong timeline, để ý hook nào “chỉ dev” vs “chỉ build” — đó là những cái bị giới hạn bởi apply và phân biệt serve/build.
Điểm chính
- Plugin Vite là object có
namevà hook — và là plugin Rollup. resolveId→load→transformxử lý mỗi module;transformlà người làm chính.enforceđiều khiển thứ tự;applyđiều khiển khi nào chạy.- Virtual module phơi code sinh ra dưới dạng import.
- Rolldown giữ API Rollup, nên đa số plugin chạy luôn.
Tiếp theo
Phần 10 — Build production với Rolldown: vite build tạo gì, tách chunk và manualChunks, advancedChunks mới, xử lý asset, và đọc output build.