@afterpack/webpack 是一个 webpack 5 插件:一个带有 apply(compiler) 方法的类。它会在压缩之前从你的源代码中读取 @afterpack 指令,然后在 webpack 写入之前的最后一个阶段,在 compilation.hooks.processAssets 上运行引擎。
每个资产的字节都会从编译结果中读出,混淆后的替代内容再交还给它,因此 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 这个类。
构建
该插件在 webpack 写入之前的最后一个阶段挂钩 compilation.hooks.processAssets。只有某个 chunk 声明的 .js、.mjs 和 .cjs 资产会被重写;.hot-update. chunk 会被跳过。编译器携带但并非自己构建出来的资产,比如另一个插件生成的清单文件或复制过来的文件,会被原样保留。
一个挂钩 afterProcessAssets 的完整性校验插件依然会在这条流水线之后运行,因此它计算出的哈希值是基于混淆后的字节的。
processAssets 在每次编译时都会运行,包括监听模式下的重新构建,每次重新构建都要付出引擎的开销。在开发循环中设置 build.autorun: false(或 AFTERPACK_build_autorun=false),生产构建则保持开启。
验证
Protection Map 默认会在 devtool 生成 source map 且构建不在 CI 中(CI=true 或 CI=1)时写出;生产构建模式不会关闭它。生产环境的 webpack 构建默认没有 devtool,因此 Protection Map 是关闭的。要显式请求它:
new AfterpackWebpackPlugin({ protectionMap: { enabled: true } });map 的默认值与打包工具是否存在 source map 相耦合,因此如果你想让它渲染出你的原始源码,就设置 devtool: "source-map"。如果没有,插件会警告说没有找到打包工具的 source map。该文件总是写入已被 gitignore 的 .afterpack/protectionMap.html,绝不会写进 dist/。它包含你的完整源码。绝不要提交它或对外提供服务。
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一起打包进你的 chunk,因此不存在按输出文件名区分它们的规律。AfterPack 会整体处理生成的文件;需要时,paths.exclude是按文件粒度排除的方式。 - 失败即中止,没有覆盖选项。 某个文件处理失败或结果为空会让构建失败,而不是发布未混淆的代码。