Довідник AfterPack CLI

Виклик npx afterpack@latest: необов'язковий шлях, кожен ключ конфігурації як прапорець, підкоманди verify, restore та audit і повний контракт кодів виходу.

npx afterpack@latest обфускує каталог збірки. Використовуйте його, коли для вашого бандлера немає плагіна, або в CI. Якщо для вашого фреймворку плагін є, встановіть замість цього @afterpack/<fw>: тоді ваша звичайна збірка одразу видає обфускований результат без окремого кроку. Див. Фреймворки.

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

Використання

afterpack [path] [--<key>=<value> ...] [-h | --help] [-v | --version]
afterpack verify [dir]
afterpack restore [dir]
afterpack audit <url>
$ npx afterpack@latest

Шлях може бути одним із двох:

  • каталогом, який обходиться рекурсивно в пошуках кожного файлу .js, .mjs і .cjs, або
  • одним файлом .js, .mjs чи .cjs, який обфускується сам по собі.

Запустіть без шляху, і afterpack сам визначить результат вашої збірки: каталог, у який за домовленістю пише бандлер, названий у вашому package.json (Next.js → .next/, Nuxt → .output/, SvelteKit → build/, Electron → out/, будь-який інший підтримуваний бандлер → dist/), якщо цей каталог існує, інакше найновіший з dist/, build/, out/, .output/ і .next/. Він ніколи не читає власний файл конфігурації вашого бандлера, тому нестандартний каталог виводу не визначається: якщо він у вас є, передайте шлях самі. Команда друкує, що знайшла і що збирається зробити, а потім виконується; у CI вона ніколи не ставить запитань. Якщо нічого не знайдено, вона друкує довідку швидкого старту і завершується з кодом 1. Команда також читає ваш бандлер із package.json і наприкінці запуску друкує однорядкову підказку про відповідний плагін.

Вказуйте на результат роботи бандлера, а не на вихідний код. Більшість бандлерів (Vite, Rollup, esbuild, webpack, Astro, Parcel) пишуть у dist/. Next.js пише в .next/, Nuxt у .output/.

Приклади

npx afterpack@latest                                        # detects the build output, light default
npx afterpack@latest dist/                                  # a directory you choose
npx afterpack@latest dist/ --preset=hard                    # heavier posture
npx afterpack@latest .next/ --seed=git                      # reproducible output, pinned to the commit
npx afterpack@latest build/widget.js                        # one file
npx afterpack@latest dist/ --diagnostics.level=all          # every diagnostic, not the rolled-up summary
AFTERPACK_complexity=40 npx afterpack@latest dist/           # any flag also works as an env var

Що робить запуск

  1. Збирає JavaScript за шляхом <path>. Якщо шлях є каталогом, обходить його рекурсивно, пропускає власні копії .backup.<hash> і пропускає node_modules/, якщо ви не включили його через --paths.include='**/node_modules/**'. Якщо нічого не зібрано, збірка завершується помилкою.
  2. Не допускає .afterpack/ у git за допомогою .gitignore усередині нього; цей файл записується, щойно він уперше знадобиться. Ваш власний .gitignore ніколи не редагується.
  3. Обфускує кожен зібраний файл на місці, на запитаному пресеті або на --complexity, якщо ви задали його явно. На збірці Next.js, Angular, Vite або webpack він також перейменовує кожен файл із хешем вмісту відповідно до його обфускованих байтів і переписує кожне посилання на нього; на будь-якому іншому результаті імена лишаються такими, як їх записав ваш бандлер. Див. Імена файлів із хешем вмісту.
  4. Записує артефакти, які дозволяють прапорці, і завжди квитанцію захисту. Об'єднана Protection Map завжди потрапляє в .afterpack/protectionMap.html, внесений у gitignore і ніколи не роздається сервером, бо містить ваш оригінальний вихідний код. Source map або резервна копія містить увесь ваш вихідний код. Ніколи не розгортайте ні те, ні інше. Якщо щось із цього потрапляє під сегмент шляху, який роздається сервером, CLI попереджає один раз.
  5. Друкує діагностику, а потім підказку про бандлер, якщо знайшла його.
Запуски не ідемпотентні

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

Не запускайте двічі на тому самому результаті

AfterPack відмовляється обфускувати файл, який уже містить його власний обфускований результат попереднього запуску: він зіставляє зібрані файли з квитанцією захисту за хешем вмісту і завершує збірку помилкою DIAG_ALREADY_OBFUSCATED, хоч з якого каталогу ви його запускаєте, замість того щоб обфускувати вже обфускований код. Копію захищеного результату, яку зробив фреймворк, наприклад build/ у SvelteKit, теж буде відхилено. Спочатку перезберіть із вихідного коду: видаліть каталог виводу або виконайте крок очищення вашого бандлера.

