# Обфускація збірки Parcel

@afterpack/parcel-optimizer обфускує кожен запакований бандл у пам'яті як Optimizer для Parcel 2 і зупиняє збірку з помилкою (fail closed), замість того щоб випустити чанк, який у продакшені віддає 404.

Source: https://www.afterpack.dev/uk/docs/frameworks/parcel

`@afterpack/parcel-optimizer` — це **Optimizer** для Parcel 2, зареєстрований у `.parcelrc`. Він обфускує кожен запакований бандл **у пам'яті**, під час власної фази оптимізації Parcel, тож бандл ніколи не потрапляє на диск у відкритому вигляді.

> **Не @afterpack/parcel**
>
> Пакет називається `@afterpack/parcel-optimizer`.

## Встановлення

```bash
npm install -D @afterpack/parcel-optimizer
```

```jsonc
// .parcelrc
{
  "extends": "@parcel/config-default",
  "optimizers": {
    "*.{js,mjs,cjs}": ["...", "@afterpack/parcel-optimizer"]
  }
}
```

Розгортання `"..."` важливе: воно зберігає стандартні оптимізатори Parcel (`@parcel/optimizer-swc`) і ставить AfterPack **останнім**. AfterPack працює після мініфікації. Peer-залежність: Parcel `>=2.9.0`.

## Збірка

Записи в `.parcelrc` є просто назвами пакетів без вбудованих параметрів, тож параметри беруться з `afterpack.json` у корені проєкту, єдиного файлу конфігурації, який читає кожна інтеграція AfterPack:

```json
{
  "seed": "git",
  "preset": "medium"
}
```

Записуються лише артефакти в корені проєкту; поруч із вашими бандлами нічого не з'являється:

