12k
All articles

Как создавать и использовать плагины в Vite

Статья охватывает создание плагинов Vite через lifecycle hooks, виртуальные модули и интеграцию с Rollup для трансформации файлов и расширения сборки.

OpenReplay Team
OpenReplay Team
Как создавать и использовать плагины в Vite

Создание пользовательских плагинов Vite позволяет расширить процесс сборки за пределы стандартной конфигурации — будь то преобразование пользовательских типов файлов, внедрение логики во время сборки или добавление middleware для сервера разработки. Если вы достигли пределов стандартной конфигурации Vite, создание собственного плагина — естественный следующий шаг.

Это руководство охватывает основные концепции: как работает Plugin API Vite, ключевые хуки жизненного цикла, которые вы будете использовать, и практические примеры для начала работы. Вы научитесь создавать, тестировать и публиковать плагины, которые решают реальные задачи в вашем рабочем процессе разработки.

Ключевые выводы

  • Плагины Vite расширяют процессы разработки и production-сборки через хуки жизненного цикла
  • Большинство плагинов Rollup работают в Vite, но функции dev-сервера требуют специфичных для Vite хуков
  • Начните с простых преобразований, прежде чем переходить к продвинутым паттернам, таким как виртуальные модули
  • Следуйте соглашениям об именовании и стандартам документации при публикации плагинов

Понимание плагинов Vite и их связи с Rollup

Плагины Vite — это JavaScript-объекты, которые подключаются к различным этапам процесса разработки и сборки. Они построены на основе системы плагинов Rollup с дополнительными хуками, специфичными для сервера разработки Vite.

Vite использует два разных инструмента сборки под капотом: esbuild обеспечивает молниеносно быстрый сервер разработки с нативными ES-модулями, в то время как Rollup обрабатывает production-бандлинг для оптимального вывода. Эта двойная архитектура означает, что ваши плагины могут нацеливаться на конкретные окружения с помощью опции apply:

function myPlugin(): Plugin {
  return {
    name: 'my-plugin',
    apply: 'serve', // Only runs during development
    // ... hooks
  }
}

Большинство плагинов Rollup работают в Vite без модификаций. Однако, если вам нужна функциональность dev-сервера — например, добавление middleware или изменение HTML во время разработки — вам потребуются специфичные для Vite хуки.

Базовая структура плагина и конфигурация

Каждый плагин Vite должен иметь свойство name и как минимум одну функцию-хук:

import type { Plugin } from 'vite'

function myPlugin(options?: MyPluginOptions): Plugin {
  return {
    name: 'vite-plugin-example',
    enforce: 'pre', // Optional: control plugin ordering
    apply: 'build', // Optional: 'serve' | 'build' | undefined
    
    // Hook functions go here
    transform(code, id) {
      if (id.endsWith('.custom')) {
        return transformCustomFile(code)
      }
    }
  }
}

Plugin API предоставляет TypeScript-определения для всех хуков и опций. Импортируйте тип Plugin из ‘vite’ для полной типобезопасности и автодополнения.

Основные хуки жизненного цикла в Plugin API

Различные хуки срабатывают на разных этапах процесса сборки. Вот наиболее часто используемые:

Хуки конфигурации

  • config: Изменение конфигурации Vite до её разрешения
  • configResolved: Доступ к финальной разрешённой конфигурации

Хуки преобразования

  • transform: Изменение исходного кода отдельных модулей
  • load: Пользовательская логика загрузки для конкретных типов файлов
  • resolveId: Пользовательское разрешение модулей
{
  name: 'transform-plugin',
  transform(code, id) {
    if (!id.includes('node_modules') && id.endsWith('.js')) {
      return {
        code: addCustomHeader(code),
        map: null // Source map support
      }
    }
  }
}

Хуки сервера и сборки

  • configureServer: Добавление пользовательского middleware к dev-серверу
  • transformIndexHtml: Изменение HTML-файлов
  • writeBundle: Выполнение после записи бандла на диск

Каждый хук имеет специфичные типы возвращаемых значений и время выполнения. Хук transform запускается для каждого модуля, поэтому держите его быстрым. Используйте load для затратных операций над конкретными файлами.

Создание вашего первого плагина Vite: практические примеры

Давайте создадим три практических плагина, демонстрирующих распространённые паттерны:

Пример 1: Модификация HTML

function htmlPlugin(): Plugin {
  return {
    name: 'html-modifier',
    transformIndexHtml(html) {
      return html.replace(
        '</head>',
        '<script>console.log("Injected!")</script></head>'
      )
    }
  }
}

