混淆一个 SvelteKit 应用

@afterpack/sveltekit:在 vite.config.ts 中 sveltekit() 之后加一行插件。

SvelteKit 用 Vite 构建,而 AfterPack 是在**打包工具**这一层做集成的,因此 @afterpack/sveltekit 是一个很薄的包装器:afterpackSveltekit(options) 就是 afterpackVite(options),只是为了在 Kit 项目里更容易被发现而单独命名。

安装

$ npm install -D @afterpack/sveltekit
// vite.config.ts
import { defineConfig } from "vite";
import { sveltekit } from "@sveltejs/kit/vite";
import { afterpackSveltekit } from "@afterpack/sveltekit";

export default defineConfig({
  plugins: [sveltekit(), afterpackSveltekit()],
});

把它放在 sveltekit() 之后。具名导出是 afterpackSveltekit;该包还重新导出了 afterpackVite 和 AfterpackViteOptions 类型。

构建

vite build 现在会生成混淆后的输出。vite dev 不受影响,因为插件只运行在构建的 generateBundle 上,也就是在 Vite 写入打包产物之前。

无论你的适配器生成了什么 JavaScript,都会被混淆。Kit 会为客户端和服务端各运行一次 Vite,插件会在每个打包产物生成时对其进行混淆,因此 adapter-static 预渲染的客户端打包产物,以及 Node 或无服务器的服务端打包产物,都会被覆盖到。使用 adapter-static 和 adapter-node 时,适配器会写入 build/;其他适配器会写到别处。

当客户端和服务端输出作为同一次发布一起出货,并且你希望两条腿由同一个种子构建出来时,固定一个 seed。seed: "git" 是保证这一点最简单的方式。构建与 CI 讲了什么时候值得固定种子,什么时候每次构建都用新种子反而更好。

验证

afterpackSveltekit({ 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.

选项

每一个配置键都可以作为选项对象在这里传入,并会逐字转发给 @afterpack/vite。类型别名 AfterpackSveltekitOptions 就是 AfterpackViteOptions。

afterpackSveltekit({ seed: "git", preset: "medium" });

指令

.svelte 文件内部的 /* @afterpack … */ 标记不会被捕获。请把指令放在路由所导入的普通 .ts/.js 模块里。src/lib/ 是自然的存放位置:

// src/lib/license.ts
/* @afterpack preset=hard */
export function verify(token: string) {
  // ...
}
/* @afterpack end */

无论如何,每一个生成的 chunk 都会被混淆;只有指令需要放在普通模块里。

下一步

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