- **По одному [`protectionMap.html`](https://www.afterpack.dev/uk/docs/protection-map) на бандл**, у `.afterpack/<bundle>.<id>.protectionMap.html`, коли мапу ввімкнено (див. розділ [Перевірка](#verify)).
- Source map, коли його вмикає [політика sourceMap](https://www.afterpack.dev/uk/docs/config#sourceMap-enabled). Він повертається в Parcel, а не записується напряму, тож Parcel сам дає йому ім'я і видає його з власним хешем вмісту.

`.afterpack/` має власний `.gitignore`; плагін ніколи не редагує `.gitignore` вашого проєкту.

## Перевірка

Оскільки об'єднаного звіту немає, перевіряйте потрібний бандл напряму: `.afterpack/<bundle-name>.<id>.protectionMap.html` для кожної точки входу або лінивого чанка, які запакував Parcel. За замовчуванням звіт записується, коли бандл має source map і збірка не працює в CI (`CI=true` або `CI=1`); задайте `"protectionMap": { "enabled": true }` в `afterpack.json`, щоб [увімкнути його примусово](https://www.afterpack.dev/uk/docs/config#protectionMap-enabled). Кожен звіт містить увесь ваш вихідний код. Ніколи не комітьте його і не роздавайте з сервера.

Щоб перевіряти розгортання, додайте reporter плагіна до команди збірки. Тоді кожна збірка записує квитанцію захисту в `.afterpack/receipts/` у [корені вашого проєкту](https://www.afterpack.dev/uk/docs/cli#files), по одній на кожен цільовий каталог виводу (`.afterpack/receipts/dist.json` для `dist`). [`afterpack verify`](https://www.afterpack.dev/uk/docs/cli#afterpack-verify-dir) завершується помилкою, коли файл змінився після обфускації або коли квитанції немає:

```bash
parcel build index.html --reporter @afterpack/parcel-optimizer/reporter
npx afterpack@latest verify dist
```

## Параметри

Там можна задати кожен [ключ конфігурації](https://www.afterpack.dev/uk/docs/config), наприклад `{ "preset": "hard", "complexity": 40 }`. [`protectionMap.enabled`](https://www.afterpack.dev/uk/docs/config#protectionMap-enabled) залежить від того, чи має бандл source map, а не від [режиму збірки](https://www.afterpack.dev/uk/docs/config#build-mode), і звіт завжди потрапляє в `.afterpack/`, внесений у gitignore. Параметра `build.backup` у цього плагіна немає. Якщо його задати, буде попередження. Явні параметри завжди мають пріоритет над продакшн-значеннями за замовчуванням.

## Директиви

Директиви — це можливість тарифу [Pro](https://www.afterpack.dev/uk/docs/pro). У [збірці Free](https://www.afterpack.dev/uk/docs/directives#free-builds) директива, яка посилює захист, зупиняє збірку з помилкою `DIAG_PRO_DIRECTIVE_REQUIRES_KEY`.

Плагін зчитує директиви з вашого вихідного коду. Якщо придатного source map немає, проходу нічого відновлювати, і він про це повідомляє.

**Директива в модулі точки входу не відновлюється.** Прохід повідомляє `DIAG_DIRECTIVE_SOURCE_UNRESOLVED` і називає модуль. Директиви в усіх інших модулях, що не є точкою входу, працюють як звичайно, щойно source map увімкнено. Якщо вам потрібна директива в модулі точки входу, перенесіть захищений код в імпортований модуль.

## Особливі випадки

### Заповнювачі хешу вмісту можуть зламати збірку

Коли хешування вмісту увімкнене (за замовчуванням для `parcel build`) і ціль не підтримує нативний ESM, заповнювачі хешу вмісту Parcel опиняються всередині обфускованих рядків, і кожен чанк, отриманий розділенням коду, у продакшені віддає 404.

Цей плагін виявляє такий конфлікт і зупиняє збірку з помилкою, замість того щоб її випустити:

```
AfterPack obfuscated 1 Parcel content-hash placeholder(s) in app.[hash].js (HASH_REF_...).
  hint: Run `parcel build --no-content-hash` (chunk URLs stop being content-addressed).
  hint: Or set "complexity": 0 in afterpack.json to ship minify-only.
```

Стандартний ESM-результат Parcel це не зачіпає.

### Варто знати

- **Один прохід на бандл, у робочих процесах.** Parcel запускає оптимізатори для кожного бандла окремо, а бандли, запаковані в різних робочих процесах, не можуть мати спільного стану. Бандли, запаковані в одному процесі, мають спільний сід. Щоб закріпити один сід для всіх робочих процесів, задайте [`seed`](https://www.afterpack.dev/uk/docs/config#seed) явно або експортуйте `AFTERPACK_seed`.
- **Parcel кешує результат оптимізаторів.** Перезбірка з прогрітим `.parcel-cache` і незміненими вхідними даними не запускає AfterPack повторно і не змінює незакріплений сід. Очистьте `.parcel-cache` для нового проходу; збірки в CI і так починаються з холодного кешу.
- **Два нешкідливі попередження.** Parcel друкує `ES module dependencies are experimental` (кожен пакет AfterPack є ESM) і повідомляє, що плагін `contains non-statically analyzable dependencies` (це визначення нативного бінарного файлу рушія під час виконання). Жодне з них не впливає на збірку.

### Без плагіна: CLI

Зберіть проєкт Parcel як завжди, а потім вкажіть AfterPack на результат:

```bash
npx parcel build
```

```bash
npx afterpack@latest dist/ --preset=medium --seed=git
```

Без [аргументу шляху](https://www.afterpack.dev/uk/docs/cli#usage) CLI визначає `dist/`, типовий каталог виводу Parcel; якщо ваш відрізняється, вкажіть каталог явно. AfterPack обходить каталог, збирає кожен `.js`/`.mjs`/`.cjs` і обфускує їх [на місці](https://www.afterpack.dev/uk/docs/cli#what-a-run-does). Запуск через CLI не має захисту від конфлікту хешу вмісту і створює одну об'єднану [`protectionMap.html`](https://www.afterpack.dev/uk/docs/protection-map) для всього каталогу замість однієї на бандл. [Правило fail closed](https://www.afterpack.dev/uk/docs/diagnostics#fail-closed-no-exceptions) усе одно діє: відсутній каталог збірки, відсутність JS-файлів, [діагностика](https://www.afterpack.dev/uk/docs/diagnostics) рівня `error`/`critical` або файл, який рушій не зміг обфускувати, завершуються з ненульовим кодом.

## Далі

- [Фреймворки](https://www.afterpack.dev/uk/docs/frameworks): повна матриця.
- [esbuild](https://www.afterpack.dev/uk/docs/frameworks/esbuild#directives): ще один плагін, який відновлює директиви із source map після мініфікації.
- [Довідник CLI](https://www.afterpack.dev/uk/docs/cli): повний перелік прапорців для резервного шляху.
- [Збірки та CI](https://www.afterpack.dev/uk/docs/builds): сіди, dev проти prod, просування тих самих байтів.
- [Protection Map](https://www.afterpack.dev/uk/docs/protection-map): як читати звіт.
- [Конфігурація](https://www.afterpack.dev/uk/docs/config): кожен параметр і через який інтерфейс його можна задати.
- [Пресети](https://www.afterpack.dev/uk/docs/presets): драбина з п'яти щаблів.
