## Чотирикроковий пайплайн генерації AVIF-двійників

AVIF-двійники (`<name>.<ext>.avif`) генерує **виключно** `npx @7n/rules fix image-avif`. Правило `image-compress` відповідає лише за стиснення початкових raster/SVG-файлів через `@nitra/minify-image`, а AVIF лишається окремим правилом. Перевірка виконує чотири кроки в порядку:

1. **Pre-scan**: шукає у `.vue`/`.html` хоча б одне raster-посилання, яке потенційно треба переписати на AVIF-двійник (`import x from '...png'` або `<img src="...png" />`). Пакети з opt-out `disable-avif: true` пропускаються. **Якщо жодного raster-посилання не знайдено — `check image-avif` завершується успіхом одразу: ні `npx --avif`, ні rewrite, ні cleanup-сиріт не виконуються** (нічого було б змінювати). Так уникаємо дорогого `npx @nitra/minify-image` у проєктах, де AVIF не вживається.
2. Запускає `npx @nitra/minify-image --src=. --write --avif` (≥ **3.3.1**) — генерує `<name>.<ext>.avif` поряд з кожним PNG/JPEG/GIF. CLI порівнює sha1 кожного raster-сорсу зі збереженим у `.n-minify-image.tsv` і перезаписує `<source>.avif` при зміні оригіналу.
3. Сканує `.vue` (а також `.html`) файли в кожному workspace-пакеті (root + workspaces) і автоматично переписує raster-посилання на AVIF-двійник у двох формах:
   - **Імпорт-пов'язані** — `import x from '...png|jpg|jpeg|gif'` (далі `:src="x"` у шаблоні);
   - **Прямі статичні** — `<img src="...png" />` у `<template>` (Vite перетворює такий шлях на asset-імпорт на етапі збірки, тож вимога та сама).
4. Видаляє AVIF-сироти: ходить по всіх `<...>.avif` у репозиторії; якщо на двійник не лишилось жодного посилання у `.vue`/`.html` — файл видаляється. **AVIF на диску лишається лише там, де заміна реально відбулась** — тому невикористані оригінали не накопичують `.avif`-«хвости». **Зауваж**: cleanup виконується ЛИШЕ якщо pre-scan на кроці 1 знайшов хоча б одне raster-посилання — інакше осиротілі `.avif` залишаються недоторканими (видаляться вже наступним прогоном, коли в `.vue`/`.html` зʼявиться raster для конвертації).

```vue title="App.vue (після check image-avif)"
<script setup>
import welcomeImage from './assets/welcome.png.avif'
</script>

<template>
  <img :src="welcomeImage" alt="Welcome" />
</template>
```

Реактивне `:src="..."` (з JS-виразом — змінною, тернарником, викликом тощо) **не сканується** — значення обчислюється у рантаймі й шлях туди потрапляє через імпорт або інший резолвинг, який ловить імпорт-перевірка вище. SVG не торкаємо (vector → AVIF безглуздо). Атрибути `data-src=`, `obj.src=` у `<script>` тощо також пропускаються.

Якщо raster-посилання у `.vue`/`.html` не вдалось переписати (наприклад, оригіналу немає на диску, тож і `.avif` не згенерувався) — `check image-avif` падає з помилкою на конкретний файл.

AVIF-двійники **зберігаємо в git** — це готові артефакти для віддачі браузеру (без них ефект від AVIF втрачається на чистому checkout-і).

## Опт-аут для конкретного пакета

У workspace-пакеті, де AVIF-імпорти небажані (наприклад, мобільний бандл або публічний сайт без гарантованої AVIF-підтримки), додай у `package.json` цього пакета. Заборонений typo `disabled-avif` (канон — `disable-avif`): [package.json.deny.json](../package_json/template/package.json.deny.json).

```json title="apps/site/package.json"
{
  "@nitra/minify-image": {
    "disable-avif": true
  }
}
```

Тоді перевірка пропускає `.vue` файли цього пакета і не видаляє наявні `.avif` всередині як «сироти». У root-`package.json` опт-аут діє лише для файлів кореня (вкладені workspaces перевіряються незалежно — вмикай прапор у кожному пакеті, де треба).
