# Обфускація збірки Next.js

@afterpack/next обфускує клієнтський JavaScript усередині next build, на Turbopack чи webpack, з SSR чи статичним експортом.

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

`@afterpack/next` обфускує ваш клієнтський JavaScript зсередини `next build`. `withAfterpack` повертає конфігурацію з `compiler.runAfterProductionCompile`, власним хуком збірки Next, який Next викликає один раз для будь-якого з двох бандлерів.

Обгорнути конфігурацію — це вся інтеграція. Немає ні lifecycle-скрипта, ні окремої команди.

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

```bash
npm install -D @afterpack/next
```

```ts
// next.config.ts
import type { NextConfig } from "next";
import { withAfterpack } from "@afterpack/next";

const nextConfig: NextConfig = {
  // your existing config
};

export default withAfterpack(nextConfig);
```

Функціональна форма конфігурації Next працює так само. `withAfterpack(async (phase, ctx) => ({ … }))` повертає обгорнуту функцію.

## Збірка

`next build` тепер видає обфускований результат, хоч би який бандлер створив `.next/` (Turbopack чи webpack). `next dev` не зачіпається. Кожен виклик `next build` запускає хук, зокрема й завдання CI, яке викликає його напряму, і немає lifecycle-скрипта, який встановлення могло б пропустити. Якщо хук кидає виняток, збірка завершується з кодом виходу 1.

Хук обфускує лише JavaScript, який роздається клієнту: `.next/static/chunks`, а для статичного експорту ще й `out/`. `.next/server` ніколи не потрапляє в браузер і не обфускується. Хук перейменовує кожен чанк з хешем вмісту, щоб його ім'я [слідувало за обфускованими байтами](https://www.afterpack.dev/uk/docs/builds#file-names-and-caching), і переписує посилання на нього. Хук запускається після компіляції і до попереднього рендерингу та статичного експорту, тож статичний експорт копіює в `out/` уже обфусковані чанки.

