Система окружений в Vite тесно связана с механизмом работы плагинов. Каждый плагин может выполняться в разных контекстах:
Во время выполнения хуков Vite предоставляет объект окружения, содержащий сведения о режиме запуска, конфигурации, SSR-контексте, текущей команде и других параметрах. Доступ к этим данным позволяет создавать адаптивные плагины, изменяющие поведение в зависимости от среды выполнения.
Наиболее важным этапом становится понимание того, какие данные доступны:
configПервым источником информации об окружении является хук
config.
export default function myPlugin() {
return {
name: 'my-plugin',
config(config, env) {
console.log(env.command)
console.log(env.mode)
}
}
}
Объект env содержит:
{
command: 'serve',
mode: 'development',
isSsrBuild: false,
isPreview: false
}
commandПоле command определяет тип запуска:
serve
или
build
Это позволяет разделять логику:
config(config, env) {
if (env.command === 'serve') {
console.log('dev server')
}
if (env.command === 'build') {
console.log('production build')
}
}
modemode определяет активный режим окружения.
Примеры:
vite --mode development
vite --mode production
vite --mode staging
vite --mode testing
Внутри плагина:
config(config, env) {
console.log(env.mode)
}
Пример адаптации поведения:
config(config, env) {
if (env.mode === 'staging') {
return {
define: {
__API__: '"https://staging-api.local"'
}
}
}
}
Во время production build Vite может запускаться в SSR-режиме.
Проверка:
config(config, env) {
if (env.isSsrBuild) {
console.log('SSR build')
}
}
Это особенно важно для:
Пример:
config(config, env) {
if (env.isSsrBuild) {
return {
build: {
target: 'node18'
}
}
}
}
configResolvedХук configResolved предоставляет полностью обработанную
конфигурацию.
export default function myPlugin() {
let resolvedConfig
return {
name: 'my-plugin',
configResolved(config) {
resolvedConfig = config
}
}
}
Этот объект содержит:
ResolvedConfigТипичный пример:
configResolved(config) {
console.log(config.command)
console.log(config.mode)
console.log(config.root)
console.log(config.base)
}
Доступные свойства:
config.server
config.build
config.resolve
config.css
config.define
config.plugins
Пример использования:
configResolved(config) {
if (config.command === 'serve') {
console.log('development mode')
}
}
Наиболее распространённый паттерн:
export default function myPlugin() {
let config
return {
name: 'my-plugin',
configResolved(resolvedConfig) {
config = resolvedConfig
},
transform(code, id) {
console.log(config.mode)
return code
}
}
}
Плагин сохраняет окружение в замыкании и затем использует его в других хуках.
transformХук transform не получает объект окружения напрямую.
Поэтому окружение обычно сохраняется через
configResolved.
export default function plugin() {
let config
return {
name: 'env-transform-plugin',
configResolved(resolved) {
config = resolved
},
transform(code, id) {
if (config.command === 'serve') {
console.log('dev transform')
}
return code
}
}
}
Практический пример:
transform(code) {
if (config.command === 'serve') {
return code.replace(
'__DEV__',
'true'
)
}
return code.replace(
'__DEV__',
'false'
)
}
applyДля ограничения окружения Vite предоставляет поле
apply.
export default function plugin() {
return {
name: 'build-only',
apply: 'build'
}
}
Варианты:
apply: 'serve'
apply: 'build'
applyapply может быть функцией:
apply(config, env) {
return env.mode === 'staging'
}
Пример:
export default function plugin() {
return {
name: 'staging-plugin',
apply(config, env) {
return env.mode === 'staging'
}
}
}
process.envВ Node.js-плагинах доступно стандартное окружение:
process.env.NODE_ENV
process.env.API_URL
process.env.PORT
Пример:
transform(code) {
console.log(process.env.NODE_ENV)
return code
}
Однако необходимо понимать различие между:
mode
и NODE_ENVЭти значения не всегда совпадают.
Пример:
vite build --mode development
Результат:
mode = development
NODE_ENV = production
Поэтому внутри плагинов предпочтительнее использовать:
config.mode
или
env.mode
.env внутри
плагинаVite предоставляет функцию loadEnv.
import { loadEnv } from 'vite'
export default function plugin() {
let env
return {
name: 'env-plugin',
config(config, viteEnv) {
env = loadEnv(
viteEnv.mode,
process.cwd(),
''
)
}
}
}
.envAPI_URL=https://api.local
APP_VERSION=1.0.0
Использование:
config(config, viteEnv) {
const env = loadEnv(
viteEnv.mode,
process.cwd(),
''
)
console.log(env.API_URL)
}
loadEnv
лучше process.envprocess.env не учитывает автоматически:
.env.production;.env.development;.env.local;.env.staging;loadEnv загружает env-файлы в соответствии с режимом
Vite.
Vite по умолчанию экспортирует клиенту только переменные:
VITE_*
Но внутри плагинов можно читать любые значения:
SECRET_KEY=hidden
DATABASE_URL=internal
const env = loadEnv(mode, process.cwd(), '')
Пустой префикс:
''
означает загрузку всех переменных.
configureServerХук configureServer предоставляет dev server.
configureServer(server) {
console.log(server.config.mode)
}
Доступно:
server.config
server.middlewares
server.ws
server.httpServer
server.moduleGraph
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (server.config.mode === 'development') {
console.log(req.url)
}
next()
})
}
transformВ некоторых хуках присутствует SSR-флаг.
transform(code, id, options) {
console.log(options?.ssr)
}
Значения:
true
false
undefined
Пример:
transform(code, id, options) {
if (options?.ssr) {
return code.replace(
'__TARGET__',
'"server"'
)
}
return code.replace(
'__TARGET__',
'"client"'
)
}
resolveIdresolveId(source, importer, options) {
if (options?.ssr) {
console.log('SSR resolve')
}
}
Это особенно полезно для:
loadload(id, options) {
if (options?.ssr) {
return 'export default "server"'
}
return 'export default "client"'
}
this.metaНекоторые Rollup-хуки предоставляют метаинформацию.
buildStart() {
console.log(this.meta.watchMode)
}
watchMode:
true
false
Пример:
buildStart() {
if (this.meta.watchMode) {
console.log('watch mode enabled')
}
}
Часто используется комбинация нескольких источников:
export default function plugin() {
let config
let env
return {
name: 'advanced-plugin',
configResolved(resolved) {
config = resolved
env = loadEnv(
resolved.mode,
resolved.root,
''
)
},
transform(code, id, options) {
const isSSR = options?.ssr
const isDev = config.command === 'serve'
const isProd = config.command === 'build'
console.log({
isSSR,
isDev,
isProd,
api: env.API_URL
})
return code
}
}
}
Плагины могут адаптироваться под:
Пример:
transform(code, id, options) {
if (options?.ssr) {
return code.replace(
'__RUNTIME__',
'"node"'
)
}
return code.replace(
'__RUNTIME__',
'"browser"'
)
}
Хорошо спроектированный плагин:
NODE_ENV;configResolved;Неверный подход:
const mode = process.env.MODE
Во время загрузки модуля значения ещё могут быть недоступны.
Правильный подход:
config(config, env) {
console.log(env.mode)
}
или:
configResolved(config) {
console.log(config.mode)
}
Неверно:
let config
за пределами фабрики плагина.
Правильно:
export default function plugin() {
let config
return {
name: 'plugin',
configResolved(resolved) {
config = resolved
}
}
}
Иначе несколько инстансов Vite могут конфликтовать между собой.
Неверно:
transform(code) {
return code.replace(
'window.',
''
)
}
Такой код может ломать SSR.
Корректный вариант:
transform(code, id, options) {
if (options?.ssr) {
return code
}
return code.replace(
'window.',
''
)
}
Неверный код:
if (mode === 'production')
Во многих проектах используются:
Более гибкий вариант:
const isDev = command === 'serve'
const isBuild = command === 'build'
import { loadEnv } from 'vite'
export default function plugin() {
let config
let env
return {
name: 'full-env-plugin',
configResolved(resolved) {
config = resolved
env = loadEnv(
resolved.mode,
resolved.root,
''
)
},
transform(code, id, options) {
const context = {
mode: config.mode,
command: config.command,
ssr: options?.ssr,
api: env.API_URL
}
console.log(context)
return code
},
configureServer(server) {
console.log(server.config.mode)
}
}
}
| Источник | Назначение |
|---|---|
env.mode |
текущий mode |
env.command |
serve/build |
configResolved() |
итоговая конфигурация |
options.ssr |
SSR-контекст хука |
server.config |
окружение dev server |
loadEnv() |
загрузка .env |
process.env |
Node.js environment |
this.meta.watchMode |
watch mode |
env.commandПодходит для:
env.modeПодходит для:
options.ssrПодходит для:
loadEnvПодходит для:
configResolvedПодходит для: