jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

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.

4 MIN READ

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:

HookKhiDùng cho
config / configResolvedkhởi độngđọc/chỉnh config
configureServerchỉ devthêm middleware dev-server
resolveIdmỗi modulenhận/chuyển hướng id import
loadmỗi modulecấp source cho một id
transformmỗi moduleviết lại code module
handleHotUpdatechỉ devtùy chỉnh hành vi HMR
renderChunk / generateBundlechỉ buildsửa output / phát file

resolveIdloadtransform là bộ ba cốt lõi cho mỗi module. transform là người làm chính.


3. enforceapply — 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

resolveIdloadtransform; 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"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ó name và hook — và là plugin Rollup.
  • resolveIdloadtransform xử lý mỗi module; transform là 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.