Bundled Hermes (バンドル版Hermes)
このページでは、Hermes と React Native がどのように構築されているかの概要を説明します。
アプリで Hermes を使用する方法については、別のページで説明しています: Hermes の使用
このページは技術的な詳細であり、Hermes または React Native の上に拡張機能を構築しているユーザーを対象としていることに注意してください。React Native の一般ユーザーは、React Native と Hermes がどのように相互作用するかについて詳細な情報を知る必要はありません。
「バンドルされたHermes」とは
React Native 0.69.0 以降、すべての React Native バージョンは Hermes バージョンと並行してビルドされます。この配布モデルをバンドルされたHermesと呼びます。
0.69 以降、React Native の各バージョンと並行してビルドおよびテストされた JS エンジンを常に使用できます。
「バンドルされたHermes」に移行した理由
これまで、React Native と Hermes は、異なるバージョン管理で 2 つの異なるリリースプロセスに従っていました。異なる番号の異なるリリースがあることで、OSS エコシステムで混乱が生じ、特定の Hermes バージョンが特定の React Native バージョンと互換性があるかどうかが不明確でした (つまり、Hermes 0.11.0 が React Native 0.68.0 などとしか互換性がないことを知る必要がありました)。
Hermes と React Native の両方が JSI コードを共有しています (Hermes はこちら、React Native はこちら)。JSI の 2 つの JSI コピーが同期しなくなると、Hermes のビルドは React Native のビルドと互換性がなくなります。このABI の非互換性の問題について詳しくはこちらをご覧ください。
この問題を克服するために、React Native のリリースプロセスを拡張して Hermes をダウンロードしてビルドし、Hermes のビルド時に JSI のコピーが 1 つだけ使用されるようにしました。
これにより、React Native のバージョンをリリースするたびに Hermes のバージョンをリリースでき、ビルドした Hermes エンジンがリリースする React Native バージョンと完全に互換性があることを確認できます。この Hermes バージョンをリリースしている React Native バージョンと一緒に出荷しているため、バンドルされたHermesという名前が付けられています。
これがアプリ開発者に与える影響
導入部で述べたように、アプリ開発者であれば、この変更は直接的な影響はありません。
以下の段落では、私たちが内部で行った変更と、透明性のためにその理由の一部を説明します。
iOSユーザー
iOSでは、使用しているhermes-engine
を移動しました。
React Native 0.69より前は、ユーザーはPodをダウンロードしていました (Podspecはこちらで確認できます)。
React Native 0.69では、ユーザーは代わりにreact-native
NPMパッケージ内のsdks/hermes-engine/hermes-engine.podspec
ファイルで定義されているPodspecを使用します。そのPodspecは、React Nativeリリースプロセスの一部としてMavenとReact Native GitHubリリースにアップロードするHermesのプリビルドされたtarballに依存しています (例: このリリースの資産を参照)。
Androidユーザー
Androidでは、デフォルトのテンプレート内のandroid/app/build.gradle
ファイルを次のように更新します。
dependencies {
// ...
if (enableHermes) {
+ implementation("com.facebook.react:hermes-engine:+") {
+ exclude group:'com.facebook.fbjni'
+ }
- def hermesPath = "../../node_modules/hermes-engine/android/";
- debugImplementation files(hermesPath + "hermes-debug.aar")
- releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
React Native 0.69より前は、ユーザーはhermes-engine
NPMパッケージからhermes-debug.aar
とhermes-release.aar
を消費していました。
React Native 0.69では、ユーザーはreact-native
NPMパッケージ内のandroid/com/facebook/react/hermes-engine/
フォルダーにあるAndroidマルチバリアント成果物を消費します。また、React Nativeの将来のバージョンでは、hermes-engine
への依存関係を完全に削除することにも注意してください。
新しいアーキテクチャのAndroidユーザー
ネイティブコードのビルド設定の性質(つまり、NDKの使用方法)により、新しいアーキテクチャのユーザーはHermesをソースからビルドします。
これにより、新しいアーキテクチャのユーザー向けのReact NativeとHermesのビルドメカニズムが統一されます(両方のフレームワークをソースからビルドします)。これは、そのようなAndroidユーザーが最初のビルド時にビルド時間のパフォーマンスヒットを経験する可能性があることを意味します。
ビルド時間を最適化し、ビルドへの影響を減らすための手順は、このページにあります:ビルドフェーズの高速化。
Windowsで新しいアーキテクチャをビルドするAndroidユーザー
Windowsマシンで新しいアーキテクチャを使用してReact Nativeアプリをビルドするユーザーは、ビルドが正しく機能するように次の追加手順に従う必要があります
- Android SDKとnodeを使用して、環境が正しく構成されていることを確認してください。
- Chocolateyでcmakeをインストールします。
- いずれかをインストールします。
- Visual Studio 2022のビルドツール.
- Visual Studio 22 Community Edition - C++デスクトップ開発のみを選択すれば十分です。
- Visual Studioコマンドプロンプトが正しく構成されていることを確認してください。これらのコマンドプロンプトで適切なC++コンパイラ環境変数が構成されているため、これは必須です。
- Visual Studioコマンドプロンプト内で
npx react-native run-android
を実行してアプリを実行します。
ユーザーは別のエンジンをまだ使用できますか?
はい、ユーザーはHermesを有効/無効にすることができます(AndroidではenableHermes
変数、iOSではhermes_enabled
)。「バンドルされたHermes」の変更は、Hermesがどのようにビルドされ、バンドルされるかにのみ影響します。
React Native 0.70以降、enableHermes
/hermes_enabled
のデフォルトはtrue
です。
これがコントリビューターと拡張機能開発者に与える影響
React Nativeのコントリビューターである場合、またはReact NativeまたはHermesの上に拡張機能を構築している場合は、バンドルされたHermesがどのように機能するかを説明しますので、引き続きお読みください。
バンドルされたHermesはどのように機能しているのか?
このメカニズムは、facebook/hermes
リポジトリからHermesソースコードを含むtarballをダウンロードしてfacebook/react-native
リポジトリに配置することに依存しています。他のネイティブ依存関係 (Folly、Glogなど) にも同様のメカニズムがあり、Hermesも同じ設定に従うように調整しました。
main
ブランチからReact Nativeをビルドする場合、facebook/hermesのmain
ブランチのtarballをフェッチし、React Nativeのビルドプロセスの一部としてビルドします。
リリースブランチ (例えば0.69-stable
) からReact Nativeをビルドする場合、代わりにHermesリポジトリのタグを使用して、2つのリポジトリ間のコードを同期させます。使用される特定のタグ名は、その後、リリースブランチのReact Native内のsdks/.hermesversion
ファイルに保存されます (例: これは0.69リリースブランチのファイルです)。
ある意味、このアプローチはgit submoduleに似ていると考えることができます。
Hermesの上に構築している場合、React Nativeのバージョンがタグ名に指定されているため (例: hermes-2022-05-20-RNv0.69.0-ee8941b8874132b8f83e4486b63ed5c19fc3f111
)、これらのタグに頼ってReact Nativeのビルド時に使用されたHermesのバージョンを理解できます。
Androidの実装詳細
Androidでこれを実装するために、React Nativeの/ReactAndroid/hermes-engine
内に新しいビルドを追加しました。これは、Hermesのビルドと消費のためのパッケージングを行います (詳細はこちら)。
これで、次を呼び出してHermesエンジンのビルドをトリガーできます。
// Build a debug version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleDebug
// Build a release version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleRelease
React Nativeのmain
ブランチから。
ビルドはNDKバージョンのツールを使用するように設定されているため、マシンに余分なツール (cmake
、ninja
、python3
など) をインストールする必要はありません。
Gradleコンシューマー側では、コンシューマー側に小さな改善も施しました。releaseImplementation
とdebugImplementation
からimplementation
に移行しました。これは、新しいhermes-engine
Androidアーティファクトがバリアント対応であり、エンジンのデバッグビルドをアプリのデバッグビルドと適切に照合できるためです。ここではカスタム設定は必要ありません (staging
やその他のビルドタイプ/フレーバーを使用している場合でも)。
しかし、これにより、テンプレートにこの行が必要になりました
exclude group:'com.facebook.fbjni'
これは、React Nativeが非プリファブアプローチ(つまり、.aar
を解凍して.so
ファイルを抽出する)を使用してfbjni
を消費しているために必要です。Hermes-engineやその他のライブラリは、代わりにプリファブを使用してfbjniを消費しています。将来、この問題に対処することを検討しており、Hermesのインポートが1行になるようにします。
iOS実装の詳細
iOSの実装は、次の場所に存在する一連のスクリプトに依存しています。
/scripts/hermes
。これらのスクリプトには、Hermes tarballをダウンロードし、解凍し、iOSビルドを構成するロジックが含まれています。hermes_enabled
フィールドがtrue
に設定されている場合、pod install
時に呼び出されます。/sdks/hermes-engine
。これらのスクリプトには、実際にHermesをビルドするビルドロジックが含まれています。これらはfacebook/hermes
リポジトリからコピーされ、React Native内で適切に動作するように調整されました。特に、utils
フォルダー内のスクリプトは、すべてのMacプラットフォーム用のHermesのビルドを担当しています。
Hermesは、CircleCIのbuild_hermes_macos
ジョブの一部としてビルドされます。このジョブは成果物としてtarballを生成し、公開されたReact Nativeリリースを使用するとhermes-engine
podspecによってダウンロードされます (build_hermes_macos
でReact Native 0.69用に作成された成果物の例はこちら)。
プリビルドされたHermes
使用されているReact Nativeバージョンにプリビルドされた成果物がない場合(つまり、main
ブランチからReact Nativeを操作している場合)、Hermesはソースからビルドする必要があります。まず、pod install
中にHermesコンパイラのhermesc
がmacOS用にビルドされ、次にbuild-hermes-xcode.sh
スクリプトを使用してXcodeビルドパイプラインの一部としてHermes自体がビルドされます。
ソースからHermesをビルドする
main
ブランチからReact Nativeを使用する場合、Hermesは常にソースからビルドされます。安定版のReact Nativeを使用している場合、CocoaPodsを使用するときにCI
環境変数をtrue
に設定することで、Hermesをソースからビルドするように強制できます: CI=true pod install
。
デバッグシンボル
Hermesのプリビルドされた成果物には、デフォルトでデバッグシンボル(dSYMs)が含まれていません。将来的には、これらのデバッグシンボルを各リリースで配布する予定です。それまでは、Hermesのデバッグシンボルが必要な場合は、Hermesをソースからビルドする必要があります。hermes.framework.dSYM
は、Hermesの各フレームワークと一緒にビルドディレクトリに作成されます。
この変更が私に影響を与えているようです
これは本質的に、Hermesがどこでビルドされ、2つのリポジトリ間でコードがどのように同期されるかという組織的な変更であることを強調したいと思います。この変更はユーザーにとって完全に透過的であるべきです。
これまで、React Nativeの特定のバージョン向けにHermesのリリースを行っていました (例: RN0.68.x向けのv0.11.0
)。
「バンドルされたHermes」では、代わりに、React Nativeの特定のバージョンがリリースされたときに使用されたバージョンを表すタグに依存できます。