Свойство apply используется для условного подключения
плагина в зависимости от режима работы Vite. Оно позволяет запускать
плагин только:
serve или
build);Без apply плагин участвует во всех этапах жизненного
цикла Vite, включая dev-сервер и production-build. Во многих случаях это
приводит к лишней обработке файлов, ненужным трансформациям и ухудшению
производительности.
apply поддерживает два варианта:
Строковое значение:
'serve''build'Функцию:
true или false.Простейший пример:
export default function myPlugin() {
return {
name: 'my-plugin',
apply: 'serve',
}
}
Такой плагин будет активен только при запуске dev-сервера.
serveРежим serve соответствует команде:
vite
или:
vite serve
Плагин подключается только во время разработки.
Пример:
export default function devLoggerPlugin() {
return {
name: 'dev-logger',
apply: 'serve',
transform(code, id) {
console.log('Transform:', id)
return code
},
}
}
Во время production-сборки плагин полностью игнорируется.
buildРежим build соответствует команде:
vite build
Плагин выполняется исключительно при production-сборке.
Пример:
export default function bannerPlugin() {
return {
name: 'banner-plugin',
apply: 'build',
generateBundle(_, bundle) {
for (const file of Object.values(bundle)) {
if (file.type === 'chunk') {
file.code =
'/* Production Build */\n' + file.code
}
}
},
}
}
Такой подход особенно полезен для:
Во время инициализации Vite анализирует каждый плагин.
Если присутствует apply, Vite проверяет:
Если условие не выполняется:
Это важное отличие от ручных проверок внутри самих хуков.
Плохо:
transform(code) {
if (process.env.NODE_ENV !== 'development') {
return null
}
return code
}
Правильно:
apply: 'serve'
Во втором случае Vite вообще не активирует плагин.
applyФункция предоставляет полный контроль над условиями подключения.
Сигнатура:
apply(config, env)
Где:
config — итоговая конфигурация Vite;env — информация о текущем запуске.Объект env содержит:
{
command,
mode,
ssrBuild
}
Текущая команда:
'serve'
'build'
Текущий режим:
vite --mode development
vite build --mode production
vite build --mode staging
Показывает SSR-сборку:
true
false
Пример:
export default function plugin() {
return {
name: 'conditional-plugin',
apply(_, { command }) {
return command === 'build'
},
}
}
Аналог:
apply: 'build'
Но функциональная форма позволяет строить сложные условия.
Подключение плагина только в staging-режиме:
export default function stagingPlugin() {
return {
name: 'staging-plugin',
apply(_, { mode }) {
return mode === 'staging'
},
}
}
Запуск:
vite build --mode staging
SSR-сборка:
export default function ssrPlugin() {
return {
name: 'ssr-plugin',
apply(_, { ssrBuild }) {
return ssrBuild
},
}
}
Только client-build:
export default function clientPlugin() {
return {
name: 'client-plugin',
apply(_, { ssrBuild }) {
return !ssrBuild
},
}
}
Часто требуется учитывать сразу несколько факторов.
Пример:
export default function productionClientPlugin() {
return {
name: 'production-client-plugin',
apply(_, { command, ssrBuild }) {
return command === 'build' && !ssrBuild
},
}
}
Плагин работает:
apply удобно комбинируется с .env.
Пример:
VITE_ENABLE_ANALYZER=true
export default function analyzerPlugin() {
return {
name: 'analyzer-plugin',
apply(_, env) {
return (
env.command === 'build' &&
process.env.VITE_ENABLE_ANALYZER === 'true'
)
},
}
}
Очень распространённый подход — условное добавление плагинов прямо в
массив plugins.
Пример:
import { defineConfig } from 'vite'
import inspect from 'vite-plugin-inspect'
export default defineConfig(({ command }) => {
return {
plugins: [
command === 'serve' && inspect(),
],
}
})
Однако здесь существует важное отличие.
apply и условным добавлением в pluginsplugins: [
command === 'serve' && plugin(),
]
Плагин вообще не создаётся.
applyplugins: [
plugin(),
]
apply: 'serve'
Плагин создаётся, но Vite решает, активировать его или нет.
applyapply особенно полезен, если:
Условное добавление лучше подходит, если:
Пример:
plugins: [
process.env.ANALYZE === 'true'
? visualizer()
: null,
]
apply и enforce работают независимо.
Пример:
export default function plugin() {
return {
name: 'pre-dev-plugin',
apply: 'serve',
enforce: 'pre',
}
}
Плагин:
export default function hmrDebugPlugin() {
return {
name: 'hmr-debug',
apply: 'serve',
handleHotUpdate(ctx) {
console.log('Updated:', ctx.file)
},
}
}
Во время production-build HMR-хук вообще не существует.
export default function removeConsolePlugin() {
return {
name: 'remove-console',
apply: 'build',
transform(code, id) {
if (!id.endsWith('.js')) {
return null
}
return code.replace(/console\.log\(.*?\);?/g, '')
},
}
}
export default function ssrGlobalsPlugin() {
return {
name: 'ssr-globals',
apply(_, { ssrBuild }) {
return ssrBuild
},
transform(code) {
return code.replace(
'__SERVER__',
'true'
)
},
}
}
Плагин может принимать параметры.
export default function myPlugin(options = {}) {
return {
name: 'my-plugin',
apply(_, env) {
if (options.devOnly) {
return env.command === 'serve'
}
return true
},
}
}
Использование:
myPlugin({
devOnly: true,
})
В Vite mode и NODE_ENV — разные
сущности.
Ошибка:
apply(_, env) {
return env.mode === 'production'
}
Если запуск:
vite build --mode staging
то условие не выполнится.
Для production-build правильнее использовать:
env.command === 'build'
Неправильно:
transform(code) {
if (this.apply === 'build') {
return code
}
}
apply — не runtime-параметр хука, а механизм подключения
плагина.
Неправильно:
apply(_, env) {
return env.command
}
Хотя JavaScript интерпретирует строку как truthy-значение, код становится неявным.
Правильно:
apply(_, env) {
return env.command === 'serve'
}
Правильное использование apply:
Особенно заметен эффект:
Крупные проекты часто разделяют плагины по категориям:
apply: 'serve'
Примеры:
apply: 'build'
Примеры:
apply(_, env) {
return env.ssrBuild
}
Примеры:
apply(_, env) {
return !env.ssrBuild
}
Примеры:
export default function analyticsPlugin() {
return {
name: 'analytics-plugin',
apply(config, env) {
return (
env.command === 'build' &&
!env.ssrBuild &&
env.mode === 'production' &&
config.build.minify !== false
)
},
}
}
Условия:
Во время отладки полезно выводить информацию:
export default function debugPlugin() {
return {
name: 'debug-plugin',
apply(config, env) {
console.log(env)
return true
},
}
}
Пример вывода:
{
command: 'serve',
mode: 'development',
ssrBuild: false
}
Хорошо:
apply: 'build'
Плохо:
apply(_, env) {
return env.command === 'build'
}
Если достаточно строкового режима, функциональная форма не нужна.
Все инструменты разработки желательно ограничивать:
apply: 'serve'
Это предотвращает случайное попадание debug-кода в production.
SSR-плагины не должны попадать в client-build.
Правильно:
apply(_, env) {
return env.ssrBuild
}
Плохо:
transform(code, id) {
if (isDev) {
...
}
if (isBuild) {
...
}
}
Лучше разделить логику на несколько плагинов с разным
apply.
Вместо:
export default function plugin() {
return {
name: 'mega-plugin',
transform(code) {
if (isDev) {
...
}
if (isBuild) {
...
}
},
}
}
Предпочтительнее:
devPlugin()
buildPlugin()
С разными условиями:
apply: 'serve'
и
apply: 'build'
Такой подход: