混淆一个 Remix 应用

没有 @afterpack/remix 这个包。Remix 通过 Vite 构建,因此使用 @afterpack/vite,或者对构建输出运行 CLI。

没有 Remix 专用包

AfterPack 不发布 @afterpack/remix。Remix v2 和 React Router v7 都通过 Vite 构建,因此 Vite 插件是自然的接入方式,而无论如何 CLI 都能对输出直接生效。框架有完整对照表。

安装

Remix 自己的插件运行在你的 vite.config.ts 里,因此把 @afterpack/vite 放进同一个 plugins 数组,排在它后面:

$ npm install -D @afterpack/vite
// vite.config.ts
import { defineConfig } from "vite";
import { vitePlugin as remix } from "@remix-run/dev";
import { afterpackVite } from "@afterpack/vite";

export default defineConfig({
  plugins: [remix(), afterpackVite()],
});

或者跳过这个包,直接对构建输出运行 CLI。

构建

该插件运行在 generateBundle 上,在 Vite 写入之前混淆打包产物中的每一个 JavaScript chunk。Remix 会把客户端和服务端两条腿分别构建为独立的 Vite 构建,因此插件每条腿各运行一次,只作用于那条腿自己的打包产物。如果这两条腿一起发布,并且你希望它们由同一个种子构建出来,就固定一个 seed(最简单的做法是 seed: "git")。构建与 CI 讲了这个取舍。

用 CLI 构建的方式是一样的:先构建,然后把 AfterPack 分别指向每一个输出目录。一次典型的 Remix Vite 构建会写出 build/client 和 build/server:

$ npx afterpack@latest build/client --seed=git

请把目录作为路径参数传入:不指定时,CLI 会选取 dist/、build/、out/、.output/ 和 .next/ 中最新的一个,而当客户端构建和服务端构建分开混淆时,这并不是你想要的。它接受一个要遍历的目录,或一个单独的 .js/.mjs/.cjs 文件。对每一个你想混淆的目录各运行一次,如果它们一起发布,两次运行使用同一个 --seed。两条路径调用的是同一套共享流程,因此其余一切(预设阶梯、失败即中止行为、产出文件)都是一致的。

验证

Protection Map 默认会在 Vite 输出 source map 且构建不在 CI 中(CI=true 或 CI=1)时写出;构建模式不会关闭它。除非设置了 build.sourcemap,否则 Vite 不会输出 source map,因此请为你想查看的这次构建开启 source map 后再构建,然后打开已被 gitignore 的 .afterpack/protectionMap.html。它包含你的完整源码。绝不要提交它或对外提供服务。

选项

每一个配置键在这个插件里的工作方式,与 Vite 页面上完全相同,包括指令捕获;每个键见配置。

指令

插件会从你的源代码中读取指令。CLI 会在输入携带 source map 时读取它们。参见指令。

边界情况

  • 失败即中止,没有覆盖选项。 一条 error/critical 诊断信息、一个空结果,或者引擎无法混淆的某个文件,都会让构建失败。
  • 服务端输出也只是 JavaScript。 AfterPack 会混淆它在你指向的目录中找到的任何 .js 文件。

下一步

  • 框架:完整对照表。
  • Vite:本页推荐使用的插件。
  • CLI 参考:完整的标志列表。
  • 配置:每一个选项,以及哪个入口能设置它。
  • 预设:preset 所对应的阶梯。
  • 构建与 CI:种子、开发环境与生产环境的区别、提升同一份字节。
  • Protection Map:如何阅读这份报告。