Дослідіть архітектуру плагінів Vite та навчіться створювати власні плагіни для покращення процесу розробки. Опануйте ключові концепції з практичними прикладами для глобальної аудиторії.
Демістифікація архітектури плагінів Vite: Глобальний посібник зі створення власних плагінів
Vite, блискавичний інструмент для збірки, здійснив революцію у фронтенд-розробці. Його швидкість та простота значною мірою зумовлені потужною архітектурою плагінів. Ця архітектура дозволяє розробникам розширювати функціональність Vite та адаптувати її до конкретних потреб проєкту. Цей посібник пропонує всебічне дослідження системи плагінів Vite, що дасть вам змогу створювати власні плагіни та оптимізувати робочий процес розробки.
Розуміння основних принципів Vite
Перш ніж зануритися у створення плагінів, важливо зрозуміти фундаментальні принципи Vite:
- Компіляція на вимогу: Vite компілює код лише тоді, коли його запитує браузер, що значно скорочує час запуску.
- Нативні ESM: Vite використовує нативні модулі ECMAScript (ESM) для розробки, що усуває потребу в бандлінгу під час розробки.
- Продакшн-збірка на основі Rollup: Для продакшн-збірок Vite використовує Rollup, високооптимізований бандлер, для генерації ефективного та готового до продакшну коду.
Роль плагінів в екосистемі Vite
Архітектура плагінів Vite розроблена для максимального розширення. Плагіни можуть:
- Трансформувати код (наприклад, транспілювати TypeScript, додавати препроцесори).
- Надавати власні файли (наприклад, обробляти статичні ресурси, створювати віртуальні модулі).
- Модифікувати процес збірки (наприклад, оптимізувати зображення, генерувати сервіс-воркери).
- Розширювати CLI Vite (наприклад, додавати власні команди).
Плагіни є ключем до адаптації Vite до різноманітних вимог проєкту, від простих модифікацій до складних інтеграцій.
Архітектура плагінів Vite: Глибоке занурення
Плагін Vite — це, по суті, об'єкт JavaScript з певними властивостями, які визначають його поведінку. Розглянемо ключові елементи:
Конфігурація плагіна
Файл `vite.config.js` (або `vite.config.ts`) — це місце, де ви налаштовуєте свій проєкт Vite, включаючи вказівку, які плагіни використовувати. Опція `plugins` приймає масив об'єктів плагінів або функцій, що повертають об'єкти плагінів.
// vite.config.js
import myPlugin from './my-plugin';
export default {
plugins: [
myPlugin(), // Виклик функції плагіна для створення екземпляра
],
};
Властивості об'єкта плагіна
Об'єкт плагіна Vite може мати кілька властивостей, що визначають його поведінку на різних етапах процесу збірки. Ось огляд найпоширеніших властивостей:
- name: Унікальна назва плагіна. Це обов'язкова властивість, яка допомагає з налагодженням та вирішенням конфліктів. Приклад: `'my-custom-plugin'`
- enforce: Визначає порядок виконання плагіна. Можливі значення: `'pre'` (виконується перед основними плагінами), `'normal'` (за замовчуванням) та `'post'` (виконується після основних плагінів). Приклад: `'pre'`
- config: Дозволяє змінювати об'єкт конфігурації Vite. Отримує конфігурацію користувача та середовище (режим і команда). Приклад: `config: (config, { mode, command }) => { ... }`
- configResolved: Викликається після повного визначення конфігурації Vite. Корисний для доступу до фінального об'єкта конфігурації. Приклад: `configResolved(config) { ... }`
- configureServer: Надає доступ до екземпляра сервера розробки (схожого на Connect/Express). Корисний для додавання власного middleware або зміни поведінки сервера. Приклад: `configureServer(server) { ... }`
- transformIndexHtml: Дозволяє трансформувати файл `index.html`. Корисний для вставки скриптів, стилів або мета-тегів. Приклад: `transformIndexHtml(html) { ... }`
- resolveId: Дозволяє перехоплювати та змінювати визначення модулів. Корисний для власної логіки визначення модулів. Приклад: `resolveId(source, importer) { ... }`
- load: Дозволяє завантажувати власні модулі або змінювати вміст існуючих. Корисний для віртуальних модулів або власних завантажувачів. Приклад: `load(id) { ... }`
- transform: Трансформує вихідний код модулів. Схожий на плагін Babel або PostCSS. Приклад: `transform(code, id) { ... }`
- buildStart: Викликається на початку процесу збірки. Приклад: `buildStart() { ... }`
- buildEnd: Викликається після завершення процесу збірки. Приклад: `buildEnd() { ... }`
- closeBundle: Викликається після запису бандла на диск. Приклад: `closeBundle() { ... }`
- writeBundle: Викликається перед записом бандла на диск, дозволяючи його модифікувати. Приклад: `writeBundle(options, bundle) { ... }`
- renderError: Дозволяє рендерити власні сторінки помилок під час розробки. Приклад: `renderError(error, req, res) { ... }`
- handleHotUpdate: Дозволяє точно контролювати HMR. Приклад: `handleHotUpdate({ file, server }) { ... }`
Хуки плагінів та порядок їх виконання
Плагіни Vite працюють через серію хуків, які спрацьовують на різних етапах процесу збірки. Розуміння порядку, в якому виконуються ці хуки, є вирішальним для написання ефективних плагінів.
- config: Змінити конфігурацію Vite.
- configResolved: Отримати доступ до визначеної конфігурації.
- configureServer: Змінити сервер розробки (лише під час розробки).
- transformIndexHtml: Трансформувати файл `index.html`.
- buildStart: Початок процесу збірки.
- resolveId: Визначити ID модулів.
- load: Завантажити вміст модуля.
- transform: Трансформувати код модуля.
- handleHotUpdate: Обробити Hot Module Replacement (HMR).
- writeBundle: Змінити вихідний бандл перед записом на диск.
- closeBundle: Викликається після запису вихідного бандла на диск.
- buildEnd: Кінець процесу збірки.
Створення вашого першого власного плагіна Vite
Створімо простий плагін Vite, який додає банер на початок кожного файлу JavaScript у продакшн-збірці. Цей банер міститиме назву та версію проєкту.
Реалізація плагіна
// 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 * Project: ${packageJson.name}\n * Version: ${packageJson.version}\n */\n`;
return banner + code;
},
};
}
Пояснення:
- name: Визначає назву плагіна, 'banner-plugin'.
- apply: Вказує, що цей плагін має працювати лише під час процесу збірки. Встановлення значення 'build' робить його активним лише для продакшну, уникаючи непотрібних накладних витрат під час розробки.
- transform(code, id):
- Це ядро плагіна. Він перехоплює код (`code`) та ідентифікатор (`id`) кожного модуля.
- Перевірка умови: `if (!id.endsWith('.js'))` гарантує, що трансформація застосовується лише до файлів JavaScript. Це запобігає обробці інших типів файлів (наприклад, CSS або HTML), що може спричинити помилки або неочікувану поведінку.
- Доступ до package.json:
- `resolve(process.cwd(), 'package.json')` створює абсолютний шлях до файлу `package.json`. `process.cwd()` повертає поточний робочий каталог, гарантуючи використання правильного шляху незалежно від того, звідки виконується команда.
- `JSON.parse(readFileSync(packageJsonPath, 'utf-8'))` читає та парсить файл `package.json`. `readFileSync` читає файл синхронно, а `'utf-8'` вказує кодування для правильної обробки символів Unicode. Синхронне читання тут є прийнятним, оскільки воно відбувається один раз на початку трансформації.
- Генерація банера:
- ``const banner = `/**\n * Project: ${packageJson.name}\n * Version: ${packageJson.version}\n */\n`;`` створює рядок банера. Він використовує шаблонні літерали (зворотні лапки), щоб легко вставляти назву проєкту та версію з файлу `package.json`. Послідовності `\n` вставляють нові рядки для правильного форматування банера. Символ `*` є частиною коментаря.
- Трансформація коду: `return banner + code;` додає банер на початок оригінального коду JavaScript. Це фінальний результат, який повертає функція transform.
Інтеграція плагіна
Імпортуйте плагін у ваш файл `vite.config.js` та додайте його до масиву `plugins`:
// vite.config.js
import bannerPlugin from './banner-plugin';
export default {
plugins: [
bannerPlugin(),
],
};
Запуск збірки
Тепер запустіть `npm run build` (або команду збірки вашого проєкту). Після завершення збірки перевірте згенеровані файли JavaScript у каталозі `dist`. Ви побачите банер на початку кожного файлу.
Просунуті техніки плагінів
Окрім простих трансформацій коду, плагіни Vite можуть використовувати більш просунуті техніки для розширення своїх можливостей.
Віртуальні модулі
Віртуальні модулі дозволяють плагінам створювати модулі, які не існують як реальні файли на диску. Це корисно для генерації динамічного контенту або надання даних конфігурації для застосунку.
// virtual-module-plugin.js
export default function virtualModulePlugin(options) {
const virtualModuleId = 'virtual:my-module';
const resolvedVirtualModuleId = '\0' + virtualModuleId; // Префікс \0, щоб Rollup не обробляв його
return {
name: 'virtual-module-plugin',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export default ${JSON.stringify(options)};`;
}
},
};
}
У цьому прикладі:
- `virtualModuleId` — це рядок, що представляє ідентифікатор віртуального модуля.
- `resolvedVirtualModuleId` має префікс `\0`, щоб Rollup не обробляв його як реальний файл. Це конвенція, що використовується в плагінах Rollup.
- `resolveId` перехоплює визначення модуля і повертає визначений ID віртуального модуля, якщо запитаний ID збігається з `virtualModuleId`.
- `load` перехоплює завантаження модуля і повертає код модуля, якщо запитаний ID збігається з `resolvedVirtualModuleId`. У цьому випадку він генерує модуль JavaScript, який експортує `options` як експорт за замовчуванням.
Використання віртуального модуля
// vite.config.js
import virtualModulePlugin from './virtual-module-plugin';
export default {
plugins: [
virtualModulePlugin({ message: 'Привіт з віртуального модуля!' }),
],
};
// main.js
import message from 'virtual:my-module';
console.log(message.message); // Вивід: Привіт з віртуального модуля!
Трансформація Index HTML
Хук `transformIndexHtml` дозволяє змінювати файл `index.html`, наприклад, вставляти скрипти, стилі або мета-теги. Це корисно для додавання відстеження аналітики, налаштування метаданих для соціальних мереж або кастомізації структури HTML.
// inject-script-plugin.js
export default function injectScriptPlugin() {
return {
name: 'inject-script-plugin',
transformIndexHtml(html) {
return html.replace(
'