加快构建阶段
构建 React Native 应用可能代价高昂,并且需要花费开发人员几分钟的时间。随着项目规模的扩大,以及在拥有多个 React Native 开发人员的大型组织中,这可能会成为一个问题。
为了减轻这种性能损失,本页分享了一些关于如何改进构建时间的建议。
开发期间仅构建一个 ABI(仅限 Android)
在本地构建 Android 应用时,默认情况下会构建所有 4 个应用程序二进制接口 (ABI):armeabi-v7a
、arm64-v8a
、x86
和 x86_64
。
但是,如果您正在本地构建并测试模拟器或物理设备,则可能不需要构建所有这些 ABI。
这应该可以将您的原生构建时间减少约 75%。
如果您使用的是 React Native CLI,则可以将--active-arch-only
标志添加到run-android
命令中。此标志将确保从正在运行的模拟器或已插入的手机中选择正确的 ABI。要确认此方法正常工作,您将在控制台上看到类似info Detected architectures arm64-v8a
的消息。
$ yarn react-native run-android --active-arch-only
[ ... ]
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 1037 file(s) to forward-jetify. Using 32 workers...
info JS server already running.
info Detected architectures arm64-v8a
info Installing the app...
此机制依赖于reactNativeArchitectures
Gradle 属性。
因此,如果您从命令行直接使用 Gradle 构建并且不使用 CLI,则可以指定要构建的 ABI,如下所示
$ ./gradlew :app:assembleDebug -PreactNativeArchitectures=x86,x86_64
如果您希望在 CI 上构建 Android 应用并使用矩阵并行化不同架构的构建,这将非常有用。
如果需要,您还可以使用项目顶级文件夹中的gradle.properties
文件在本地覆盖此值。
# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
构建应用的发布版本后,请务必删除这些标志,因为您希望构建适用于所有 ABI 的 apk/app bundle,而不仅仅是您在日常开发工作流程中使用的那个 ABI。
使用编译器缓存
如果您正在运行频繁的原生构建(C++ 或 Objective-C),则可能受益于使用编译器缓存。
具体来说,您可以使用两种类型的缓存:本地编译器缓存和分布式编译器缓存。
本地缓存
以下说明适用于Android 和 iOS。如果您只构建 Android 应用,则可以继续操作。如果您也构建 iOS 应用,请按照下面XCode 特定设置部分中的说明操作。
我们建议使用ccache来缓存原生构建的编译结果。Ccache 通过包装 C++ 编译器、存储编译结果并在存储了中间编译结果的情况下跳过编译来工作。
大多数操作系统的包管理器中都提供了 Ccache。在 macOS 上,我们可以使用brew install ccache
安装 ccache。或者,您可以按照官方安装说明从源代码安装。
然后,您可以执行两次干净构建(例如,在 Android 上,您可以先运行yarn react-native run-android
,删除android/app/build
文件夹,然后再次运行第一个命令)。您会注意到,第二次构建比第一次快得多(应该只需要几秒钟而不是几分钟)。构建过程中,您可以验证ccache
是否正常工作并检查缓存命中/未命中率ccache -s
$ ccache -s
Summary:
Hits: 196 / 3068 (6.39 %)
Direct: 0 / 3068 (0.00 %)
Preprocessed: 196 / 3068 (6.39 %)
Misses: 2872
Direct: 3068
Preprocessed: 2872
Uncacheable: 1
Primary storage:
Hits: 196 / 6136 (3.19 %)
Misses: 5940
Cache size (GB): 0.60 / 20.00 (3.00 %)
请注意,ccache
会汇总所有构建的统计信息。您可以在构建前使用ccache --zero-stats
重置它们,以验证缓存命中率。
如果需要清除缓存,可以使用ccache --clear
XCode 特定设置
要确保ccache
与 iOS 和 XCode 正常配合使用,您需要在ios/Podfile
中启用 React Native 对 ccache 的支持。
在编辑器中打开ios/Podfile
并取消注释ccache_enabled
行。
post_install do |installer|
# https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
react_native_post_install(
installer,
config[:reactNativePath],
:mac_catalyst_enabled => false,
# TODO: Uncomment the line below
:ccache_enabled => true
)
end
在 CI 上使用此方法
Ccache 使用 macOS 上的/Users/$USER/Library/Caches/ccache
文件夹来存储缓存。因此,您也可以在 CI 上保存和还原相应的文件夹以加快构建速度。
但是,需要注意以下几点
-
在 CI 上,我们建议执行完全干净构建,以避免出现缓存污染问题。如果您遵循上一段中提到的方法,则应该能够并行化 4 个不同 ABI 的原生构建,并且很可能不需要在 CI 上使用
ccache
。 -
ccache
依赖于时间戳来计算缓存命中。这在 CI 上效果不佳,因为文件在每次 CI 运行时都会重新下载。要解决此问题,您需要使用compiler_check content
选项,该选项改为依赖于文件的哈希值。
分布式缓存
与本地缓存类似,您可能需要考虑对原生构建使用分布式缓存。这在频繁执行原生构建的大型组织中可能特别有用。
我们建议使用sccache来实现此目的。有关如何设置和使用此工具的说明,请参阅 sccache 的分布式编译快速入门指南。