Введение
Нередко в проектах необходимо заводить переменные окружения (environment variables). Существует много способов сделать это. Например, указать переменную "inline", как MY_VAR="my value" node index.js или обозначить источник командой source. Некоторые фреймворки имеют даже целые отдельные пакеты для формирования переменных окружения (прим. nest.js). Но чаще всего за годы работы в сфере фронтенд-разработки мне приходилось работать со способом, который подразумевает содержание .env файлов в проекте. Такие файлы имеют простейший синтаксис вида KEY=VALUE:
# .env
APP_TITLE="My application"
PORT=3000Для чего вообще нужны эти переменные и какого рода данные в них стоит записывать? Ответ:
какие-либо секретные значения, которые не стоит держать в репозитории.
Пример:KEY_SECRETот стороннего API или данные для аутентификации БД;значения, которые различаются для разных режимов работы приложения. Пример:
BASE_URLдля:dev-стенда — https://dev.my-amazing-resource.com
test-стенда — https://stage.my-amazing-resource.com
production — https://my-amazing-resource.com
параметры конфигурации или глобальные константы. Пример:
PORT,PROXY_URL,FEATURE_TOGGLEи т.д.
Таким образом, данные скрыты от чужих глаз и могут конфигурировать наше приложение в (и вне) зависимости от режима его работы. Удобно!
Проблема
А проблема в том, что использование env-переменных не гарантирует нам наличие значения и не дает понимание о его типе данных. Взгляните на следующий конфиг:
# .env
APP_TITLE="My app"
APP_VERSION=1
SHOW_VERSION=true
# COMMENTED_REQUIRED_VALUE=Во-первых, может показаться, что APP_TITLE, APP_VERSION и SHOW_VERSION — это строка, число и логическое значение соответственно. На самом же деле ВСЕ эти значения являются строками.
Во-вторых, имеется закомментированная переменная COMMENTED_REQUIRED_VALUE, которая неспроста названа именно так. Предположим, что это обязательное значение, без которого приложение не может функционировать.
Что мы имеем по итогу:
Для того, чтобы работать со значениями согласно задуманным им типам данных, необходимо сначала привести их к этим типам:
const title = process.env.APP_TITLE; // all is okconst version = Number(process.env.APP_VERSION);const showVersion = JSON.parse(process.env.SHOW_VERSION);
На этом этапе приложение может сломать самая малая опечатка в конфиге, например,Falseвместоfalseили1,0вместо1. Стоит подумать на счет разнообразных проверок, обработки ошибки парсинга и прочем.Так как .env не дает никакой валидации данных, мы, вызывая переменную
COMMENTED_REQUIRED_VALUE, которая считается обязательной и всегда должна быть прописана, НО почему-то осталась закомментированной, получаем ошибку. Окей, просто добавить еще проверок наличия обязательного значения, приведения типов, проверок типов.
Добавили все необходимые приведения типов, проверки, и теперь код...
Нет.
Решение v0
Наверняка, вы уже самостоятельно додумали, что было дальше. Такое решение не очень-то красиво и удобно. Особенно, учитывая гораздо большее количество переменных, появление новых и другие аспекты. В этом разделе я хочу представить
