Замена process.env на import.meta.env

## Причины отказа от `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 ``` --- ## Использование 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 | Не используются |