Vite становится все более популярным среди разработчиков, но поскольку сообщество не такое большое (как в Webpack ), для решения ваших проблем может потребоваться создание собственного плагина. В этой статье мы обсудим, как создать плагин для Vite , и я разберу свой собственный плагин.
Для создания плагина важно знать, что Vite использует разные системы сборки для сервера разработки (команда vite
) и бандла (команда vite build
).
Для сервера разработки он использует esbuild с собственными ES-модулями, которые поддерживаются современными браузерами, и нам не нужно связывать код в один файл, и это дает нам быструю HRM (горячую замену модулей).
Для пакета используетсяrollup.js , поскольку он гибкий и имеет большую экосистему; он позволяет создавать высокооптимизированные производственные пакеты с различными форматами вывода.
Интерфейс плагина Vite основан на Rollup, но с дополнительными опциями и возможностями для работы с сервером разработки.
Когда вы создаете плагин, вы можете встроить его в свой vite.config.js
. Для него нет необходимости создавать новый пакет. Как только вы увидите, что плагин оказался полезен в ваших проектах, подумайте о том, чтобы поделиться им с сообществом и внести свой вклад в экосистему Vite.
Кроме того, поскольку у Rollup.js более обширное сообщество и экосистема, вы можете рассмотреть возможность создания плагина дляrollup.js, и он будет работать так же хорошо в Vite. Таким образом, если функциональность вашего плагина работает только для пакета, вы можете использовать плагинrollup.js вместо Vite, и пользователи смогут без проблем использовать ваш плагин Rollup в своих проектах Vite.
Если вы создадите плагин для объединения, вы охватите больше пользователей, которые используют толькоrollup.js. Если ваш плагин повлияет на сервер разработки, вам подойдет плагин Vite.
Начнем создавать плагин прямо в vite.config.ts
:
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });
В этом примере я создал плагин под названием myPlugin
, который печатает конфигурацию Vite, как только она будет разрешена в консоли на обоих этапах: сервер разработки и пакет. Если я хочу распечатать конфигурацию только в режиме сервера разработки, мне следует добавить apply: 'serve'
и apply: 'build'
для пакета.
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', apply: 'serve', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });
Кроме того, я могу вернуть массив плагинов; это полезно для разделения функций сервера разработки и пакета:
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin[] { return [ { name: 'my-plugin:serve', apply: 'serve', configResolved(config) { console.log('dev server:', config); }, }, { name: 'my-plugin:build', apply: 'build', configResolved(config) { console.log('bundle:', config); }, }, ]; } export default defineConfig({ plugins: [ myPlugin(), ], });
И это почти все; вы можете легко добавлять небольшие плагины в конфигурацию Vite. А если плагин становится слишком большим, я предпочитаю переместить его в другой файл или даже создать пакет.
Если вам нужно что-то более сложное, в документации Vite можно найти множество полезных приемов. Но в качестве примера давайте ниже разберем мой собственный плагин.
Итак, у меня есть плагин для создания SVG-спрайтов на основе файлов иконок — vite-plugin-svg-spritemap .
Цель состоит в том, чтобы захватить все значки .svg
из папки src/icons
и собрать их содержимое в один файл .svg
, который называется спрайтом SVG. Начнем со стадии комплектации:
import { Plugin, ResolvedConfig } from 'vite'; import path from 'path'; import fs from 'fs-extra'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: 'my-plugin:build', apply: 'build', async configResolved(_config) { config = _config; }, writeBundle() { const sprite = getSpriteContent({ pattern: 'src/icons/*.svg' }); const filePath = path.resolve(config.root, config.build.outDir, 'sprite.svg'); fs.ensureFileSync(filePath); fs.writeFileSync(filePath, sprite); }, }; }
Хук configResolved
позволяет нам получить конфигурацию, когда она будет решена, чтобы использовать ее в следующих хуках;
Перехват writeBundle
вызывается после завершения процесса объединения, и здесь я создам файл sprite.svg
;
Функция getSpriteContent
возвращает строку подготовленных спрайтов SVG на основе шаблона src/icons/*.svg
. Я не буду углубляться в этот вопрос; вы можете прочитать другую мою статью, объясняющую весь процесс генерации спрайтов SVG ;
Затем я создаю абсолютный путь к sprite.svg
, чтобы поместить в него содержимое спрайта SVG с помощью path.resolve()
, проверяю, что файл существует (или создаю его) с помощью fs.ensureFileSync
., и записываю в него содержимое спрайта SVG. .
Теперь самое интересное — этап разработки сервера. Я не могу здесь использовать writeBundle
и не могу размещать файлы, когда работает сервер разработки, поэтому нам нужно использовать промежуточное программное обеспечение сервера, чтобы перехватить запрос к sprite.svg
.
import { Plugin, ResolvedConfig } from 'vite'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { // (1) return () => { server.middlewares.use(async (req, res, next) => { // (2) if (req.url !== '/sprite.svg') { return next(); // (3) } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { // (4) 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }
configureServer
— это перехватчик для настройки сервера разработки. Он срабатывает до установки внутреннего промежуточного программного обеспечения Vite; в моем случае мне нужно добавить собственное промежуточное программное обеспечение после внутреннего промежуточного программного обеспечения, поэтому я возвращаю функцию;
Чтобы добавить собственное промежуточное программное обеспечение для перехвата каждого запроса к серверу разработки, я использую server.middlewares.use()
. Мне нужно, чтобы он обнаруживал запросы с URL-адресом [localhost:3000/sprite.svg](http://localhost:3000/sprite.svg)
, чтобы я мог эмулировать поведение файла;
Если URL-адрес запроса не /sprite.svg
— перейти к следующему промежуточному программному обеспечению (т. е. передать управление следующему обработчику в цепочке);
Чтобы подготовить содержимое файла, я помещаю результат getSpriteContent
в переменную sprite
и отправляю его в качестве ответа с настроенными заголовками (тип контента и статус HTTP 200).
В результате я смоделировал поведение файла.
Но если файлы в src/icons
изменены, удалены или добавлены, нам следует перезапустить сервер, чтобы сгенерировать новый контент спрайта через getSpriteContent
; для этого я буду использовать библиотеку просмотра файлов — chokidar . Добавим в код обработчики chokidar:
import { Plugin, ResolvedConfig } from 'vite'; import chokidar from 'chokidar'; function myPlugin(): Plugin { let config: ResolvedConfig; let watcher: chokidar.FSWatcher; // Defined variable for chokidar instance. return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { function reloadPage() { // Function that sends a signal to reload the server. server.ws.send({ type: 'full-reload', path: '*' }); } watcher = chokidar .watch('src/icons/*.svg', { // Watch src/icons/*.svg cwd: config.root, // Define project root path ignoreInitial: true, // Don't trigger chokidar on instantiation. }) .on('add', reloadPage) // Add listeners to add, modify, delete. .on('change', reloadPage) .on('unlink', reloadPage); return () => { server.middlewares.use(async (req, res, next) => { if (req.url !== '/sprite.svg') { return next(); } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }
Как видите, API создания плагинов не очень сложен. Вам просто нужно найти хуки от Vite или Rollup, которые подойдут под ваши задачи. В моем примере я использую writeBundle
из Rollup.js (как я уже сказал, он используется для создания пакета) и configureServer
из Vite, поскольку Rollup.js не имеет встроенной поддержки сервера разработки.
В случае с writeBundle
все было очень просто: мы взяли содержимое спрайта SVG и поместили его в файл. В случае с сервером разработки меня смутило, почему я не могу сделать то же самое; Я посмотрел плагины других авторов, и все они делают примерно то же самое.
Итак, я использую configureServer
и через аргумент server
добавляю промежуточное программное обеспечение, которое запускает каждый запрос к серверу разработки, перехватывая запрос sprite.svg
.
Как я уже упоминал ранее, чтобы создавать более полезные плагины, вам необходимо изучить крючки. Они подробно описаны в документации:
https://vitejs.dev/guide/api-plugin#universal-hooks
https://vitejs.dev/guide/api-plugin#vite-специфические-хуки
Что касается именования, в Vite есть некоторые соглашения для плагинов, поэтому вам лучше проверить их, прежде чем закончить. Вот некоторые ключевые моменты:
vite-plugin-
;
vite-plugin
в package.json;
vite-plugin-vue-
, vite-plugin-react-
, vite-plugin-svelte-
).Если вы решите опубликовать свой плагин в NPM, я рекомендую это, поскольку обмен знаниями и опытом является фундаментальным принципом ИТ-сообщества, способствующим коллективному росту. Чтобы узнать, как публиковать и поддерживать свой пакет, ознакомьтесь с моим руководством → Самый простой способ создать пакет NPM .
Я также настоятельно рекомендую отправить ваш плагин в список сообщества Vite — Awesome-Vite . Многие люди ищут там наиболее подходящие плагины, и это была бы прекрасная возможность внести свой вклад в экосистему Vite! Процесс отправки вашего плагина прост — просто убедитесь, что вы соответствуете условиям, и создайте запрос на включение. Список терминов вы можете найти здесь .
В целом, он должен быть специфичным для Vite (не накопительным), иметь открытый исходный код и хорошую документацию. Удачи вам с вашими плагинами!