メインコンテンツへスキップ

ビルドフェーズの高速化

React Nativeアプリのビルドはコストがかかり、開発者の時間を数分消費することがあります。これはプロジェクトが成長するにつれて、また複数のReact Native開発者がいる大規模な組織では一般的に問題となる可能性があります。

このパフォーマンス上の問題を軽減するため、このページではビルド時間を改善するためのいくつかの提案を共有します。

情報

これらの提案は、ネイティブビルドツールの仕組みをある程度理解する必要がある高度な機能であることにご注意ください。

開発中に1つのABIのみをビルドする(Androidのみ)

Androidアプリをローカルでビルドする場合、デフォルトでは4つのApplication Binary Interfaces (ABIs)、すなわちarmeabi-v7aarm64-v8ax86x86_64をすべてビルドします。

しかし、ローカルでビルドしてエミュレーターや物理デバイスでテストしている場合、これらすべてをビルドする必要はないでしょう。

これにより、ネイティブビルド時間が約75%削減されるはずです。

React Native CLIを使用している場合、run-androidコマンドに--active-arch-onlyフラグを追加できます。このフラグは、実行中のエミュレーターまたは接続されている電話から正しい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プロパティに依存しています。

したがって、コマンドラインからCLIなしでGradleで直接ビルドする場合、ビルドしたい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だけでなく、すべてのABIで機能するapk/app bundleをビルドしたいからです。

設定キャッシュを有効にする(Androidのみ)

React Native 0.79以降、Gradle設定キャッシュを有効にすることもできます。

yarn androidでAndroidビルドを実行すると、2つのステップから構成されるGradleビルドが実行されます(ソース)。

  • 設定フェーズ:すべての.gradleファイルが評価されます。
  • 実行フェーズ:タスクが実際に実行され、Java/Kotlinコードなどがコンパイルされます。

設定キャッシュを有効にすることで、後続のビルドで設定フェーズをスキップできるようになります。

これは、ビルド時間を短縮するため、ネイティブコードに頻繁な変更を加える場合に有益です。

たとえば、ネイティブコードの変更後にRN-Testerを再ビルドするのがどれだけ速くなるかをここで確認できます。

gradle config caching

Gradle設定キャッシュを有効にするには、android/gradle.propertiesファイルに次の行を追加します。

org.gradle.configuration-cache=true

設定キャッシュに関するより詳細な情報については、公式のGradleドキュメントを参照してください。

Mavenミラーの使用(Androidのみ)

Androidアプリをビルドする場合、GradleビルドはMaven Centralやその他のリポジトリから必要な依存関係をインターネットからダウンロードする必要があります。

組織がMavenリポジトリミラーを運用している場合、ミラーからアーティファクトをダウンロードすることで、インターネットからダウンロードするよりもビルドを高速化できるため、それを使用することを検討すべきです。

android/gradle.propertiesファイルにexclusiveEnterpriseRepositoryプロパティを指定することで、ミラーを構成できます。

diff
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true

# Use this property to configure a Maven enterprise repository
# that will be used exclusively to fetch all of your dependencies.
+exclusiveEnterpriseRepository=https://my.internal.proxy.net/

このプロパティを設定すると、ビルドは排他的に指定されたリポジトリから依存関係を取得し、他のリポジトリからは取得しません。

コンパイラキャッシュを使用する

頻繁にネイティブビルド(C++またはObjective-C)を実行している場合、コンパイラキャッシュを使用することでメリットが得られるかもしれません。

具体的には、ローカルコンパイラキャッシュと分散コンパイラキャッシュの2種類のキャッシュを使用できます。

ローカルキャッシュ

情報

以下の手順は、AndroidとiOSの両方で機能します。Androidアプリのみをビルドしている場合は問題ありません。iOSアプリもビルドしている場合は、以下のXcode固有のセットアップセクションの手順に従ってください。

ネイティブビルドのコンパイルをキャッシュするためにccacheを使用することをお勧めします。Ccacheは、C++コンパイラをラップし、コンパイル結果を保存し、以前に中間コンパイル結果が保存されていればコンパイルをスキップすることで機能します。

Ccacheは、ほとんどのオペレーティングシステムのパッケージマネージャーで利用可能です。macOSでは、brew install ccacheでccacheをインストールできます。または、公式のインストール手順に従ってソースからインストールすることもできます。

次に、2回のクリーンビルドを実行します(例:Androidでは、まずyarn react-native run-androidを実行し、android/app/buildフォルダを削除してから、最初のコマンドをもう一度実行します)。2回目のビルドが1回目よりもはるかに高速になったことに気づくでしょう(数分ではなく数秒かかるはずです)。ビルド中に、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でccacheのReact Nativeサポートを有効にする必要があります。

エディタでios/Podfileを開き、ccache_enabled行のコメントを解除します。

ruby
  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でも対応するフォルダを保存および復元することで、ビルドを高速化できます。

ただし、いくつかの注意点があります。

  1. CIでは、ポイズンキャッシュの問題を避けるために、完全なクリーンビルドを実行することをお勧めします。前の段落で述べたアプローチに従う場合、ネイティブビルドを4つの異なるABIで並列化でき、CIでccacheはほとんど必要ないでしょう。

  2. ccacheはキャッシュヒットを計算するためにタイムスタンプに依存します。ファイルがCI実行ごとに再ダウンロードされるため、これはCIではうまく機能しません。これを克服するには、代わりにファイルのコンテンツをハッシュ化するcompiler_check contentオプションを使用する必要があります。

分散キャッシュ

ローカルキャッシュと同様に、ネイティブビルドに分散キャッシュの使用を検討することをお勧めします。これは、頻繁にネイティブビルドを行っている大規模な組織で特に役立つ可能性があります。

これを達成するためにsccacheを使用することをお勧めします。このツールのセットアップと使用方法については、sccacheの分散コンパイルクイックスタートを参照してください。