Змінні середовища Vue.js

Olivier Pichon Jan 26 · 6 min read

Змінні середовища в vue.js, звичайно, є критичними, щоб ваш додаток підтримував декілька середовищ (локальне, розробку, постановку, виробництво). Однак вони часто виявляють більше клопоту, ніж того варті. Кожен розробник, кого я знаю, провів декілька годин, намагаючись з'ясувати дивні помилки, пов’язані із завантаженням env vars програми (як правило, рядки, коли очікуєш логічне), а потім ще пару годин, намагаючись розробити остаточне рішення для їх вирішення. Сукупно кількість витрачених людино-годин повинна бути приголомшливою. Ми пропонуємо тут просте рішення для обробки змінних оточуючих середовищ у додатку vue.js. Незабаром ми створимо плагін Vue.

Dotenv: правильний шлях

dotenv - це фантастичний інструмент для управління вашими env vars, і вам слід його використовувати. Якщо у вашому додатку використовується vue-cli, він уже включений.

За допомогою dotenv ви визначаєте оточення у .env-файлі, збереженому у кореневому каталозі вашого проекту. Цей файл не повинен знаходитись під контролем версій. Ми наполегливо пропонуємо включити .env.example файл, також у кореневий каталог вашого проекту, який знаходиться під контролем версій, щоб запропонувати обґрунтовані параметри за замовчуванням та вказати, які змінні доступні для використання іншими розробниками. Env vars, визначені в .env, доступні через process.env.VAR_NAME (за винятком додатка vue.js, як пояснено нижче).

Переконайтесь, що .env не знаходиться під контролем версій

# .gitgnore
.env*
!.env.example

Ваш файл README повинен містити такі інструкції:

My app
======...
Installation
  • Copy .env.example to .env and adjust the values where necessary.

Ось приклад файлу `.env.example`:

# .env.example HOST=localhost PORT=8080 VUE_APP_API_ROOT=https://localhost:8081 VUE_APP_API_KEY=SECRET

та відповідний `.env` файл:

# .env HOST=localhost PORT=20000 VUE_APP_API_ROOT=https://localhost:20001 VUE_APP_API_KEY=1234567890abcdef

Ваш файл `.env` повинен містити значення для вашого локального середовища. Таким чином ви можете використовувати власні налаштування, не втручаючись у налаштування інших розробників. Оскільки він знаходиться під контролем версій, файл `.env.example` не повинен містити чутливих або секретних значень.

Наведені вище приклади пропонують порт 8080 для локального запуску вашої програми, який було змінено на 20000. Це буде використано так:

# vue.config.js module.exports = { …, devServer: { host: process.env.HOST || localhost, open: true, port: process.env.PORT || 8080 }, … }

Зауважте, що `env.example` показує значення за замовчуванням, визначені в блоці коду вище.

=== Використання env vars через process.env

Усі змінні доступні на через `process.env.VAR_NAME`. З vue-cli, якщо ви хочете, щоб змінна була доступна у пакеті клієнта, ви повинні почингати її ім'я `VUE_APP_` (https://cli.vuejs.org/guide/mode-and-env.html#using-env -перемінний код-на стороні клієнта-код).

Код поза пакетом клієнтів (наприклад, vue.config.js) має доступ до всіх змінних середовища. У прикладі з попереднього пункту використовувались HOST та PORT.

=== Кращі практики

На відміну від офіційних документів `vue-cli`, я настійно рекомендую дотримуватися кращих практик `dotenv` та не використовувати специфічні для режиму файли env (наприклад, `.env.test`, `.env.develop` тощо). Env vars слід вводити лише під час збирання або запуску.

Крім того, я не рекомендую використовувати виклики до `process.env` у коді з кількох причин:

1. `process.env` - це інтерфейс між вашим додатком та навколишнім середовищем. Немає жодної причини допускати це всередину вашого коду.

2. Змінні, оброблені `dotenv`, завжди є рядками. Рано чи пізно це неминуче призводить до плутанини. Якщо я визначу флаг як env var (наприклад, для вмикання можливостей) в коді, я очікую, що він буде булевим. Отримання рядка призведе до плутанини, а потім маємо додати трохи дурного коду, щоб перевірити правдивість рядка. Загалом суцільна каша.

3. Програми Vue.js можуть мати багато знінних, і файл .`env` може швидко забитись. Якщо, як і я (і як і слідує бути), ви хочете впорядкувати своє оточення в алфавітному порядку, то стає важко чітко вказати, що потрібно визначати локально, що можна перевизначити, а що не можна перекривати. В ідеалі `.env` слід використовувати лише для змінних, які можна або потрібно перекрити локально.

=== Config.js

