🚀 Вышла книга Build Layered Microservices! Купите себе копию прямо сейчас на learnbackend.dev.

В программировании конфигурация — это список пар ключ-значение, используемых для настройки параметров и начальных настроек компьютерных программ, чтобы настроить их поведение.

В Node.js эти значения обычно определяются в окружении процесса, и к ним можно получить доступ через глобальный объект process.env.

Несмотря на практичность, этот метод имеет два недостатка:

  1. Это заставляет программу полагаться на изменчивую среду целевой машины, переменные которой могут быть перезаписаны или удалены другими разработчиками или программами.
  2. Это заставляет разработчиков перезаписывать эти значения каждый раз, когда они хотят изменить среду развертывания приложения (development, staging, production и т. д.).

Лучше использовать несколько файлов конфигурации — по одному на каждую среду развертывания, — которые загружаются при запуске процесса.

Переменная NODE_ENV

Переменная NODE_ENV — это переменная среды, популяризированная средой Express, которая указывает среду развертывания, в которой работает приложение, например development или staging.

Как и к любой другой переменной среды, к ней можно получить доступ через глобальный объект process.env и использовать флаг параметра для запуска определенного фрагмента кода или в качестве динамического параметра для изменения поведения приложения, например, включения и выключения отладки.

Эту переменную можно установить локально, объявив ее прямо перед командой — это означает, что она будет видна только этой программе.

$ NODE_ENV=development node index.js

Или глобально с помощью утилиты экспорта — это значит, что он будет виден всеми программами.

$ export NODE_ENV=development

Чтобы проиллюстрировать это, мы можем создать сценарий с именем index.js, который будет просто регистрировать значение этой переменной NODE_ENV.

// index.js
console.log(process.env.NODE_ENV);

И проверьте это, выполнив следующие команды в новом окне терминала.

$ NODE_ENV=development node index.js
development
$ NODE_ENV=production node index.js
production

Пакет dotenv

dotenv — это пакет Node.js с нулевой зависимостью, который загружает переменные среды из файла в среду запущенного процесса.

$ npm install dotenv

Функция config(), представленная модулем dotenv, по умолчанию попытается проанализировать содержимое файла .env, расположенного в каталоге верхнего уровня проекта.

var_1=123
var_2=hello

Затем он присвоит свое значение глобальному объекту process.env и либо вернет объект, содержащий ключ parsed с загруженным содержимым, либо ключ error в противном случае.

const { config } = require('dotenv');
const env = config();
if (env.error) {
  throw env.error;
}
console.log(env.parsed);

В качестве альтернативы, если мы хотим назвать наш файл конфигурации по-другому, мы можем указать dotenv, какой файл загружать, передав необязательный объект со свойством path в функцию config().

const { config } = require('dotenv');
const env = config({
  path: '/path/to/config'
});


Модуль загрузки конфигурации

Как упоминалось во введении, реальное приложение должно иметь возможность переключаться между несколькими средами развертывания и, следовательно, загружать соответствующий файл конфигурации в соответствии с контекстом, что может быть легко достигнуто с помощью комбинации переменной среды NODE_ENV и пакета dotenv.

Давайте начнем с создания двух файлов конфигурации с именами .env.development и .env.production, которые будут содержать переменную с именем SERVER_PORT, представляющую номер порта, который сервер будет прослушивать для входящих запросов.

$ echo "SERVER_PORT=3000" > .env.development
$ echo "SERVER_PORT=80" > .env.production

Давайте создадим модуль с именем loadenv.js, который экспортирует фабричную функцию, которая:

  1. Использует пакет dotenv для загрузки указанного файла, определяемого следующей интерполяцией строк; который по умолчанию будет равен ".env.development", если переменная NODE_ENV равна undefined.
  2. Выдает ошибку, если файл не существует или по какой-то причине недоступен.
  3. Возвращает форматированный объект на основе проанализированных данных.
// loadenv.js
const { config } = require('dotenv');
module.exports = () => {
  const env = config({  // (1)
    path: `./.env.${process.env.NODE_ENV || 'development'}`,
  });
  if (env.error) {  // (2)
    throw env.error;
  }
  return {  // (3)
    server: {
      port: parseInt(env.parsed.SERVER_PORT, 10),
    },
  };
};

Давайте создадим сценарий с именем index.js, который импортирует модуль загрузчика конфигурации и регистрирует объект, который он возвращает при его вызове.

// index.js
const Env = require('./loadenv');
try {
  const env = Env();
  console.log(env);
} catch(error) {
  console.error(error);
  process.exit(1);
}

Наконец, давайте проверим модуль загрузчика, выполнив следующие команды в окне терминала, которые должны вывести правильное значение SERVER_PORT в соответствии со средой развертывания, определенной для переменной среды NODE_ENV.

$ NODE_ENV=development node index.js
{ server: { port: 3000 } }
$ NODE_ENV=production node index.js
{ server: { port: 80 } }
$ node index.js
{ server: { port: 3000 } }

Теперь вы можете легко добавлять новые переменные в файлы конфигурации.

# .env.development
SERVER_PORT=3000
DATABASE_NAME=project
DATABASE_USER=user
DATABASE_PASSWORD=password

И перегруппировать их под общим ключом внутри объекта, возвращаемого загрузчиком конфигурации.

// loadenv.js
// ...
return {
  server: {
    port: parseInt(env.parsed.SERVER_PORT, 10),
  },
  database: {
    name: env.parsed.DATABASE_NAME,
    user: env.parsed.DATABASE_USER,
    password: env.parsed.DATABASE_PASSWORD,
  },
};

Что дальше?

👉 Нравится ли вам такой контент? Ознакомьтесь с книгой Создание многоуровневых микросервисов на сайте https://learnbackend.dev о том, как создать готовый к эксплуатации микросервис многоуровневой аутентификации с использованием платформы Express, который соответствует отраслевым стандартам с точки зрения методов разработки и архитектуры программного обеспечения от первой строки кода до последней строки документации.