Пример 2: Middleware для dev-сервера

function analyticsPlugin(): Plugin {
  return {
    name: 'request-analytics',
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        console.log(`${req.method} ${req.url}`)
        next()
      })
    }
  }
}

Пример 3: Генерация файлов во время сборки

import path from 'path'
import fs from 'fs'
import type { Plugin, ResolvedConfig } from 'vite'

function generateManifest(): Plugin {
  let config: ResolvedConfig
  
  return {
    name: 'generate-manifest',
    configResolved(resolvedConfig) {
      config = resolvedConfig
    },
    writeBundle() {
      const manifestPath = path.join(config.build.outDir, 'manifest.json')
      fs.writeFileSync(manifestPath, JSON.stringify({
        timestamp: Date.now(),
        version: process.env.npm_package_version
      }))
    }
  }
}

Для отладки используйте console.log в ваших хуках для трассировки выполнения. Методы this.warn() и this.error() обеспечивают лучшую отчётность об ошибках, чем выброс исключений.

Продвинутые паттерны плагинов и лучшие практики

Виртуальные модули

Создание модулей, которые не существуют на диске:

const virtualModuleId = 'virtual:my-module'
const resolvedVirtualModuleId = '\0' + virtualModuleId

export function virtualPlugin(): Plugin {
  return {
    name: 'virtual-plugin',
    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedVirtualModuleId
      }
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        return `export const msg = "from virtual module"`
      }
    }
  }
}

Оптимизация производительности

Кэширование затратных преобразований:

const cache = new Map<string, string>()

function cachedTransform(): Plugin {
  return {
    name: 'cached-transform',
    transform(code, id) {
      if (cache.has(id)) return cache.get(id)
      
      const result = expensiveOperation(code)
      cache.set(id, result)
      return result
    }
  }
}

Тестируйте ваши плагины Vite с помощью Vitest, используя API createServer для проверки поведения хуков в изоляции.

Публикация и распространение вашего плагина

Следуйте этим соглашениям при публикации:

  1. Назовите ваш пакет vite-plugin-[name]
  2. Включите "vite-plugin" в ключевые слова package.json
  3. Документируйте, почему он специфичен для Vite (если использует хуки только для Vite)
  4. Добавьте префиксы фреймворка, если специфичен для фреймворка: vite-plugin-vue-[name]

Создайте понятный README с инструкциями по установке, примерами конфигурации и документацией API. Отправьте ваш плагин в awesome-vite, чтобы охватить сообщество.

Заключение

Создание пользовательских плагинов Vite даёт вам полный контроль над процессом сборки. Начните с простых преобразований, используя хуки вроде transform или transformIndexHtml, затем расширяйте до более сложных паттернов по мере необходимости. Plugin API мощный, но при этом доступный — большинству плагинов требуется всего несколько хуков для решения конкретных задач.

Для более глубокого изучения ознакомьтесь с официальной документацией по плагинам Vite и изучите популярные плагины в экосистеме. Ваша следующая оптимизация сборки или улучшение рабочего процесса может быть всего в одном плагине от вас.

Часто задаваемые вопросы

Могу ли я использовать существующие плагины Rollup с Vite?

Да, большинство плагинов Rollup работают с Vite без модификаций. Однако плагины, которые полагаются на хук moduleParsed или требуют функциональности dev-сервера, нуждаются в адаптации для Vite. Проверьте документацию плагина на предмет заметок о совместимости с Vite.

Как отлаживать плагин Vite во время разработки?

Используйте операторы console.log в ваших хуках для трассировки потока выполнения. Методы this.warn() и this.error() обеспечивают лучшую отчётность об ошибках. Вы также можете использовать переменную окружения DEBUG с Vite для просмотра детальных логов.

В чём разница между enforce pre и post в плагинах?

Опция enforce контролирует порядок выполнения плагинов. Pre-плагины выполняются до основных плагинов Vite, post-плагины — после. Используйте pre для входных преобразований и post для модификаций вывода. Без enforce плагины выполняются в порядке их появления.

Должен ли я публиковать свой плагин, если он работает только для моего конкретного случая использования?

Рассмотрите публикацию, если ваш плагин решает проблему, с которой могут столкнуться другие, даже если она специализированная. Чётко документируйте его конкретный случай использования. Для действительно проектно-специфичных плагинов храните их локально или в приватном реестре.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.