# Керування залежностями

> Як сайт встановлює, перевіряє та оновлює свої npm-залежності

---

LLMS index: [llms.txt](/llms.txt)

---

npm-залежності закріплені зафіксованим `package-lock.json`, а встановлення виконують лише перевірені скрипти життєвого циклу. Щодо моделі загроз та обґрунтування цих заходів див. [Безпека ланцюга постачання][Supply-chain security].

## Контракти встановлення {#install-contracts}

CI, devcontainer та Netlify встановлюють із точним блокуванням версій та без скриптів, а потім явно повторно вмикають єдиний перевірений хук: повторну збірку `hugo-extended`, яка завантажує зафіксований бінарний файл Hugo. За середовищами:

- **CI**: `npm run ci:min`; завдання, які збирають сайт, після цього виконують `npm run ci:prepare`.
- **Devcontainer**: `npm run install:safe` — той самий контракт зі збереженням опціональних залежностей.
- **Netlify**: `npm run install:safe`, який виконує [команда збірки][Netlify] після [inert auto-install](#inert-netlify-auto-install), між перевірками чистоти робочого дерева:
  - Відхилення блокування або будь-які інші зміни, видимі в Git, призводять до збою збірки.
  - Для збоїв на шляхах, яких встановлення ніколи не торкалося, див. [Застарілий кеш збірки Netlify](#netlify-build-cache) нижче.
- **Локально**: `npm run install:safe` або стандартне `npm install`, яке слідує за блокуванням, поки воно узгоджується з `package.json`, і обмежує скрипти життєвого циклу [дозволеним списком](#lifecycle-script-allowlist), а не вимикає їх; див. [локальне налаштування][local setup].

Вкладене налаштування [теми Docsy][Docsy] дотримується того самого контракту: крок `prepare` викликає власне точне, без скриптів, встановлення залежностей теми.

### Застарілий кеш збірки Netlify {#netlify-build-cache}

Netlify зберігає кеш збірки для кожного [контексту розгортання][deploy context]:

- Один для робочої версії
- Один для кожного вже зібраного PR, створений на основі кешу робочої версії під час першої збірки PR.

Кожен кеш [містить клон репозиторію][includes a clone of the repository], а перехід на коміт, який прибирає git-субмодуль, залишає робоче дерево субмодуля на місці, тож видалений субмодуль може через кеш повернутися у наступні збірки як невідстежуваний залишок і призвести до збою перевірок чистоти робочого дерева: журнал розгортання показує шлях у статусному рядку з префіксом `??`.

Очистіть відповідний [кеш збірки][build cache], а не додавайте шлях до `.gitignore`:

- **Робоча версія**:
  - Очистіть кеш і розгорніть сайт: **Deploys** > **Trigger deploy**.
- **Deploy Previews**: кожен вже зібраний PR має власну копію кешу, на яку пізніше очищення кешу робочої версії не впливає.
  - Очистіть його зі сторінки останнього розгортання PR: **Retry** > **Clear cache and retry with latest branch commit**. Масового очищення по всіх PR немає.

> [!IMPORTANT]
>
> Після видалення git-субмодуля очистіть кеш збірки робочої версії як частину видалення, до того як залишки поширяться у кеші окремих PR.

## Оновлення залежностей {#updating}

### Планові оновлення {#routine-updates}

`npm run update:packages` оновлює лише `package.json`. До запропонованих версій застосовується [період охолодження](#release-cooldown). Потім перегенеруйте блокування та зафіксуйте обидва файли разом:

```sh
npm install --package-lock-only --ignore-scripts
```

### Пакунки зі скриптами {#script-bearing-packages}

Коли додаєте або оновлюєте пакунок, який має чи потребує запис `allowScripts`, учасник, що вносить зміну:

1. Переглядає скрипти життєвого циклу нової версії.
2. Записує результат, зафіксований разом зі зміною залежності та перевірений під час рецензування PR: потрібний скрипт — як схвалення з точною версією, непотрібний — як заборона на рівні назви (`false`, яка не потребує оновлення при наступних підвищеннях версій).
3. Для нового схвалення також додає пакунок до винятку автоматичного злиття Renovate у [`.github/renovate.json5`][]: кожне підвищення схваленого пакунка потребує наведених вище кроків, тож його PR з оновленням мають чекати на учасника.

### Обслуговування файлу блокування {#lock-file-maintenance}

- **Ви змінили залежності**: перегенеруйте блокування, як у [планових оновленнях](#updating), і зафіксуйте його разом із `package.json`.
- **Конфлікт злиття у файлі блокування**: візьміть версію з `main` і повторно виконайте команду регенерації.
- **Файл блокування змінився, але ви не змінювали залежності** (перевірка `postinstall` попереджає, коли встановлення робить це): це ознака відхилення; відновіть блокування та дослідіть причину, а не фіксуйте перезапис.

## Заходи безпеки ланцюга постачання {#controls}

### Період охолодження випусків {#release-cooldown}

Визначення версій ігнорує випуски, молодші за налаштований мінімальний вік.

- **Вимога**: `min-release-age` у [`.npmrc`][].
- **Сфера дії**:
  - Зачіпаються лише операції визначення версій; точні встановлення з блокуванням (`npm ci`) не визначають версії.
  - npm надає перевагу конфігурації проєкту над конфігурацією користувача, тож суворіший період охолодження у вашому власному `.npmrc` тут послаблюється до значення проєкту; щоб зберегти своє для одного виклику, встановіть змінну середовища `npm_config_min_release_age`, яка має вищий пріоритет за обидва.
- **[Renovate][]**: застосовує власний період охолодження до PR з оновленнями, які він відкриває, заданий `minimumReleaseAge` у [`.github/renovate.json5`][]; довший для оновлень, які зливаються без рецензування людиною.

### Дозволений список скриптів життєвого циклу {#lifecycle-script-allowlist}

Встановлення виконує скрипти життєвого циклу пакунка лише тоді, коли його точна назва та версія внесені до списку дозволів `allowScripts`:

- **Вимога**: мапа `allowScripts` у [`package.json`][], яка стає стандартно закритою через `strict-allow-scripts` у [`.npmrc`][].
- **Заборони**:
  - Запис зі значенням `false` фіксує переглянуту заборону: пакунок встановлюється, його скрипт пропускається.
  - Заборони нічого не надають, тож вони покривають пакунок за назвою, на всіх версіях.
- **Взаємодія з `--ignore-scripts`**:
  - Дозволений список лише фільтрує: він ніколи не вмикає повторно скрипти, які вимикає `ignore-scripts`, тож встановлення без скриптів не виконують жодних, дозволених чи ні.
  - Переглянутий виняток вимагає явного `--ignore-scripts=false` у місці виклику.

### Мінімальна версія npm {#npm-version-floor}

Встановлення завершується збоєм, коли активний npm старший за мінімальну версію engines: найстарішу версію, яка підтримує наведені вище заходи.

- **Забезпечення**:
  - `engines` у [`package.json`][] задає мінімальну версію.
  - `engine-strict` у [`.npmrc`][] робить це закритим.
- **Політика мінімальної версії**:
  - Мінімальна версія зростає, коли npm виправляє прогалини у забезпеченні цих заходів.
  - Вона слідує за версіями npm, вбудованими у Node LTS, тож стандартний інструментарій проходить перевірку.
- **Netlify**:
  - Стандартний npm, вбудований у Node від Netlify, може бути старшим за мінімальну версію; [`NPM_VERSION`][netlify-deps] у [`netlify.toml`][] закріплює версію, яка її задовольняє.
  - Оновлюйте закріплення щонайменше тоді, коли зростає мінімальна версія.

### Автоматичне встановлення Inert Netlify {#inert-netlify-auto-install}

Автоматичне [встановлення][netlify-deps] Netlify на початку збірки нейтралізується [`NPM_FLAGS`][netlify-deps] у [`netlify.toml`][]:

- `--dry-run`: npm вирішує та логує, що змінило б встановлення, але нічого не записує.
- `--ignore-scripts`: скрипти життєвого циклу залишаються вимкненими за явною вказівкою, а не як побічний ефект сухого запуску.

**Сфера дії**: `NPM_FLAGS` — це налаштування збірки Netlify, а не конфігурація npm; він застосовується лише до автоматичного встановлення, ніколи до запусків npm у команді збірки.

**Захист у глибину**: [справжнє встановлення][install contracts] — це `npm ci`, яке замінює `node_modules` повністю, тож залишки автоматичного встановлення чи кешу збірки там не переживають збірку, навіть якщо `node_modules` невидиме для перевірок чистоти робочого дерева (вони бачать лише зміни, видимі в Git).

### Жодного голого npx {#no-bare-npx}

Обвʼязка репозиторію (скрипти пакунка, CI, допоміжні скрипти, документація для учасників) ніколи не викликає бінарний файл як `npx BIN`: на застарілому чи відсутньому `node_modules` `npx` звертається до публічного реєстру та виконує будь-який пакунок, якому належить ця назва. Його запит на встановлення не є захистом: він пропускається в неінтерактивних контекстах і провокує бездумне «так» в інших. Локалізовані копії документації для учасників наздоганяють це правило через [відстеження відхилень][drift tracking].

- **Натомість**:
  - Скрипти пакунка викликають бінарні файли, надані залежностями, безпосередньо; npm додає `node_modules/.bin` до їхнього `PATH`, а відсутній бінарний файл завершується гучним збоєм без жодного звернення до реєстру.
  - Контексти без запису в `PATH` (документація, окремі скрипти) використовують `npm exec --no -- BIN`, який ніколи нічого не встановлює.
- **Забезпечення**: дисципліна рецензування; автоматичної перевірки немає.

<!-- prettier-ignore-start -->
[`.github/renovate.json5`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/.github/renovate.json5
[`.npmrc`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/.npmrc
[`netlify.toml`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/netlify.toml
[`package.json`]: https://github.com/open-telemetry/opentelemetry.io/blob/main/package.json
[Supply-chain security]: ../../design/supply-chain-security/
[build cache]: https://docs.netlify.com/build/configure-builds/troubleshooting-tips/
[deploy context]: https://docs.netlify.com/deploy/deploy-overview/#deploy-contexts
[drift tracking]: /docs/contributing/localization/#track-changes
[includes a clone of the repository]: https://answers.netlify.com/t/what-does-clear-cache-and-deploy-site-do-specifically/9419/2
[install contracts]: #install-contracts
[local setup]: /docs/contributing/development/#local-setup
[netlify-deps]: https://docs.netlify.com/build/configure-builds/manage-dependencies/#npm
[Netlify]: https://www.netlify.com/
[Renovate]: https://docs.renovatebot.com/
[Docsy]: https://www.docsy.dev/
<!-- prettier-ignore-end -->
