## Причины отказа от `process.env` в Vite
В экосистеме Node.js переменная `process.env` долгое время считалась стандартным способом передачи конфигурации окружения. В сборщиках вроде Webpack этот механизм активно использовался как на сервере, так и в браузерном коде через подмену значений во время сборки.
Vite использует другой подход. Вместо глобального объекта `process` применяется специальный объект:
```js
import.meta.env
```
Этот механизм основан на стандарте ES-модулей и работает значительно быстрее и предсказуемее.
Основные причины перехода:
* отсутствие полифиллов Node.js в браузере;
* ускорение dev-сервера;
* более прозрачная система инъекции переменных;
* безопасность клиентских переменных;
* совместимость с современным ESM-подходом.
---
## Проблемы использования `process.env` в Vite
При попытке использовать старый синтаксис:
```js
console.log(process.env.API_URL)
```
часто появляется ошибка:
```txt
process is not defined
```
Причина заключается в том, что:
* Vite не внедряет объект `process`;
* браузер не знает о Node.js API;
* Vite избегает тяжёлых полифиллов ради производительности.
Webpack автоматически подменял обращения к `process.env`, создавая иллюзию существования объекта `process` в браузере. Vite намеренно отказался от такой магии.
---
## Объект `import.meta`
В стандарте ES Modules существует специальный объект:
```js
import.meta
```
Он содержит метаинформацию о текущем модуле.
Vite расширяет этот объект собственным свойством:
```js
import.meta.env
```
Пример:
```js
console.log(import.meta.env)
```
В результате можно получить:
```js
{
BASE_URL: '/',
MODE: 'development',
DEV: true,
PROD: false,
VITE_API_URL: 'https://api.example.com'
}
```
---
## Базовая замена `process.env`
### Старый подход
```js
const apiUrl = process.env.API_URL
```
### Новый подход
```js
const apiUrl = import.meta.env.VITE_API_URL
```
---
## Почему нужен префикс `VITE_`
Vite защищает переменные окружения от случайной утечки в клиентский код.
В браузер попадают только переменные, начинающиеся с:
```txt
VITE_
```
Пример `.env` файла:
```env
VITE_API_URL=https://api.site.com
VITE_APP_TITLE=Dashboard
SECRET_KEY=123456
DATABASE_PASSWORD=qwerty
```
В клиентском коде доступны только:
```js
import.meta.env.VITE_API_URL
import.meta.env.VITE_APP_TITLE
```
Следующие значения недоступны:
```js
import.meta.env.SECRET_KEY
import.meta.env.DATABASE_PASSWORD
```
Это предотвращает утечку серверных секретов.
---
## Создание `.env` файлов
### `.env`
Общий файл для всех окружений:
```env
VITE_API_URL=https://api.site.com
```
---
### `.env.development`
Переменные только для разработки:
```env
VITE_API_URL=http://localhost:3000
```
---
### `.env.production`
Переменные для production-сборки:
```env
VITE_API_URL=https://production-api.com
```
---
## Приоритет env-файлов
Vite использует следующую систему приоритетов:
| Файл | Назначение |
| ------------------------ | -------------------------------- |
| `.env` | Общие переменные |
| `.env.local` | Локальные переменные |
| `.env.development` | Development режим |
| `.env.production` | Production режим |
| `.env.development.local` | Локальные development-переменные |
| `.env.production.local` | Локальные production-переменные |
Более специфичные файлы имеют больший приоритет.
---
## Использование встроенных переменных Vite
Vite автоматически предоставляет несколько служебных переменных.
### MODE
Текущий режим:
```js
console.log(import.meta.env.MODE)
```
Результат:
```txt
development
```
или:
```txt
production
```
---
### DEV
Флаг режима разработки:
```js
if (import.meta.env.DEV) {
console.log('development mode')
}
```
---
### PROD
Флаг production:
```js
if (import.meta.env.PROD) {
console.log('production build')
}
```
---
### BASE_URL
Базовый URL приложения:
```js
console.log(import.meta.env.BASE_URL)
```
---
### SSR
Флаг server-side rendering:
```js
if (import.meta.env.SSR) {
console.log('server rendering')
}
```
---
## Миграция проекта с `process.env`
### Исходный код
```js
const api = process.env.API_URL
const mode = process.env.NODE_ENV
```
### После миграции
```js
const api = import.meta.env.VITE_API_URL
const mode = import.meta.env.MODE
```
---
## Замена `NODE_ENV`
В Vite не рекомендуется использовать:
```js
process.env.NODE_ENV
```
Вместо этого используются:
```js
import.meta.env.MODE
```
или:
```js
import.meta.env.DEV
import.meta.env.PROD
```
---
## Проверка режима приложения
### Старый вариант
```js
if (process.env.NODE_ENV === 'production') {
enableAnalytics()
}
```
### Новый вариант
```js
if (import.meta.env.PROD) {
enableAnalytics()
}
```
Либо:
```js
if (import.meta.env.MODE === 'production') {
enableAnalytics()
}
```
---
## Работа с TypeScript
TypeScript может не понимать пользовательские env-переменные.
Например:
```ts
import.meta.env.VITE_API_URL
```
может вызывать ошибку типов.
Для решения создаётся файл:
```txt
vite-env.d.ts
```
Содержимое:
```ts
///
```
---
## Расширение типов env-переменных
Для строгой типизации:
```ts
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_NAME: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
```
---
## Использование env в `vite.config.js`
В конфигурации Vite переменные окружения читаются иначе.
### Неправильно
```js
console.log(import.meta.env.VITE_API_URL)
```
`import.meta.env` недоступен внутри `vite.config.js`.
---
### Правильно
```js
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
console.log(env.VITE_API_URL)
return {}
})
```
---
## Функция `loadEnv`
Сигнатура:
```js
loadEnv(mode, root, prefix)
```
### Пример
```js
const env = loadEnv('development', process.cwd())
```
---
### Третий аргумент `prefix`
Можно загрузить все переменные без фильтрации:
```js
const env = loadEnv(mode, process.cwd(), '')
```
---
## Использование env в React
```jsx
function App() {
return (
{import.meta.env.VITE_APP_TITLE}
)
}
```
---
## Использование env в Vue
```vue
const apiUrl = import.meta.env.VITE_API_URL
{{ apiUrl }}
```
---
## Использование env в Svelte
```svelte
const api = import.meta.env.VITE_API_URL
{api}
```
---
## Использование env в обычном JavaScript
```js
fetch(`${import.meta.env.VITE_API_URL}/users`)
```
---
## Динамическое формирование URL
```js
const base = import.meta.env.VITE_API_URL
const requestUrl = `${base}/posts`
```
---
## Особенности подстановки переменных
Vite заменяет env-переменные на этапе сборки.
Например:
```js
console.log(import.meta.env.PROD)
```
может превратиться в:
```js
console.log(true)
```
Это позволяет:
* удалять мёртвый код;
* уменьшать bundle;
* ускорять выполнение.
---
## Tree Shaking и env
Пример:
```js
if (import.meta.env.DEV) {
console.log('debug')
}
```
В production этот блок полностью удаляется из итогового бандла.
---
## Ошибка отсутствия префикса
### `.env`
```env
API_URL=https://site.com
```
### Код
```js
console.log(import.meta.env.API_URL)
```
Результат:
```txt
undefined
```
Причина — отсутствие префикса `VITE_`.
Правильный вариант:
```env
VITE_API_URL=https://site.com
```
---
## Перезапуск dev-сервера
После изменения `.env` файлов требуется перезапуск Vite dev server.
Иначе новые значения не будут применены.
---
## Использование env в HTML
Vite поддерживает подстановку переменных в HTML.
### `index.html`
```html
%VITE_APP_TITLE%
```
---
### `.env`
```env
VITE_APP_TITLE=Admin Panel
```
---
## Значения env всегда строки
Даже если указано:
```env
VITE_PORT=3000
VITE_DEBUG=true
```
результат:
```js
typeof import.meta.env.VITE_PORT
typeof import.meta.env.VITE_DEBUG
```
будет:
```txt
string
string
```
---
## Преобразование типов
### Число
```js
const port = Number(import.meta.env.VITE_PORT)
```
---
### Boolean
```js
const debug = import.meta.env.VITE_DEBUG === 'true'
```
---
## Работа с JSON
### `.env`
```env
VITE_FEATURES=["chat","search"]
```
### Код
```js
const features = JSON.parse(
import.meta.env.VITE_FEATURES
)
```
---
## Безопасность env-переменных
Нельзя хранить в клиентских env:
* токены БД;
* секретные ключи;
* приватные API-ключи;
* пароли;
* серверные сертификаты.
Любая переменная с префиксом `VITE_` попадает в браузерный bundle и может быть просмотрена пользователем.
---
## Отличие клиентских и серверных env
### Клиент
```js
import.meta.env.VITE_API_URL
```
### Node.js
```js
process.env.DB_PASSWORD
```
Серверные секреты должны оставаться только на backend-стороне.
---
## Использование режима (`mode`)
Запуск:
```bash
vite --mode staging
```
Файл:
```txt
.env.staging
```
Переменные:
```env
VITE_API_URL=https://staging-api.com
```
---
## Доступ к mode в коде
```js
console.log(import.meta.env.MODE)
```
Результат:
```txt
staging
```
---
## Использование env в SSR
При SSR часть кода выполняется на сервере, часть — в браузере.
Проверка окружения:
```js
if (import.meta.env.SSR) {
console.log('server')
} else {
console.log('client')
}
```
---
## Ошибки при миграции с Webpack
### Ошибка №1 — использование `process.env`
```js
process.env.API_URL
```
Решение:
```js
import.meta.env.VITE_API_URL
```
---
### Ошибка №2 — отсутствие префикса
```env
API_URL=http://localhost
```
Нужно:
```env
VITE_API_URL=http://localhost
```
---
### Ошибка №3 — ожидание boolean
```js
if (import.meta.env.VITE_ENABLED)
```
Строка `"false"` всё равно считается truthy.
Правильно:
```js
if (import.meta.env.VITE_ENABLED === 'true')
```
---
### Ошибка №4 — отсутствие перезапуска сервера
После изменения `.env`:
```bash
npm run dev
```
нужно перезапустить.
---
## Использование define вместо env
Иногда вместо env удобнее использовать `define`.
### `vite.config.js`
```js
export default {
define: {
__APP_VERSION__: JSON.stringify('1.0.0')
}
}
```
### Использование
```js
console.log(__APP_VERSION__)
```
---
## Когда использовать `define`
Подходит для:
* compile-time констант;
* версий приложения;
* feature flags;
* глобальных флагов сборки.
---
## Когда использовать `import.meta.env`
Подходит для:
* URL API;
* режимов окружения;
* переменных деплоя;
* конфигурации окружений.
---
## Сравнение `process.env` и `import.meta.env`
| Возможность | process.env | import.meta.env |
| --------------------- | --------------- | --------------- |
| Node.js API | Да | Нет |
| Работа в браузере | Через полифиллы | Нативно |
| Совместимость с ESM | Ограниченная | Полная |
| Поддержка Vite | Ограниченная | Основная |
| Tree shaking | Хуже | Лучше |
| Скорость dev-сервера | Ниже | Выше |
| Безопасная фильтрация | Нет | Да |
---
## Рекомендуемый стиль использования
### Хорошо
```js
const API_URL = import.meta.env.VITE_API_URL
```
### Плохо
```js
const API_URL = process.env.API_URL
```
---
## Централизация env-конфигурации
Удобно создавать отдельный конфигурационный модуль.
### `config.js`
```js
export const config = {
apiUrl: import.meta.env.VITE_API_URL,
debug: import.meta.env.DEV
}
```
### Использование
```js
import { config } from './config'
fetch(config.apiUrl)
```
---
## Типичная структура env-файлов
```txt
.env
.env.local
.env.development
.env.production
.env.staging
```
---
## Практический пример
### `.env.development`
```env
VITE_API_URL=http://localhost:5000
VITE_DEBUG=true
```
---
### `.env.production`
```env
VITE_API_URL=https://api.production.com
VITE_DEBUG=false
```
---
### `api.js`
```js
const API_URL = import.meta.env.VITE_API_URL
export async function getUsers() {
const response = await fetch(
`${API_URL}/users`
)
return response.json()
}
```
---
## Итоговая схема миграции
| Webpack / CRA | Vite |
| ---------------------- | ------------------------------ |
| `process.env.NODE_ENV` | `import.meta.env.MODE` |
| `process.env.API_URL` | `import.meta.env.VITE_API_URL` |
| `process.env` | `import.meta.env` |
| DefinePlugin | `define` |
| Поллифиллы process | Не используются |