Імена файлів із хешем вмісту

Бандлери називають чанк за хешем його вмісту, наприклад index-4f9a2c1e.js, щоб сервер міг кешувати його на рік із Cache-Control: immutable. Обфускація змінює байти, тож на збірках нижче запуск дає кожному файлу з хешем вмісту новий хеш в імені й переписує кожне посилання на нього в HTML, маніфестах та інших чанках. Ім'я ніколи не вказує на інші байти, тож браузер, CDN чи сервіс-воркер ніколи не віддасть застарілу копію під повторно використаним ім'ям. Новий хеш виводиться з початкового разом із сідом, версією рушія та вашими налаштуваннями, так само як плагін називає свої файли; що сід означає для вашого кешу, описано в Імена файлів і кешування.

ЗбіркаНа що спрямувати CLIЩо перейменовує запуск
Next.js, на webpack або Turbopack.next/, .next/static/ або .next/static/chunks/; out/ для статичного експортуЧанки в static/chunks/
Application builder Angulardist/<app>/browser/ або dist/<app>/Кожен файл із хешем. Запуск також перераховує атрибути integrity і таблицю хешів ngsw.json сервіс-воркера
ViteКаталог з index.html або .vite/manifest.jsonСкрипти й таблиці стилів name-<hash> в assets/ або в теках, які називає маніфест
webpackКаталог, чанки якого завантажує рантайм webpackФайли з шістнадцятковим хешем вмісту в імені

Імена з хешем вмісту лишаються такими, як їх записав ваш бандлер, і запуск друкує одне повідомлення, коли:

  • шлях — це один файл або результат іншого бандлера;
  • бандлер збірки Next.js не вдається визначити;
  • на збірці Vite або webpack на файл із хешем немає посилання зсередини каталогу збірки, два хеші неможливо розрізнити, або тека поруч із каталогом збірки, як-от серверний бандл, .svelte-kit/ чи .output/, називає файли з хешем чи завелика для перевірки;
  • маніфест попереднього кешування, як-от у Workbox, перелічує файли за ревізією.

Для довготривалого кешування на такій збірці використовуйте плагін вашого фреймворку або зафіксуйте сталий --seed.

Серверну збірку Angular, чий angular-app-manifest.mjs містить хеші ресурсів, відхилено з кодом 1, а результат лишається таким, як його записав збирач. Обфускуйте браузерний результат збірки без SSR.

Прапорці

Кожен ключ конфігурації є прапорцем: --<key>=<value>, наприклад --complexity=40 або --identifiers.reserved=Hls,Foo для списку. Булевий прапорець без значення означає true (--build.backup), а =false вимикає його (--protectionMap.enabled=false). -h, --help і -v, --version друкують відповідний текст і завершуються з кодом 0.

Кожен скалярний ключ або ключ-список із довідника параметрів працює як прапорець саме так. Структуровані значення належать у afterpack.json. Змінні середовища мають ті самі назви з крапками, заміненими на підкреслення, див. Конфігурація, наприклад AFTERPACK_key, AFTERPACK_preset і AFTERPACK_telemetry_enabled.

Файли

ШляхРоль
afterpack.jsonФайл конфігурації. AfterPack піднімається від робочого каталогу вгору до найближчого збігу. Він містить усю конфігурацію рушія: параметри збірки, key, усе.
.afterpack/receipts/<build dir>.jsonКвитанція захисту для одного каталогу збірки, наприклад .afterpack/receipts/dist.json або .afterpack/receipts/.next.json. Довгий або незвичний шлях отримує скорочену назву з хешем. Вона містить кожен вихідний файл із хешем записаних байтів, версію рушія та сід. afterpack verify повторно хешує файли і звіряє з нею, і через неї наступний запуск на тому самому неперезібраному результаті буде відхилено.
.afterpack/protectionMap.htmlОб'єднана Protection Map. Автоматично вноситься в gitignore. Містить ваш оригінальний вихідний код. Ніколи не комітьте і не роздавайте її сервером.
.afterpack/backups/<build dir>/Ваші оригінали для одного каталогу збірки, без змін, наприклад .afterpack/backups/dist/, з маніфестом кожного файлу, який запуск створив, змінив, перейменував чи видалив. Кожен каталог збірки має власну резервну копію і власне блокування, тож збірки різних застосунків в одному репозиторії ніколи не ділять одну копію. Записується під час кожного запуску (--build.backup=false вимикає), і afterpack restore читає її, щоб скасувати запуск. Запуск друкує її шлях, коли завершується. Це ваш вихідний код. Ніколи не комітьте і не розгортайте її.
<file>.js.mapЗгенерований source map, коли увімкнено sourceMap.enabled. За замовчуванням вимкнено: запуск є продакшн-запуском, якщо він не позначений як запуск для розробки, а продакшн-запуск також видаляє source map, які записав ваш бандлер, зокрема CSS-карти. Опублікований source map відображає результат прямо назад у ваш вихідний код.

