Back

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

Как создавать и использовать плагины в 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 без модификаций. Однако плагины, которые полагаются на хук moduleParsed или требуют функциональности dev-сервера, нуждаются в адаптации для Vite. Проверьте документацию плагина на предмет заметок о совместимости с Vite.

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

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

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

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. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay