This repository has been archived by the owner on Sep 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Описан guide по работе с env (#4)
* feat: ENV. Описано Intro * feat: ENV. Описано Arch * feat: ENV. Начало csr * feat: ENV. Написано про безопасность * feat: ENV. Закончена дока по CSR * feat: ENV. Закончена дока по SSR * feat: ENV. Дополнена дока про хэш * feat: ENV. Дополнена инфа про d.ts * feat: ENV. Исправлены грамматические ошибки * feat: Изменен процесс генерации env
- Loading branch information
Showing
8 changed files
with
259 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -359,3 +359,10 @@ jsdoc | |
дебагинга | ||
админские | ||
Permissioning | ||
vite | ||
хэшу | ||
неэкспортируемых | ||
WORKDIR | ||
fholzer | ||
brotli | ||
envsubst |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"label": "Работа с env", | ||
"position": 2, | ||
"link": { | ||
"type": "generated-index", | ||
"description": "Работа с env переменными в приложениях" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Работа с env в архитектуре | ||
|
||
В зависимости от сборщика или фреймворка, env переменные доставляются в приложение разным способом: | ||
- В vite через `import.meta.env` | ||
- В webpack через `process.env` | ||
- В нашем подходе для CSR через `window.__ENV__` | ||
|
||
Все обращение к источнику env должны происходить только на уровне [application слоя](https://industrious-search-cdf.notion.site/Application-cc27fa7727fd49599caafc2f2d76ae23). | ||
Работа с env только на уровне application позволяет не зависеть приложению от сборщика или механизма доставки env. | ||
|
||
## ConfigService | ||
|
||
Слои приложения, отличные от **application**, должны получать данные из env через `ConfigService`. | ||
|
||
Подробнее о ConfigService читайте в [документации](https://industrious-search-cdf.notion.site/Config-cbfc6d248c5f47cd80d35f0f2cc95281). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
--- | ||
sidebar_position: 3 | ||
--- | ||
|
||
# CSR + Nginx. Динамические env | ||
|
||
В данном разделе описана инструкция загрузки env переменных при использовании CSR и Nginx для раздачи статики. | ||
|
||
## Пример | ||
|
||
Пример реализован в [vite-boilerplate](https://github.com/kaluga-astral/vite-boilerplate/tree/main). | ||
|
||
## Проблема получения env в build time | ||
|
||
Получение env в build time - это классический подход. | ||
|
||
Работает следующим образом: | ||
1. Сборщик при запуске получает | ||
2. Либо помещает полученные env в `import.meta.env` (vite), либо делает replace `process.env` переменных на их значения непосредственно в js коде (webpack) | ||
3. Переменные доступны в браузере при выполнении js | ||
|
||
Проблемы: | ||
- Для изменения значений env необходимо заново пересобирать приложение | ||
- Если в приложении есть поддержка white label, то для каждого бренда необходимо собирать отдельный docker image. | ||
Это сильно увеличивает время сборки приложения и количество ресурсов, необходимое для поддержки и развертывания | ||
|
||
Для решения описанных проблем необходимо делать inject env в html при запуске docker контейнера. | ||
|
||
## Генерация `index.html` и inject env | ||
|
||
Для того чтобы при изменении env переменных не приходилось заново делать сборку, необходимо при запуске docker контейнера генерировать `index.html` и инжектировать в html env переменные. | ||
|
||
### Генерация `index.html` из `index.template.html` | ||
|
||
В репозитории должен находиться только `index.template.html` - это шаблон html, на основе которого будет построен `index.html`. | ||
|
||
`index.html` должен быть добавлен в `.gitignore`. | ||
|
||
#### Содержимое `index.template.html` | ||
|
||
**[Пример index.template.html](https://github.com/kaluga-astral/vite-boilerplate/blob/main/index.template.html)** | ||
|
||
`index.template.html` содержит всю необходимую для приложения разметку и `<script>` в `<head>`: | ||
```html | ||
<script> | ||
<!-- При запуске dev команды или запуске docker контейнера в __ENV__ подставятся значения из окружения --> | ||
window.__ENV__={}; | ||
</script> | ||
``` | ||
|
||
#### Зачем нужен `index.template.html` и почему `index.html` в `.gitignore`? | ||
|
||
При запуске dev-server должно происходить inject env переменных в `index.html`, | ||
если файл не будет в `.gitignore`, то в репозиторий могут случайно попасть изменения, которых разработчик не делал. | ||
|
||
|
||
#### Для генерации и inject env используются bash скрипты. | ||
|
||
Bash используется по причине того, что для CSR в компании используется Nginx. | ||
Это означает, что в итоговом docker контейнере нет nodejs, а если добавить в образ nodejs, то он вырастет в разы по объему, что повлияет на скорость сборок и оптимизацию хранилища. | ||
|
||
## Dev Mode | ||
|
||
### Генерация `index.html`. `generateEnv.dev.sh` скрипт | ||
|
||
**[Пример generateEnv.dev.sh](https://github.com/kaluga-astral/vite-boilerplate/tree/main/scripts/generateEnv.dev.sh)** | ||
|
||
В режиме разработки необходимо, чтобы перед каждым запуском dev-server выполнялся bash скрипт, который: | ||
1. Парсит все переменные из файла `.env.local` (или `.env.dev`) с префиксами `PUBLIC_` | ||
2. Создает в директории для раздачи статики `index.html` с копией содержимого из `index.template.html`. | ||
Для vite директория для раздачи статики - это корень приложения. Для webpack - public директория | ||
3. Заменяет в `index.html` `window.__ENV__={}` на: | ||
```js | ||
window.__ENV__={"PUBLIC_API_URL":"https://astral.ru"}; | ||
``` | ||
|
||
## Prod Mode | ||
|
||
### Генерация `index.html` | ||
|
||
#### Dockerfile | ||
|
||
При запуске docker контейнера необходимо запускать bash скрипт, который сгенерирует `index.html` файл и инжектирует в него env. | ||
Для этого в `Dockerfile` необходимо добавить команду выполнения скрипта при запуске контейнера: | ||
```dockerfile | ||
FROM node:22-alpine AS build | ||
|
||
WORKDIR /usr/src/app | ||
|
||
COPY package.json package-lock.json* ./ | ||
|
||
COPY . . | ||
|
||
RUN npm i --production | ||
|
||
RUN npm run build | ||
|
||
FROM fholzer/nginx-brotli:v1.19.1 | ||
|
||
COPY .nginx/nginx.conf.template /etc/nginx/nginx.conf.template | ||
COPY --from=build /usr/src/app/dist /usr/share/nginx/html | ||
|
||
# Запускаем контейнер при помощи exec в shell оболочке, чтобы иметь доступ к env | ||
ENTRYPOINT ["sh", "/usr/share/nginx/html/scripts/startup.prod.sh"] | ||
``` | ||
|
||
#### Скрипт `startup.prod.sh` | ||
|
||
**[Пример startup.prod.sh](https://github.com/kaluga-astral/vite-boilerplate/tree/main/scripts/startup.prod.sh)** | ||
|
||
Скрипт `startup.prod.sh` выполняет следующие действия: | ||
1. Достает из текущего окружения все env переменные с префиксом `PUBLIC_` | ||
2. Создает `index.html` с копией содержимого из `index.template.html` | ||
3. Заменяет в `index.html` `window.__ENV__={}` на: | ||
```js | ||
window.__ENV__={"PUBLIC_API_URL":"https://astral.ru"}; | ||
``` | ||
5. Подменяет переменные для nginx на их значения. Читай об этом подробнее [здесь](#подстановка-переменных-в-nginx) | ||
6. Запускает nginx | ||
|
||
### Подстановка переменных в nginx | ||
|
||
В зависимости от env в проекте может изменяться `nginx.conf`. | ||
|
||
Для того чтобы nginx.conf менялся при запуске необходимо: | ||
1. Создать в проекте файл `nginx.conf.template`. Из него будет генерироваться уже настоящий `nginx.conf`. | ||
2. Заменить динамические участки конфига на `${PUBLIC_WS_URL}`. Пример: | ||
``` | ||
http { | ||
... | ||
server { | ||
listen 80; | ||
listen [::]:80; | ||
... | ||
add_header Content-Security-Policy connect-src 'self' ${PUBLIC_WS_URL}; | ||
... | ||
} | ||
} | ||
``` | ||
3. Добавить в `startup.prod.sh` следующий код с переменными, которые необходимо подменить: | ||
```bash | ||
# Необходимо экспортировать, тк envsubst является разветвленным процессом и не знает неэкспортируемых переменных | ||
export PUBLIC_WS_URL | ||
|
||
# Подмена указанных переменных в nginx.conf.template и копирование всего файла в nginx.conf | ||
envsubst "${PUBLIC_WS_URL}" < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf | ||
``` | ||
4. При запуске `startup.prod.sh` подменит в `nginx.conf.template` все переменные на их значения и создаст `nginx.conf`, который и будет использовать для запуска nginx | ||
|
||
## Использование env из сгенерированного файла | ||
|
||
Для использования переменных необходимо определить тип для `window.__ENV__` в `global.d.ts`: | ||
```ts | ||
interface Window { | ||
__ENV__: { | ||
PUBLIC_API_URL: string; | ||
PUBLIC_SENTRY_DSN: string; | ||
PUBLIC_SENTRY_ENV: string; | ||
PUBLIC_RELEASE_TAG: string; | ||
}; | ||
} | ||
``` | ||
|
||
В браузере доступ к env переменным осуществляется через `window.__ENV__` в application слое приложения: | ||
```ts | ||
configService.init({ | ||
apiUrl: window.__ENV__.PUBLIC_API_URL, | ||
monitoringDsn: window.__ENV__.PUBLIC_SENTRY_DSN, | ||
monitoringStand: window.__ENV__.PUBLIC_SENTRY_ENV, | ||
monitoringRelease: window.__ENV__.PUBLIC_RELEASE_TAG, | ||
}); | ||
``` | ||
|
||
## Преимущества inject env в `index.html` | ||
|
||
Inject env позволяет: | ||
- Получать env в браузере синхронно. Нет необходимости делать обработку асинхронного получения данных. Код приложения гарантированно получает все env на этапе выполнения | ||
- Снизить к 0 затраты на загрузку динамических env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
sidebar_position: 0 | ||
--- | ||
|
||
# Intro | ||
|
||
Раздел содержит: | ||
- Как работать с env в рамках единой архитектуры | ||
- Как генерировать и загружать env в CSR (Client Side Rendering) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
sidebar_position: 2 | ||
--- | ||
|
||
# Безопасность. Использование PUBLIC и PRIVATE env | ||
|
||
Для env переменных, которые должны быть доступны в браузере, необходимо указывать префикс `PUBLIC_`: | ||
- `PUBLIC_API_URL` | ||
- `PUBLIC_BRAND` | ||
|
||
Для env переменных, которые должны быть доступны только на стадии билда, необходимо указывать префикс `PRIVATE_`: | ||
- `PRIVATE_RELEASE_MANAGER_TOKEN` | ||
|
||
## Мотивация | ||
|
||
Если все env переменные сделать доступные в браузере, то злоумышленники могут найти уязвимости системы потому, что env хранит информацию о сервере, на котором запускает билд или само приложение. | ||
|
||
Именно по этой причине Nextjs и Vite требуют для env переменных префиксы: `NEXT_PUBLIC | NEXT_PRIVATE`, `VITE_`. | ||
|
||
## CSR | ||
|
||
Если приложение собирается через `webpack`, то достаточно просто следовать указанным ранее соглашениям по именованию. | ||
|
||
Если приложение собирается через `vite`, то необходимо использовать [envPrefix](https://vitejs.dev/config/shared-options.html#envprefix) для кастомизации префикса. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
sidebar_position: 4 | ||
--- | ||
|
||
# Nextjs. SSR и SSG | ||
|
||
Если на проекте используется Nextjs, то необходимо использовать тот механизм работы с env, который предоставляет фреймворк. | ||
|
||
При SSR и SSG env нужны при билде. |