Next записує чанки до запуску хука, тож ваші необфусковані чанки лежать на диску приблизно секунду під час збірки, і все, що може читати `.next/` у цей проміжок, може їх прочитати. Плагіни, що працюють усередині конвеєра ([Vite](https://www.afterpack.dev/uk/docs/frameworks/vite), [Rollup](https://www.afterpack.dev/uk/docs/frameworks/rollup), [webpack](https://www.afterpack.dev/uk/docs/frameworks/webpack), [Parcel](https://www.afterpack.dev/uk/docs/frameworks/parcel)), натомість повертають обфускований бандл бандлеру, тож нічого необфускованого ніколи не записується.

Хук `compiler.runAfterProductionCompile`, який ви вже задали, компонується, а не замінюється. Ваш запускається першим, AfterPack — другим, тож ваш бачить ті самі байти, що й без встановленого AfterPack.

Параметри, передані в `withAfterpack`, замикаються в хуку. Вони мають пріоритет над змінними середовища `AFTERPACK_*`, які, своєю чергою, мають пріоритет над `afterpack.json`. Використовуйте [`paths.exclude`](https://www.afterpack.dev/uk/docs/config#paths-exclude), щоб залишити файл без змін.

Коли мапу ввімкнено, об'єднана [`protectionMap.html`](https://www.afterpack.dev/uk/docs/protection-map) записується в `.afterpack/` у корені вашого проєкту, внесений у gitignore. За замовчуванням її вимкнено; див. розділ [Перевірка](#verify).

## Перевірка

Кожна захищена збірка записує квитанцію в `.afterpack/receipts/.next.json` у [корені вашого проєкту](https://www.afterpack.dev/uk/docs/cli#files), поза `.next/`: версію рушія, сід, бандлер, ідентифікатор збірки та sha256 для кожного обфускованого файлу. Перевіряйте її на кроці розгортання:

```bash
npx afterpack@latest verify .
```

Команда завершується з ненульовим кодом, коли квитанції немає, коли вона належить іншій збірці або коли хеш будь-якого записаного в ній файлу більше не збігається зі значенням, до якого його обфускували.

`out/` статичного експорту є копією цих чанків, тож `npx afterpack@latest verify out` перевіряє його за тією самою квитанцією і називає кожен змінений файл.

[Protection Map](https://www.afterpack.dev/uk/docs/protection-map) за замовчуванням записується лише тоді, коли бандлер видав source map і збірка не працює в CI (`CI=true` або `CI=1`). Next.js не видає source map для браузера, якщо не ввімкнено `productionBrowserSourceMaps`, тож мапа за замовчуванням вимкнена. Щоб побачити всі артефакти локально, явно ввімкніть її:

```ts
export default withAfterpack(nextConfig, { protectionMap: { enabled: true } });
```

Звіт потрапляє у `.afterpack/protectionMap.html`, внесений у gitignore. Він містить увесь ваш вихідний код. Ніколи не комітьте його і не роздавайте з сервера.

> **Ніколи не випускайте source map у продакшн**
>
> Файл `.map` містить ваш оригінальний вихідний код. Задавайте `productionBrowserSourceMaps: true` лише тоді, коли хочете, щоб Protection Map показувала оригінальний вихідний код. Хук прибирає map-файли з дерева, яке роздається, і в продакшні не додає коментар `//# sourceMappingURL`.

## Параметри

Будь-який [ключ конфігурації](https://www.afterpack.dev/uk/docs/config) можна передати другим аргументом у `withAfterpack`, наприклад `withAfterpack(nextConfig, { preset: "hard", complexity: 40 })`.

## Директиви

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

Директиви зчитуються плагіном із вашого вихідного коду, і щоб знайти їх у зібраних чанках, потрібен `productionBrowserSourceMaps: true`. Див. [Директиви](https://www.afterpack.dev/uk/docs/directives).

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

- **`experimental.sri` відхиляється.** Next обчислює хеш цілісності кожного ассета під час його запису, ще до того, як може запуститися будь-який хук збірки, тож браузер блокує чанк, переписаний після цього. Приберіть `experimental.sri` або приберіть `withAfterpack`.
- **Фіксований `generateBuildId` лишає змінені файли за тією самою URL-адресою.** Якщо ідентифікатор збірки не змінюється між релізами, `static/<buildId>/_buildManifest.js` і `_ssgManifest.js` зберігають свою URL-адресу, хоча їхні байти змінюються, і збірка попереджає про це. Не задавайте `generateBuildId`, щоб Next генерував випадковий ідентифікатор для кожної збірки, або повертайте новий ідентифікатор з кожним релізом.
- **Вказуйте на `.next/`, а не на `dist/`.** Якщо замість цього пакета ви використовуєте [універсальний CLI](https://www.afterpack.dev/uk/docs/cli#usage), еквівалентна ціль — `npx afterpack@latest .next/static/chunks`, але він не прибирає за вас map-файли, які роздаються.
- **[Зупинка з помилкою (fail closed)](https://www.afterpack.dev/uk/docs/diagnostics#fail-closed-no-exceptions) на необфускованих файлах, без можливості перевизначення.** Якщо рушій не може безпечно обфускувати файл, збірка завершується помилкою і називає цей файл. Якщо файл ніколи не має обфускуватися, повністю виключіть його з проходу через [`paths.exclude`](https://www.afterpack.dev/uk/docs/config#paths-exclude).

## Далі

- [Фреймворки](https://www.afterpack.dev/uk/docs/frameworks): повна матриця.
- [Швидкий старт](https://www.afterpack.dev/uk/docs/quickstart): встановлення, збірка і перевірка.
- [Збірки та 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/directives): кожен ключ маркера і що він робить.
- [Конфігурація](https://www.afterpack.dev/uk/docs/config): поверхня конфігурації рушія.