.afterpack/ містить квитанції, Protection Map і резервні копії. AfterPack знаходить його від каталогу збірки, хоч з якого каталогу ви запускаєте. Він піднімається вгору до найближчої папки, де є lock-файл (package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, bun.lock або bun.lockb), afterpack.json або .git. Якщо такої немає, він бере найближчу папку з package.json, а якщо немає й такої, кладе його поруч із каталогом збірки. Саме ця папка на цих сторінках є коренем вашого проєкту. .afterpack/ ніколи не лежить усередині результату збірки.

Запуск завершується помилкою, нічого не перезаписавши, коли знаходить папку .afterpack/ усередині результату збірки (DIAG_AFTERPACK_DIR_IN_OUTPUT: видаліть цю папку і зберіть знову) або не може записати квитанцію (DIAG_RECEIPT_UNWRITABLE). Файл .afterpack-protection.json, який залишила в результаті старіша версія, видаляється під час наступного запуску.

afterpack verify [dir]

Ворота перед розгортанням. Кожна захищена збірка записує квитанцію захисту в .afterpack/receipts/. verify знаходить квитанцію для [dir] так само, як і запуск, тож працює з будь-якого каталогу. Вона повторно хешує кожен файл, названий у квитанції, і завершується помилкою, коли якийсь із них більше не збігається, коли квитанції немає або коли вона з іншої збірки.

npx afterpack@latest verify .        # a project root: looks in ./ then ./.next/
npx afterpack@latest verify dist     # or the build output directory itself
npx afterpack@latest verify build    # SvelteKit's adapter copy; also .output/public, out/

Каталог, який фреймворк скопіював зі свого результату збірки, наприклад build/ у SvelteKit, .output/public/ у Nuxt або out/ у Next, перевіряється за квитанцією каталогу, з якого його скопійовано. verify зіставляє копію з цією квитанцією за її файлами і перевіряє кожен хеш, тож змінений файл спричиняє помилку і називається. Вказуйте саме корінь розгортання. Текстовий вивід тоді додає · copy of <source dir>/.

Вона не читає конфігурацію рушія, лише --diagnostics.format і --diagnostics.level. З --diagnostics.format=json поле receipt у підсумку називає квитанцію, яку вона перевірила, а copiedFrom називає каталог, з якого зроблено копію. Запускайте її останнім кроком перед розгортанням; див. Збірки та CI.

Вона також завершується помилкою, коли зупинений запуск чи відновлення лишили в каталозі збірки тимчасовий файл .afterpack-tmp. Див. Запуск, що зупинився на півдорозі.

afterpack restore [dir]

Скасування. Перш ніж щось записати, запуск копіює ваші оригінали в .afterpack/backups/<build dir>/ і записує кожен файл, який він створить, змінить, перейменує чи видалить. restore повертає кожен файл під його початковим ім'ям і з початковими байтами, скасовує перейменування та переписані посилання і видаляє резервну копію та квитанцію, яку записав запуск.

npx afterpack@latest restore          # every backup under the project root
npx afterpack@latest restore dist     # only the run over dist/

Спрямована на каталог збірки, вона відновлює лише запуски над цим каталогом, над каталогом усередині нього або над збіркою, що його містить. Спрямована на корінь проєкту, вона відновлює всі резервні копії, що там є. Коли жодна резервна копія не покриває шлях, вона завершується помилкою і перелічує каталоги, які мають копію. Вона знаходить .afterpack/ від [dir] так само, як запуск, і також читає теку .afterpack/backup/, яку записав попередній випуск.

Вона зупиняється з помилкою (fail closed): кожен записаний файл перевіряється, перш ніж щось буде записано, тому файл, який ви редагували чи перезібрали після запуску, зупиняє відновлення, нічого не відновлюється, а команда називає файл і завершується з кодом 1. Без резервної копії вона відмовляється працювати одразу. Відновлення, що зупинилося на півдорозі, завершує наступний restore. Не читає конфігурацію рушія, окрім --diagnostics.format.

Запуск, що зупинився на півдорозі

Запуск, що завершується помилкою, відкочує власні записи перед виходом. Кожен файл спершу записується в тимчасовий <file>.afterpack-tmp, а тоді перейменовується на місце, тож перерваний запуск ніколи не лишає наполовину записаного файлу. Резервна копія перерваного запуску лишається позначеною як незавершена, і наступний запуск afterpack над тим самим каталогом спершу перевіряє результат:

