混淆 esbuild 构建

@afterpack/esbuild 挂接 build.onEnd,就地混淆已写出的输出。

@afterpack/esbuild 是一个标准的 esbuild 插件({ name, setup(build) })。它挂接 build.onEnd,该钩子在 esbuild 把输出写入磁盘后触发(write !== false,即默认值)。

它能处理两种输出形态:outdir(多个文件)和 outfile(单个文件)。已经出错的构建会被跳过。

安装

$ npm install -D @afterpack/esbuild
// build.mjs
import { build } from "esbuild";
import { afterpackEsbuild } from "@afterpack/esbuild";

await build({
  entryPoints: ["src/main.js"],
  bundle: true,
  format: "esm",
  outfile: "dist/app.js",
  plugins: [afterpackEsbuild()],
});

具名导出为 afterpackEsbuild。

构建

插件在 build.onEnd 上运行,此时 esbuild 已经把输出写入磁盘,outdir 和 outfile 都是如此。不存在需要它跳过的单独开发命令:每一次写出文件的 build() 调用都会运行插件。

esbuild 没有提供流程内的钩子,因此在这一遍处理完成之前,未混淆的 bundle 会留在磁盘上;对一个 185 KB 的 bundle,这一遍处理在默认预设下大约需要四分之一秒。在这段时间窗口内能读取输出目录的任何东西都能读到它。混淆失败时,这份输出会原样保留:构建失败,所以不会有任何东西被发布,但这些文件会一直留着,直到下一次构建覆盖它们。

验证

Protection Map 默认会在 esbuild 输出 source map 且构建不在 CI 中(CI=true 或 CI=1)时写出;生产模式不会关闭它。除非你设置 sourcemap,否则 esbuild 不会输出 source map,因此 Protection Map 默认关闭。请显式开启:

afterpackEsbuild({ protectionMap: { enabled: true } });

它会写入已被 gitignore 的 .afterpack/protectionMap.html。没有 sourcemap: true 时,插件会警告说找不到可用来渲染原始源码的打包工具 map。报告包含你的完整源码。绝不要提交或对外提供它。

选项

每个配置键都可以通过这里的选项对象传入,例如 afterpackEsbuild({ preset: "hard", complexity: 40 })。

指令

指令是从打包工具的 source map 中恢复出来的,因此如果使用指令,请以 sourcemap: true 构建。参见指令。

边界情况

  • **失败即中止。**某个文件失败或输出为空,都会让构建被拒绝。
  • **write: false。**磁盘上没有任何文件,因此插件什么也不做。AfterPack 需要已写出的文件。
  • **TypeScript。**AfterPack 运行时,esbuild 已经剥离了类型;map 会一路链回你的 .ts 行。

下一步

  • 框架:完整矩阵。
  • Vite:参考集成以及完整的选项语义。
  • 构建与 CI:种子、开发与生产环境的区别、原样提升同一份字节。
  • Protection Map:如何阅读报告。
  • 指令:每个标记键及其作用。
  • 配置:引擎的配置面。