混淆一个 Nuxt 应用

@afterpack/nuxt 是一个 Nuxt 3 模块,在 Nuxt 的 Vite 配置上注册 @afterpack/vite。

Nuxt 3 用 Vite 打包,而 AfterPack 是在打包工具这一层做集成的,因此 @afterpack/nuxt 是一个很薄的 Nuxt 模块:它调用 addVitePlugin,在 Nuxt 的 Vite 配置上注册 @afterpack/vite,客户端打包产物会在 Vite 的 generateBundle 阶段、也就是构建写入之前被混淆。

Nuxt 2 项目用 webpack 构建。那里请改用 @afterpack/webpack。

安装

$ npm install -D @afterpack/nuxt
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@afterpack/nuxt"],
  afterpack: {
    seed: "git",
  },
});

选项位于 afterpack 配置键下。

构建

nuxt generate(静态)或 nuxt build(SSR)现在会生成混淆后的输出。nuxt dev 不受影响,因为插件只运行在 Vite 的 generateBundle 上。每个 Vite 环境(客户端和服务端)都会注册一个独立的 @afterpack/vite 插件实例,各自在 Vite 写入之前混淆自己的打包产物。

静态与服务端

  • 静态 / 预渲染(nuxt generate):.output/public/_nuxt/ 中预渲染的客户端打包产物会被混淆。这是发布受保护客户端代码的推荐形态。
  • 服务端(SSR):客户端打包产物按同样的方式被混淆;Nitro 服务端打包产物是你自己的部署产物。

当你希望一次发布的多条客户端分支由同一个种子构建出来,或者一次构建必须逐字节可复现(命中缓存、黄金快照)时,固定 seed: "git"。构建与 CI 讲了这个取舍。Nuxt 每次构建也会生成一个新的 buildId。

验证

export default defineNuxtConfig({
  modules: ["@afterpack/nuxt"],
  afterpack: { protectionMap: { enabled: true } },
});

把合并后的 Protection Map 写入已被 gitignore 的 .afterpack/protectionMap.html。source map 的副作用和处理规则与 @afterpack/vite 相同。

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.

要检查一次部署,请在上传前运行 npx afterpack@latest verify .output/public。Nitro 会把受保护的客户端构建复制到这里,verify 按构建的保护回执检查这份副本,并点名任何被改动的文件。

选项

每一个配置键都可以放在 afterpack 配置键下传入,并会逐字转发给 @afterpack/vite,例如 afterpack: { preset: "hard", complexity: 40 }。类型别名 AfterpackNuxtOptions 就是 AfterpackViteOptions。

指令

.vue 文件内部的 /* @afterpack … */ 标记不会被捕获。请把指令放在组件所导入的普通 .ts/.js 模块里(一个 composable、一个 utils/ 文件)。

下一步

  • 框架:完整对照表。
  • Vite:实际执行工作的插件。
  • Vue:一个普通的 Vue 3 + Vite 应用。
  • Protection Map:如何阅读这份报告。
  • 构建与 CI:种子、开发环境与生产环境的区别、提升同一份字节。