Як рішення, я хочу ввести, так сказати, «єдину точку входу», тобто єдиний фрагмент коду, який обробить усі змінні середовища для програми та поверне належним чином набране значення.

Ми можемо почати з цього:

[source,js]

# config.js const config = { apiBaseUrl: process.env.VUE_APP_API_BASE_URL, locale: process.env.VUE_APP_LOCALE, sso: { enabled: process.env.VUE_APP_SSO_ENABLED, … }, … }

export { config }

Для зручності це можна визначити як плагін Vue:

[source,js]

export default { install (Vue) { Vue.appConfig = config Vue.prototype.$appConfig = config } }

У своєму коді, замість доступу до env vars, ви отримуєте доступ до налаштувань конфігурації через `this.$appConfig` або `$appConfig`, наприклад, `this.$appConfig.apiBaseUrl` або `$appConfig.sso.enabled`.

Цей файл конфігурації також повинен містити відповідні типові параметри. Моя практика - визначати параметри-замовчування для локального середовища. Для розгортань на стороні сервера (розробка, стейдж, виробництво) я вважаю за краще чітко визначити всі змінні середовища під час збирання чи часу виконання, тому будь-що за замовчуванням буде перекрито.

Простий спосіб зробити це так:

[source,js]

# config.jsconst config = { apiBaseUrl: process.env.VUE_APP_API_BASE_URL || http://localhost:8081, locale: process.env.VUE_APP_LOCALE || en, sso: { enabled: process.env.VUE_APP_SSO_ENABLED || false }, … }

Однак я також хочу, щоб цей файл конфігурації надійно передав усі налаштування конфігурації відповідному типу. Для цього я використовую цю додаткову логіку:

[source,js]

# config.jsconst config = { apiBaseUrl: parse(process.env.VUE_APP_API_BASE_URL, http://localhost:8081), locale: parse(process.env.VUE_APP_LOCALE, en), sso: { enabled: parse(process.env.VUE_APP_SSO_ENABLED, false), … }, … }

function parse (value, fallback) { if (typeof value === undefined) { return fallback } switch (typeof fallback) { case boolean : return !!JSON.parse(value) case number : return JSON.parse(value) default : return value } }

Оскільки всі параметри конфігурації визначені в одному файлі, розробник може легко знайти, які налаштування доступні, і файл `.env.example` може бути зарезервований, щоб вказати лише ті змінні, які потрібно перекрити локально. Звичайно, самому .env-файлу потрібно було б визначити лише ті самі налаштування. У більшості випадків файли `.env.example` та `.env` можуть бути скорочені до нуля.

На даний момент ми досягли всіх заявлених цілей: єдиний файл, що забезпечує всі параметри конфігурації додатків на основі змінних середовища, завантажених через `dotenv`, перетворені у відповідний тип та з можливістю визначати параметри за замовчуванням, щоб файл `.env` міг бути скорочений до мінімуму.

Але ми можемо піти на крок далі і набрати ще більше значення, додавши підтримку перемикань функцій.

=== Перемикачі функцій

Перемикачі функцій надзвичайно корисні, і ви дуже хочете їх використовувати. Для цього доступно кілька гарних пакетів, але це так просто реалізувати в `config.js`, що краще уникнути ще однієї залежності.

[source,js]

# config.js

const config: { …,

  features: {
    example: parse(process.env.VUE_APP_FEATURE_EXAMPLE, false),
    ...
  },  ...
}

function feature (name) { return config.features[name] }

export default { install (Vue) { Vue.appConfig = config Vue.feature = feature Vue.prototype.$appConfig = config Vue.prototype.$feature = feature } }

Для визначення перемикання функції додайте дочірню властивість у `config.features`. За домовленістю, щоб все було просто, я називаю відповідну env var після перемикання з префіксом `VUE_APP_FEATURE_`. Наприклад, перемикання функції `example` визначається змінною `VUE_APP_FEATURE_EXAMPLE`.

Щоб перевірити, чи увімкнено цю функцію, викличте цей `this.$feature('example')` або `$feature('example')`.

=== Висновок

Here is the full config.js file:

[source,js]

# config.jsconst config = { …, features: { … }. … }

function feature (name) { return config.features[name] }

function parse (value, fallback) { if (typeof value === undefined) { return fallback } switch (typeof fallback) { case boolean : return !!JSON.parse(value) case number : return JSON.parse(value) default : return value } }

export { config }

export default { install (Vue) { Vue.appConfig = config Vue.feature = feature Vue.prototype.$appConfig = config Vue.prototype.$feature = feature } }

Скопіюйте цей файл у каталог `src/` та додайте його до `main.js`:

[source,js]

# main.jsimport Vue from 'vue` import configPlugin from '@/config’Vue.use(configPlugin)