原文链接:www.callstack.com/blog/why-yo…
作者: Davyd Narbutovich
如果你来自网页开发背景,可能熟悉这样一个常识:"JavaScript越少越好",尤其在性能方面。为缩减JavaScript体积,网页开发者通常会使用名为"压缩工具"的专用工具,其中最受欢迎的是Terser。
这类工具会介入打包流程,将可读的JavaScript代码转换为由单字符、双字符甚至三字符组成的乱码混合体(如a、__p或b2),同时确保代码功能不受影响。
export function add(left, right) {
const result = left + right; return result;
}
add(2, 3);
JavaScript 源代码。大小:95 个字符。
export function add(d,n){return d+n}add(2,3);
压缩后的源代码。大小:45个字符。
结果如何?代码体积甚至能缩减10%-50%。同类工具通常会执行无用代码消除(DCE),寻找诸如"开发"环境分支这类"无用代码",但仅限于代码用于"生产环境"时。
然而React Native有所不同。你会发现即使在生产环境构建中,压缩功能也默认处于关闭状态。
原因何在?答案在于:Hermes。
Hermes 无用代码消除
Hermes 是一款专为移动端设计的 JavaScript 引擎,特别适用于 React Native 应用。自 2022 年起成为默认引擎后,它彻底改变了移动应用性能格局:启动速度提升高达 40%,内存消耗显著降低,而应用包仅增加约 2MB。
Hermes的独特之处在于:当配置得当时,它不会直接运行JavaScript代码,而是运行字节码(确切说是Hermes字节码),这正是性能提升的部分原因。这种机制带来令人振奋的启示——只要生成的字节码大小相当,JavaScript代码的实际体积就不再是关键因素。因此,React Native团队认为在打包管道中进行额外优化不值得,于是将其移除。
// https://github.com/facebook/react-native/blob/670a4d942f5eb5c6d406effcd84360958305056b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt#L84
// react-native/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt
task.minifyEnabled.set(!isHermesEnabledInThisVariant)
// https://github.com/facebook/react-native/blob/670a4d942f5eb5c6d406effcd84360958305056b/packages/react-native/scripts/react-native-xcode.sh#L140-L143
// react-native/packages/react-native/scripts/react-native-xcode.sh
if [[ $USE_HERMES != false && $DEV == false ]]; then
EXTRA_ARGS+=("--minify" "false")
fi
由于Hermes编译器原生执行所有必要的优化,因此跳过了源JavaScript的压缩步骤。在构建阶段,编译器生成最终字节码时会应用无用代码消除技术,这使得单独的压缩步骤变得多余,并显著加快了构建过程。
例如,您可以在这里看到使用Expensify应用作为实际测试案例的Metro包大小对比。
观察到的差异微乎其微:21.79 MB 与 21.62 MB。
验证无用代码消除
如何验证Hermes编译器是否真正消除了无用代码?您需要确保那些未使用的函数或分支不会偷偷溜进生产环境的打包文件中。
解决方案是使用反编译器将Hermes字节码(.jsbundle、.bundle文件)转换回可读的JavaScript(.js文件)。通过这种方式生成的输出可直接检查最终处理后的代码,从而确认Hermes编译器已成功完成无用代码消除。
快速指南:使用hermes-dec反编译hermes字节码
以下步骤将引导您安装并运行强大的hermes-dec工具,用于检查已编译的程序包。
步骤 1:安装 pipx(如有必要)
pipx 是一款用于在隔离环境中安装和运行 Python 应用程序的工具,非常适合 hermes-dec 实用程序。若尚未安装,请使用 Homebrew 安装:
brew install pipx
步骤 2:安装 hermes-dec 反编译器
使用 pipx 从其 Git 仓库直接安装反编译器:
pipx install git+https://github.com/P1sec/hermes-dec
步骤 3:对您的软件包运行反编译器
执行反编译器,将其指向您的主 Hermes 软件包(通常 iOS 设备以 .jsbundle 结尾,Android 设备以 .bundle 结尾),并指定输出文件。
~/.local/pipx/venvs/hermes-dec/bin/hbc-decompiler path/to/main.jsbundle result.js
一旦该过程完成,您就可以打开result.js文件,手动检查其中的JavaScript代码,确认那些预期被移除的代码确实已经消失!
此快速检查可为您节省数小时的调试时间,并为您提供Hermes无用代码消除能力的具体证明,确保您的React Native打包文件尽可能精简。
结论
某些优化措施往往容易被忽视。在 React Native 应用中,我们拥有多层工具各自执行着优化任务。我们认为理解整个优化流程至关重要,仅在必要时进行干预。毕竟 Web 端的 React 与 React Native 存在差异,而作为 JavaScript 引擎的 Hermes 正是其中最显著的差异点之一。尽情探索吧!