复杂度

每个预设背后的那一个旋钮:数值升高时什么随之增加、在 medium 处切换的那个阈值,以及哪些变换可以通过配置关闭却无法强制开启。

complexity 是决定引擎施加多少保护的唯一旋钮。预设就是它上面一个有名字的点:light 是 5,hard 是 12。light 会重命名标识符、重写语法并编码字符串,不添加结构层;从 medium 起,以及对于你直接设置的任何值,每一个词元都会被推向该目标。想要介于两者之间或超出范围的值,就直接设置 complexity——它是一个无上限的非负数。

数值升高时什么随之增加

复杂度是一份预算,而不是一张时间表。不存在“到这个数值就开启这个功能”的固定列表。高于 0 时,数值越大,引擎可用的预算就越多,并在每次构建中协商要应用哪些变换——因此相同复杂度下的两次构建形态各不相同,也没有任何单个变换能保证在某个级别出现。这种逐构建的差异正是目的所在:固定的结构为什么会成为指纹,参见 AfterPack 的工作原理。

有三点是固定的:

complexity保证的内容
0(minify)不做混淆。标识符会被重命名,代码会被压缩;下面的内容都不会运行。引擎 0.2.2 在 0 时还会重写语法。
> 0引擎能重写的每一个字符串字面量都会经过运行时解码器——即字符串下限。
≥ 7(medium 及以上)编码后的字符串和整数以一个共享的运行时值为密钥,对象字面量会被重建成各种不同的形态。

其余一切——控制流重塑、不透明谓词、整数表达式解释等等——都随预算增长从中支取,而不是在某条线上开启。inflation.max 不会改变其中哪些被应用:不设置时,完全由目标决定;设置了它,膨胀会超过该值的构建就会失败。

关闭或开启某个变换

你可以关闭任何一种变换,但无法强制开启某一种。

  • 关闭是可靠的。transforms.<kind>.enabled = false 在任何复杂度下都会移除该种变换。从引擎 0.2.3 起,在 7 及以上关闭 scopeDeepen 可能让文件的某一部分达不到目标,此时构建会以 DIAG_TARGET_NOT_REACHED 失败,并指出相应的行。
  • 开启只是许可。true 允许引擎使用某种变换;是否需要它,仍由引擎在每次构建时根据复杂度和预算决定。在你提高的区域之外,light 构建应用的变换种类只有字符串编码,在 Pro 上另加 comparisonHardening。objectConstruction 只在 7(medium)及以上出现,两种 Pro 变换需要 Pro 构建。
  • 在 0 时,这些都不适用。minify 不运行任何变换,因此所有 transforms 标志都没有意义。

想让某个变换更可能出现,应提高 complexity,而不是切换某个标志。

下一步

  • 预设:各个有名字的级别,以及每个级别设定的体积预算。
  • 配置:每一个键,包括 transforms.<kind>.enabled 标志。
  • AfterPack 的工作原理:为什么变换的组合每次构建都会变化。
  • 指令:为单个区域设置不同的复杂度(Pro)。