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

@afterpack/webpack під'єднується до compilation.hooks.processAssets і обфускує ваші ассети, перш ніж webpack їх запише.

@afterpack/webpack — це плагін для webpack 5: клас з apply(compiler). Він зчитує директиви @afterpack з вашого вихідного коду до мініфікації, а потім запускає рушій на compilation.hooks.processAssets, на останньому етапі перед записом webpack.

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

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

$ npm install -D @afterpack/webpack
// webpack.config.js
import { AfterpackWebpackPlugin } from "@afterpack/webpack";

export default {
  mode: "production",
  output: { path: "dist" },
  plugins: [new AfterpackWebpackPlugin()],
};

Експорт — це клас AfterpackWebpackPlugin.

Збірка

Плагін під'єднується до compilation.hooks.processAssets на останньому етапі перед записом webpack. Переписуються лише ассети .js, .mjs і .cjs, які належать якомусь чанку компіляції; чанки .hot-update. пропускаються. Ассет, який компілятор містить, але не збирав, наприклад маніфест, згенерований іншим плагіном, або скопійований файл, лишається без змін.

Плагін цілісності, що під'єднується до afterProcessAssets, усе одно запускається після цього конвеєра, тож його хеші обчислюються вже з обфускованих байтів.

processAssets запускається на кожній компіляції, зокрема на перезбірках у watch-режимі, і кожна перезбірка платить ціну роботи рушія. Задайте build.autorun: false (або AFTERPACK_build_autorun=false) для циклу розробки і залиште його увімкненим для продакшн-збірок.

Перевірка

Protection Map за замовчуванням записується, коли devtool створює source map і збірка не працює в CI (CI=true або CI=1); продакшн-режим збірки її не вимикає. Продакшн-збірка webpack за замовчуванням не має devtool, тож мапа вимкнена. Запросіть її явно:

new AfterpackWebpackPlugin({ protectionMap: { enabled: true } });

Значення мапи за замовчуванням залежить від наявності source map бандлера, тож задайте devtool: "source-map", якщо хочете, щоб вона показувала ваш оригінальний вихідний код. Без нього плагін попередить, що не знайшов source map бандлера. Файл завжди записується у .afterpack/protectionMap.html, внесений у gitignore, і ніколи в dist/. Він містить увесь ваш вихідний код. Ніколи не комітьте його і не роздавайте з сервера.

entitlements.jslight · complexity 5Open full size
entitlements.js, 54 lines, built at the light preset with a directive around the signature check. Click any token to see what was applied to it.

Параметри

Будь-який ключ конфігурації можна передати тут в об'єкті параметрів, наприклад new AfterpackWebpackPlugin({ preset: "hard", complexity: 40 }). Назви точно повторюють @afterpack/vite і @afterpack/next, тож конфігурацію можна переносити між пакетами.

Директиви

Директиви зчитуються плагіном із вашого вихідного коду.

/* @afterpack preset=hard */
function verifyLicense(token) {
  // ...
}
/* @afterpack end */

Директиви бувають лише блоковими коментарями: рядковий коментар // @afterpack … не сканується і з'являється як діагностика. Повна граматика — на сторінці Директиви.

Збір директив пропускає node_modules і модулі, що не є JS/TS. Задайте directives.enabled: false, щоб повністю пропустити сканування; написані вручну regions працюють у будь-якому разі.

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

  • Сторонній код у бандлі. webpack об'єднує node_modules з вашими чанками, тож немає шаблону імен вихідних файлів, який би їх розділяв. AfterPack працює зі згенерованими файлами цілком; paths.exclude — це виключення на рівні файлів, коли воно вам потрібне.
  • Зупинка з помилкою (fail closed), без можливості перевизначення. Невдалий файл або порожній результат завершують збірку помилкою, а не випускають необфускований код.

Далі