@afterpack/vite 是参考集成。Astro、Svelte、SvelteKit、Vue 和 Nuxt 都封装了它,因此本页所述同样适用于这些包。
它先从你的源码中读取 @afterpack 指令,然后在 generateBundle 中运行引擎,此时完整的 bundle 还在内存中,Vite 尚未写出任何文件。
安装
$ npm install -D @afterpack/vite// vite.config.ts
import { defineConfig } from "vite";
import { afterpackVite } from "@afterpack/vite";
export default defineConfig({
plugins: [afterpackVite()],
});构建
配置到此为止。npm run build 现在会输出已混淆的结果;vite dev 不受影响,因为插件只在构建的 generateBundle 阶段起作用。Vite 写出的是已混淆的 chunk,原始文件从不落盘;混淆失败时,outDir 保持原样。
它混淆的是 Vite 构建出来的内容:输出 bundle 中的每一个 chunk。Vite 从 publicDir 原样复制到输出目录的文件没有经过构建,不在 bundle 中,也不会被处理。任何需要保护的内容都应经过打包工具。
插件会写出:
protectionMap.html:整个构建的一份合并地图,在 map 开启时写入项目根目录下已被 gitignore 的.afterpack/。它默认关闭,参见验证。它内嵌了你的原始源码。绝不要让它落入对外提供服务的目录。foo.js.map:启用 map 时写出的 source map。关闭 map 时(这是生产环境的默认值),Vite 自身的 map 条目会被丢弃,而不会写在已混淆的 chunk 旁边。
这里不会有 foo.backup.<hash>.js。已混淆的字节直接回写到 bundle 中,没有已写出的文件可供备份放在旁边,因此 build.backup: true 只会发出警告,而不会写出备份。
.afterpack/ 自带一个 .gitignore,因此插件从不修改你的 .gitignore。产物落入对外提供服务的路径时,它会发出警告。
验证
Protection Map 默认会在 Vite 输出 source map 且构建不在 CI 中(CI=true 或 CI=1)时写出;生产构建不会关闭它。除非设置了 build.sourcemap,否则 Vite 不会输出 source map,因此在常规构建中 Protection Map 默认关闭。想要查看时请显式开启:
afterpackVite({ protectionMap: { enabled: true } });在未设置 build.sourcemap 的情况下,这同时会开启 Vite 自身的 source map,以便地图能够渲染你的原始源码。找不到可用的 map 时,插件没有可据以渲染原始源码的来源,并会如实说明。
报告写入 .afterpack/protectionMap.html。它包含你的完整源码。绝不要提交或对外提供它,只在本地查看。
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.一个 .map 文件就能直达你的原始源码。绝不要部署它。
选项
每个配置键都可以通过这里的选项对象传入,例如 afterpackVite({ preset: "hard", complexity: 40 })。所有选项均为可选。具名导出为 afterpackVite。
preset 和 complexity 设置的是不同的东西。预设是一组打包好的设置:它同时设定复杂度目标、总输出体积倍数和膨胀预算。complexity 则是这组设置中的一个数字:
afterpackVite({ preset: "hard", complexity: 40 }); // hard's size limits, target 40指令
指令是 Pro 功能。在 Free 构建中,会提高保护强度的指令会让构建停止,并报错 DIAG_PRO_DIRECTIVE_REQUIRES_KEY。
插件会在任何压缩器剥离注释之前,从你的源码中读取指令。语法只接受块注释:
/* @afterpack preset=hard */
function verifyLicense(token) {
// ...
}
/* @afterpack end */// @afterpack … 这样的行注释不会被扫描,并会作为诊断信息报告出来。
指令可以设置的每个键都列在指令页面上。
捕获时会跳过 node_modules 以及非 JS/TS 文件。写在 .vue 或 .svelte 单文件组件内的指令不会被捕获。请改放到该组件导入的普通 .ts/.js 模块中。设置 directives.enabled: false 可完全跳过扫描。
边界情况
库模式
build.lib 的输出是一份公开契约。AfterPack 作用于最终的 bundle,因此导出名称会保留;内部实现仍会被重命名和重组。
多个输出
每次 Vite 构建只混淆自己的 bundle,不涉及其他内容,因此即使多次构建写入同一个目录,它们也是各自独立的处理。如果它们共享运行时契约,请为它们固定同一个 seed。
内容哈希文件名
每个 chunk 的文件名都跟随其混淆后的字节。一个以普通资源而不是 Vite 构建的 chunk 形式进入 bundle 的 JavaScript 文件,会保留 Vite 根据其未混淆字节给出的文件名,构建会发出警告:请把它作为模块导入,或在不使用长期缓存的情况下提供它。bundle 中预压缩的 .gz 和 .br 副本会根据混淆后的字节重新生成,其他格式的预压缩副本会让构建失败。
子资源完整性
计算子资源完整性哈希的 Vite 插件会被拒绝,因为它的 integrity 属性将与混淆后的文件不匹配。请移除它,并在构建之后根据部署的文件计算完整性。