Що містить результат збіркиНаступний запуск
Лише те, що записав ваш бандлер, і те, що записав зупинений запускЗавершується з кодом 1. Виконайте afterpack restore, щоб повернути результат до стану, який записав ваш бандлер, або перезберіть із вихідного коду й запустіть знову.
Нову збірку або точно те, що записав ваш бандлер, без жодного сліду зупиненого запускуВідкидає застарілу резервну копію з повідомленням і виконується.
Суміш: частину файлів перезібрано, інші досі містять результат зупиненого запускуЗавершується з кодом 1 і називає перезібрані файли, а restore теж відмовляється. Перезберіть увесь результат із вихідного коду й запустіть знову або скопіюйте оригінали інших файлів із теки резервної копії, яку називає повідомлення.

З --build.backup=false резервна копія не записується, тож перерваний запуск неможливо скасувати: перезберіть із вихідного коду. AfterPack не скидає свої записи на диск примусово, тож після втрати живлення під час запуску чи відновлення так само перезберіть із вихідного коду.

Паралельні запуски та блокування

Запуск і відновлення тримають блокування свого каталогу збірки, .afterpack/backups/<build dir>/lock, доки не завершаться. Запуски над різними каталогами збірки, як-от двома застосунками в одному репозиторії, ідуть паралельно. Другий запуск над тією самою збіркою, зокрема над каталогом усередині неї, як-от .next/static/chunks/, поки захищається .next/, завершується з кодом 1 і називає запуск, що тримає блокування. Блокування, процес якого на цій машині вже завершився або яке старше за дві години, перебирається з повідомленням. Якщо жоден запуск не триває, а блокування лишається, видаліть файл, який називає повідомлення.

afterpack audit <url>

Сканує розгорнутий сайт на витоки секретів, відкритий вихідний код і незахищений JavaScript, передаючи знахідки потоком у процесі сканування. Команда не читає конфігурацію і не надсилає нічого, крім URL. Повний довідник команди див. на сторінці Аудит.

npx afterpack@latest audit example.com

Машиночитний вивід

--diagnostics.format=json виводить у stdout рівно один JSON-документ і більше нічого; кожен рядок для людини переходить у stderr. Працює через прапорець, через AFTERPACK_diagnostics_format=json або через diagnostics.format у afterpack.json, і verify та audit також його враховують. Поєднайте його з diagnostics.level=none, щоб запуск не друкував нічого, крім документа. Саме цю форму мають читати кроки CI та AI-агенти замість розбору текстового виводу; пакет також містить SKILL.md, який описує CLI для агента, що викликає його напряму.

npx afterpack@latest dist/ --diagnostics.format=json --diagnostics.level=none

Коди виходу

КодЗначення
0Успіх. Кожен зібраний файл обфусковано і записано. Також повертається для --help і --version.
1Помилка. Нічого придатного не створено: шлях не існує, під ним не знайдено JavaScript, будь-яка помилка рушія, невдалий verify, невдале сканування audit або збірка з ключем Pro, чий хмарний виклик не вдався.
2Частково. Зарезервовано для збірки з вичерпаною квотою; сьогодні жодна збірка його не повертає.
3Обмеження розміру. inflation.max не дозволив досягти цільової складності (DIAG_SIZE_CAP_REACHED).
4Потрібен Pro. Запис regions підвищує захист понад конфігурацію всієї програми й потребує key (DIAG_PRO_DIRECTIVE_REQUIRES_KEY). CLI не читає директив із вихідного коду, тож до цього виходу веде лише regions.
5Рефлексія. Виявлено патерн рефлексії під час виконання без reflection.allow (DIAG_REFLECTION_NOT_ACKNOWLEDGED).
6Потрібне оновлення. Хмарі AfterPack або цьому afterpack потрібен новіший @afterpack/core. Нічого не записано.
64Неправильне використання. Невідомий прапорець або команда, некоректне значення або продубльований аргумент шляху.

Використовуйте paths.exclude, щоб виділити файл, який має вийти незмінним.

Збірка Pro з розпізнаним key зупиняється з помилкою (fail closed). Якщо хмарний виклик не вдався, збірка зупиняється замість того, щоб повертатися до результату рівня Free. Код 4 — вихід Free-збірки із записом regions, що потребує ключа; код 5 — вихід для непідтвердженого патерну рефлексії на будь-якій збірці, Free чи Pro; код 2 зарезервовано для майбутньої збірки з вичерпаною квотою, і сьогодні жодна збірка його не повертає. Повний контракт див. у розділі Коди виходу.

Далі

  • Конфігурація: кожен параметр і чотири форми, якими його можна задати.
  • Пресети: драбина з п'яти щаблів і ціна кожного щабля.
  • Аудит: повний довідник afterpack audit.
  • Діагностика: контракт кодів виходу, правило зупинки з помилкою (fail closed) і кожен код DIAG_*.
  • Фреймворки: шлях через плагін, кращий, коли плагін для вашого стека існує.
  • Швидкий старт: найкоротший шлях від встановлення до Protection Map.