В Vite опция define в конфигурации используется для
выполнения статических замен во время сборки. Эти
замены происходят на этапе трансформации кода и полностью удаляются из
рантайма, превращаясь в литеральные значения. Такой подход позволяет
внедрять константы, флаги окружения и конфигурационные значения без
накладных расходов на выполнение.
Ключевая особенность механизма заключается в том, что
define работает на уровне AST-подстановки, а не через
обычные переменные JavaScript. Это означает, что выражения подменяются
до выполнения кода и не существуют в итоговом бандле как переменные.
Опция задаётся в vite.config.js или
vite.config.ts и представляет собой объект, где ключи — это
идентификаторы, а значения — выражения, которые будут подставлены вместо
них.
import { defineConfig } from 'vite'
export default defineConfig({
define: {
__APP_VERSION__: '"1.0.0"',
__DEV__: true,
__API_URL__: '"https://api.example.com"'
}
})
В результате использования:
console.log(__APP_VERSION__)
код преобразуется в:
console.log("1.0.0")
Важно учитывать, что строковые значения должны быть корректно сериализованы, иначе подстановка приведёт к синтаксической ошибке.
Все значения в define являются константами
времени сборки. Они не могут изменяться в runtime и не
поддерживают динамическую логику.
Пример недопустимого ожидания динамики:
define: {
__TIME__: Date.now()
}
Такое выражение не будет пересчитываться при каждом запуске приложения. Оно вычисляется один раз при сборке и фиксируется в итоговом коде.
Одной из распространённых практик является использование
JSON.stringify для автоматической корректной сериализации
значений.
define: {
__API__: JSON.stringify('https://api.example.com'),
__CONFIG__: JSON.stringify({
retry: 3,
timeout: 5000
})
}
Без JSON.stringify сложные структуры могут быть
интерпретированы некорректно, особенно строки и объекты.
Частый сценарий использования — определение режимов приложения:
define: {
__DEV__: JSON.stringify(process.env.NODE_ENV !== 'production'),
__PROD__: JSON.stringify(process.env.NODE_ENV === 'production')
}
Это позволяет полностью исключать ветки кода при минификации:
if (__DEV__) {
console.log('Development mode')
}
После сборки в production:
if (false) {
console.log('Development mode')
}
Дальнейшая оптимизация бандлером приводит к удалению мёртвого кода.
Хотя обе механики связаны с окружением, они принципиально различаются.
import.meta.env:
define:
Пример различия:
console.log(import.meta.env.MODE)
значение определяется в рантайме окружением Vite.
console.log(__MODE__)
значение подставляется как литерал ещё до выполнения кода.
Механизм применяется в случаях, когда требуется:
Пример feature flag:
define: {
__FEATURE_NEW_UI__: JSON.stringify(true)
}
if (__FEATURE_NEW_UI__) {
renderNewUI()
} else {
renderLegacyUI()
}
После сборки одна из веток может быть полностью удалена оптимизатором.
Vite выполняет замену только для глобальных идентификаторов, поэтому важно избегать конфликтов с локальными переменными.
const __API_URL__ = 'local'
Если такой идентификатор определён в define, он будет
заменён даже внутри локальной области видимости, что может привести к
неожиданному поведению.
Подстановка сложных объектов требует сериализации:
define: {
__APP_CONFIG__: JSON.stringify({
api: {
base: '/api',
timeout: 3000
},
features: {
auth: true
}
})
}
Использование:
const config = __APP_CONFIG__
После сборки:
const config = {"api":{"base":"/api","timeout":3000},"features":{"auth":true}}
Статические замены напрямую влияют на tree-shaking и dead code elimination. Поскольку значения становятся литералами, сборщик может:
Пример:
if (__DEV__) {
import('./dev-tools').then(m => m.init())
}
После замены:
if (false) {
import('./dev-tools').then(m => m.init())
}
Такой код полностью исключается из production-бандла.
Несмотря на гибкость, механизм имеет ряд ограничений:
Также следует учитывать, что подстановка происходит текстово, поэтому синтаксическая корректность значений критична.
При проектировании конфигурации через define обычно
применяются следующие подходы:
__APP__,
__FEATURE__)JSON.stringifyСтатические значения должны оставаться действительно статическими, иначе теряется смысл сборочной подстановки и усложняется предсказуемость поведения приложения.