とにかく速くビルドする:Expo はどう速度を最適化しているか(そしてあなたもできること)
新しい M4 Mac Mini、コンパイラキャッシュ、事前ビルド済みバイナリが EAS ビルドを高速化している。フィンガープリントと OTA 更新でビルド回数を減らす方法を解説する。
日本語
コピー

あなたにはスピードが要る。
授業の合間に初めてのアプリを出す学生でも、昼休みに副業プロジェクトをこっそり進めるエンジニアでも、何百万人ものユーザーを抱える企業チームでも、制約は同じだ。ビルドを待っている時間はない。フィードバックはすぐに欲しい。アイデアが熱いうちにリリースしたい。
ビルドが遅ければ勢いは途切れる。速ければフローに留まれる。いいプロダクトはそういう状態から生まれる。
どのプランを使っていても、最速のビルドを届けること。それが私たちの目標だ。その約束を守るために、Expo が前例のない需要と Mac ハードウェアの不足に直面する中で手を打ち、企業のエンジニアと vibe coder の両方に対応できるよう規模を拡大している。
OpenClaw で AI 自動化をやっている人にとって、Mac Mini は争奪戦の的だ。とくにメモリを増やした構成はそうで、メモリ自体ずっと前から不足している。私たちのビルドサーバー構成ページを見たことがあれば分かる通り、iOS ビルドはフル構成の M4 Mac Mini で動いている。Mac Mini の世界的な納期遅延に、世界中の vibe coder、インディー開発者、地元企業、大企業が巻き起こしたアプリ開発ブームが重なれば、Expo の Build と Workflows のキューに影響が出るのではと気になるのは当然だ。
ビルドを速くし、インフラを増強するために私たちがやっていることは次の通り:
-
まず、最近クラスタに新しい M4 Pro と Max の Mac Mini を数十台追加した。今もさらに導入を続けていて、発注済みで輸送中の分もある。
-
ビルドごとの速度を上げる取り組みも複数進めている。つまり誰もがより多くのビルドを回せるようになる。
-
最近 SDK 54 と 55 のプロジェクトにコンパイラレベルのキャッシュを導入し、fastlane と gradlew のステップを最大 30% 高速化した。
-
Android ビルドの性能を上げるため、Gradle キャッシュを展開中だ。
-
react-native-reanimatedやreact-native-screensのようなよく使うパッケージにはプリコンパイル済みバイナリを追加している。これでこれらの生成にかかる時間はほぼゼロになる。
-
-
SDK 56 では iOS で最も複雑な Expo モジュールにプリコンパイル済み XCFrameworksを提供し、iOS ビルドを高速化する。
私たちの狙いは、すべてのビルダーが本物を作る機会を持てるようにすることだ。Expo を初めて使ってビルドが一瞬で終わったとき、それを実感するはずだ。それがまた起きて、いつしかビルドのことなど考えなくなる。すべてが正しく、速く動くと信じられるようになる。それが私たちの基準だ。インフラを気にせず、いいものづくりに集中できるようにする。
同じ基準はツールにも当てはまる。私たちの開発者ツールは、一度のビルドを最大限活かせるようにし、手持ちのハードウェアの性能を引き出しやすくするものであるべきだ。
フィンガープリントベースのワークフローでビルド回数を減らす
ccache とプリコンパイル済み React Native バイナリを有効にした EAS M4 Max large worker でのビルドより速いものは何か? ビルドしないことだ。
Expo の OTA Updatesで本番アプリにバグ修正を配信する必要がない場合でも、プレビューアプリのフィードバックループを最短にするのにうってつけだ。ほとんどのアプリはコードを変えるたびにフルビルドし直す必要がない。ほとんどの変更は JavaScript だけだからだ。代わりに更新をプッシュし、JavaScript だけを再ビルドして、インストール済みのアプリに新しいコードをダウンロードさせればいい。
eas update:configure を実行すると、アプリが EAS Update を使うよう設定され、再ビルドされる。動的なアプリ設定を使えば、プレビューアプリだけで更新を有効にできる(その場合は updates.enabled を false に設定する)。
その後、ネイティブコードや依存関係を変更していないと分かっているときは、eas update --channel preview を実行して手動でアプリを更新できる。あるいは EAS workflow として設定し、コミット時に自動で実行して、ネイティブのフィンガープリントのサンプリング結果に応じてビルドか更新かを選ぶこともできる。フィンガープリントはハッシュで、ネイティブコードが変わったときだけ変化する。
Expo プロジェクトを Github に接続し、この workflow を .eas/workflows フォルダに追加する:
name: Build or update preview on main push, based on fingerprint
on:
# Trigger on pushes to main branch
push:
branches: [main]
jobs:
fingerprint:
environment: preview
type: fingerprint
ios_get_build:
needs: [fingerprint]
type: get-build
params:
fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
platform: ios
profile: preview
ios_update:
needs: [ios_get_build]
if: ${{ needs.ios_get_build.outputs.build_id }}
type: update
params:
channel: preview
platform: ios
ios_build:
needs: [ios_get_build]
if: ${{ !needs.ios_get_build.outputs.build_id }}
type: build
params:
platform: ios
profile: preview
# add the same steps for Android to handle those builds/updates, as well!
アプリに EAS Update を導入し、可能な限りこれでコードを更新するのは、一度のビルドを最大限活かすいい方法だ。
開発とテストのためにローカルでビルドする
npx expo start でローカル開発サーバーを起動し、Expo Go や development build でアプリを動かす——これが Expo CLI の最も一般的な使い方だろう。だが、必要なら Expo CLI はアプリをシミュレータや実機で直接ビルドして実行することもできる。
準備
ローカルでビルドするとき、Expo CLI はインストール済みの Android Studio や Xcode を呼び出し、その中のネイティブ開発ツールを使う。これらのツールは設定を少し誤るだけで問題が起きるので、検証済みの Android と iOS のビルド構成をまとめたローカルビルドガイドを用意した。iOS のビルドには Mac が必要だ。
ローカルでの development build
ネイティブツールをインストールしたら、次のコマンドでシミュレータ上にアプリをビルドして実行できます。
npx expo run:android
または
npx expo run:ios
これでアプリの debug build が生成され、ローカルの開発サーバーが起動します(npx expo start がやっていることです)。つまり、ローカルでビルドが完了するだけでなく、JavaScript コードを編集するとリアルタイムでリロードされます。
このコマンドを初めて実行すると、npx expo prebuild も実行されて android と iOS のネイティブディレクトリが生成されます。ネイティブコードを含むパッケージを追加した場合や app.json を変更した場合は、通常 npx expo prebuild --clean を実行してこれらのディレクトリを再生成し、npx expo run:android|ios を実行して再ビルドする必要があります。これは EAS がアプリをビルドするたびに行っていることとほぼ同じです。
expo-dev-client をインストールするとさらに便利になります。このパッケージは任意の debug build を development build に変えることができ、任意の開発サーバーの URL を開けるようになります。development build を一度シミュレータにインストールしてしまえば、ネイティブランタイムが変わらない限り、何度も再ビルドする必要はありません。そのまま npx expo start を実行し、Android では a、iOS では i を押して開きます。
Release build
development build ではテストしにくいものがあります。起動画面は特にそうです。リリース前のテストの多くは、ローカルビルドでも十分こなせます。スタンドアロンの release build をビルドしてください。
npx expo run:android --variant release
または
npx expo run:ios --configuration Release
ビルドの共有
EAS を使えば、ローカルでビルドした Android APK ビルドと iOS シミュレータビルドを、組織内の他の開発者と共有できます。eas upload を実行して手動でビルドをアップロードし共有可能なリンクを生成するか、EAS をビルドキャッシュプロバイダーとして設定して自動化します。あとは他の開発者が eas build:run を実行すれば、そのビルドをダウンロードして実行できます。
デバイスへのビルド
npx expo run:android|ios を使えば、USB 接続したデバイス上でビルドを実行することもできます。
Android の場合、Android 端末を接続して USB デバッグが有効になっていることを確認し、adb devices -l を実行してデバイス名を取得し、そのデバイス名を npx expo run:android --device [device-name] に入力します。
iOS の場合、デバイスを接続して開発者モードが有効になっていることを確認し、xcrun xctrace list devices を実行してデバイスの UDID を取得したら、npx expo run:ios --device [udid] を実行します。Xcode で ios フォルダを開き、開発チームを選択する必要があるかもしれません(必要なら Expo CLI が促してくれます)。
development build であれば、ネイティブランタイムが変わらない限り、USB を外した後も同じビルドを使い続けられます。あとは npx expo start を実行して QR コードをスキャンするだけです。
署名済みの本番ビルドを生成する
EAS のクレデンシャル管理はかなり便利で、シミュレータやエミュレータ、接続したデバイスで実行するのに必要な簡単な署名設定があれば、開発とテストの大半は事足ります。なので、このローカル署名の流れは「非常時にガラスを割る」ための保険だと思っておけばよいでしょう。とはいえ、EAS が生成した本番用クレデンシャルを使ってローカルでビルドしたい場合には、方法があります。
まず、eas credentials コマンドで必要なクレデンシャルをダウンロードします。各プラットフォームで必要なもの(Android のアップロードキーストアと iOS の配布証明書)について、順を追って案内してくれます。次に npx expo prebuild --clean を実行してネイティブプロジェクトを生成します。複数のアプリバリアントを使っている場合は、環境が本番バリアントに切り替わっていることを確認してください(EAS の環境変数で設定しているなら、eas env:pull を実行してローカルにこれらの変数を設定できます)。
Android では、Android Studio で android フォルダを開き、Build → Generate Signed App Bundle or APK に進み、先ほどダウンロードした keystore を入力します。
iOS では、ダウンロードしたクレデンシャルを解凍して Keychain にインストールします。Xcode で ios フォルダを開き、Target の Signing and Capabilities を確認して署名設定に問題がないことを確かめます。provisioning profile を再生成したほうが楽かもしれません(そうしても害はありません)。あとは Product → Archive を実行してビルドします。
おわりに
ローカルビルドは、ローカルのネイティブコードのデバッグからネットワークアクセスの制約まで、さまざまな理由でツールボックスに加えておく価値のあるものです。クラウドの EAS Build や Workflows と補完し合い、行き詰まったときに助けてくれます。その間も残りの自動化は EAS 上で動き続けます。自動化と言えば、fingerprints と EAS Update を導入するのに良いタイミングでもあります。再ビルドの頻度とタイミングを抑えられ、イテレーションの速度はさらに上がります。