Visual Studio Code 最近将其内置的 JavaScript 大小减少了 20%,节省了超过 3.9 MB。这种减少不仅降低了下载和存储需求,而且由于在运行 JavaScript 之前需要扫描的源代码更少,因此也提高了启动速度。这个减小是通过一个新的构建步骤 “名称混淆压缩” 实现的,而非删除任何代码或进行重大重构。
workbench.js 随时间变化大小,右侧两个下降点:VS Code 1.74 第一大跌幅结果来源于混淆压缩私有属性,VS Code 1.80 第二小跌幅来源于混淆压缩 export。
混淆压缩私有属性
混淆压缩源码后 JavaScript 仍包含许多长标识符名称如 extensionIgnoredRecommendationsService。作者本来以为 esbuild 已经将这些标识符简化了,比如:
const someLongVariableName = 123;
console.log(someLongVariableName);
变为更短的:
const x = 123;
console.log(x);
由于 JavaScript 以源文本形式发布,减少标识符名称的长度实际上可以减小程序的大小。这种优化可能看起来有些荒谬,但在 JavaScript 世界里确实顶瓜瓜。
尽管 esbuild 实现了混淆功能,默认情况下只有当确定混淆不会改变代码行为时才对名称进行处理。
因此,在实践中,esbuild 只对局部变量名和参数名进行处理。
也就是说,esbuild 这种保守策略意味着许多无法确认是否安全修改名称被忽略了。
怎么办呢?
作者团队最终利用 TypeScript 对混淆代码进行验证,正如 TypeScript 可以在常规代码中捕获未知的属性访问一样,TypeScript 编译器能够捕获到一个属性已经被混淆但对它的引用没有正确更新的情况。
解决思路:可以将 TypeScript 源码进行混淆,然后使用被改变标识符名称的新 TypeScript 进行编译。这种方式会使得对于是否无意间破坏了代码有更高的把握。
同时,通过使用 TypeScript,可以真正找到所有私有属性(而不是仅以 _ 开始的属性),甚至还可以利用 TypeScript 的现有重命名功能来智能地重命名符号,而不会意外改变对象形状。
他们提出了新的大致工作流程: 使用 TypeScript's AST 针对每个在代码库中发现的私有或受保护属性:
如果该属性需要被修改:
通过寻找未使用过的符号名称计算出一个新名称
使用 TypeScript 生成所有引用该属性的重命名编辑 将所有重命名编辑应用于 TypeScript 源码 编译带有修改过名称的新编辑过的 Typescript 资源 结果大部分有效。
当然,也有一些例外需要处理:
当前类内唯一性并不能满足要求,在超类和子类之间也必须具备唯一性。根本原因是 TypeScripts 私有关键字只是一个编译时装饰器,并不能真正防止超级和子类访问私有属性。
如果不小心处理,则可能导致重新命名时产生名称冲突(幸运地是 Typescript 将其报告为错误)。
在某些情况下,子类公开继承自父类受保护权限,在很多例子里面都属于错误操作,需要禁止此处进行混淆。
这样构建成功后,混淆私有属性后 VS Code 主要 workbench.js 文件大小从 12.3MB 降低至 10.6MB , 减少近 14%。这也带来 5% 加载速度提高,因为需要扫描文本量减少。
混淆压缩 export
另一方面,其实 provideWorkspaceTrustExtensionProposals 等长名字,或者 localize 函数(用于 UI 显示字符串)明显还有改善空间。
针对它的处理是:导出符号名称。只要导出仅供内部使用,就可以缩短它们而不改变代码行为。
最终,经过优化,总体上文件比没有进行名称压缩小了 20%。
在整个 VS Code 中,名称压缩从编译源码移除 3.9MB JavaScript 代码,这既降低了下载大小和安装大小,也使每次启动 VS Code 需要扫描 JS 代码量减少 3.9MB。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !