跳到主要内容
新架构实战课 实操 + 基建 + 原理全维度包揽,抢先掌握 React Native 新架构精髓 立即查看 >

内置 Hermes 引擎

This page gives an overview of how Hermes and React Native are built.

If you're looking into instructions on how to use Hermes in your app, you can find instructions on this other page: using Hermes

caution

Please note that this page serves as a technical deep dive and is targeted for users which are building extensions on top of Hermes or React Native. General users of React Native should not need to know in-depth information on how React Native and Hermes interact.

What is 'Bundled Hermes'

Starting with React Native 0.69.0, every version of React Native will be built alongside to a Hermes version. We call this distribution model Bundled Hermes.

From 0.69 on, you will always have a JS engine that has been built and tested alongside each React Native version that you can use.

Why we moved to 'Bundled Hermes'

Historically, React Native and Hermes followed two distinct release processes with distinct versioning. Having distinct releases with distinct numbers created confusion in the OSS ecosystem, where it was not clear if a specific version of Hermes was compatible with a specific version of React Native (i.e. you needed to know that Hermes 0.11.0 was compatible only with React Native 0.68.0, etc.)

Both Hermes and React Native, share the JSI code (Hermes here and React Native here). If the two JSI copies of JSI get out of sync, a build of Hermes won't be compatible with a build of React Native. You can read more about this ABI incompatibility problem here.

To overcome this problem, we've extended the React Native release process to download and build Hermes and made sure only one copy of JSI is used when building Hermes.

Thanks to this, we can release a version of Hermes whenever we release a version of React Native, and be sure that the Hermes engine we built is fully compatible with the React Native version we're releasing. We're shipping this version of Hermes alongside the React Native version we're doing, hence the name Bundled Hermes.

How this will impact app developers

As mentioned in the introduction, if you're an app developer, this change should not affect you directly.

The following paragraphs describe which changes we did under the hood and explains some of the rationales, for the sake of transparency.

iOS Users

On iOS, we've moved the hermes-engine you're using.

Prior to React Native 0.69, users would download a pod (here you can find the podspec).

On React Native 0.69, users would instead use a podspec that is defined inside the sdks/hermes-engine/hermes-engine.podspec file in the react-native NPM package. That podspec relies on a pre-built tarball of Hermes that we upload on GitHub Releases, as part of the React Native release process (i.e. see the assets of this release).

Android Users

On Android, we're going to update the android/app/build.gradle file in the default template the following way:

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
}
}

Prior to React Native 0.69, users will be consuming hermes-debug.aar and hermes-release.aar from the hermes-engine NPM package.

On React Native 0.69, users will be consuming the Android multi-variant artifacts available inside the android/com/facebook/react/hermes-engine/ folder in the react-native NPM package. Please also note that we're going to remove the dependency on hermes-engine entirely in one of the future version of React Native.

Android Users on New Architecture

Due to the nature of our native code build setup (i.e. how we use the NDK), users on the New Architecture will be building Hermes from source.

This aligns the build mechanism of React Native and Hermes for users on the New Architecture (they will build both framework from source). This means that such Android users might experience a performance hit at build time on their first build.

You can find instructions to optimize your build time and reduce the impact on your build on this page: Speeding up your Build phase.

Android Users on New Architecture building on Windows

Users building React Native App, with the New Architecture, on Windows machines need to follow those extra steps to let the build work correctly:

Can users still use another engine?

Yes, users are free to enable/disable Hermes (with the enableHermes variable on Android, hermes_enabled on iOS). The 'Bundled Hermes' change will impact only how Hermes is built and bundled for you.

Please note that, at the time of writing, the default for enableHermes/hermes_enabled is false. We're looking into updating the template to have it default to true in the near future.

How this will impact contributor and extension developers

If you're a React Native contributor or you're building an extension on top of React Native or Hermes, please read further as we explain how Bundled Hermes works.

How is Bundled Hermes working under the hood?

This mechanism relies on downloading a tarball with the Hermes source code from the facebook/hermes repository inside the facebook/react-native repository. We have a similar mechanism in place for other native dependencies (Folly, Glog, etc.) and we aligned Hermes to follow the same setup.

When building React Native from main, we will be fetching a tarball of main of facebook/hermes and building it as part of the build process of React Native.

When building React Native from a release branch (say 0.69-stable), we will instead use a tag on the Hermes repo to syncronize the code between the two repos. The specific tag name used will then be stored inside the sdks/.hermesversion file inside React Native in the release branch (e.g. this is the file on the 0.69 release branch).

In a sense, you can think of this approach similarly to a git submodule.

If you're building on top of Hermes, you can rely on those tags to understand which version of Hermes was used when building React Native, as the version of React Native is specified in the tag name (e.g. hermes-2022-05-20-RNv0.69.0-ee8941b8874132b8f83e4486b63ed5c19fc3f111).

Android implementation details

To implement this on Android, we've added a new build inside the /ReactAndroid/hermes-engine of React Native that will take care of building Hermes and packaging for consumption ((See here for more context)[https://github.com/facebook/react-native/pull/33396]).

You can now trigger a build of Hermes engine by invoking:

// Build a debug version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleDebug
// Build a release version of Hermes
./gradlew :ReactAndroid:hermes-engine:assembleRelease

from the React Native main branch.

You won't need to install extra tools (such as cmake, ninja or python3) in your machine as we configured the build to use the NDK versions of those tools.

On the Gradle consumer side, we also shipped a small improvement on the consumer side: we moved from releaseImplementation & debugImplementation to implementation. This is possible because the newer hermes-engine Android artifact is variant aware and will properly match a debug build of the engine with a debug build of your app. You don't need any custom configuration here (even if you use staging or other build types/flavors).

However, this made this line necessary in the template:

exclude group:'com.facebook.fbjni'

This is needed as React Native is consuming fbjni using the non-prefab approach (i.e. unzipping the .aar and extracting .so files). Hermes-engine, and other libraries, are using prefab instead to consume fbjni. We're looking into addressing this issue in the future so the Hermes import will be a oneliner.

iOS implementation details

The iOS implementation relies on a series of scripts that lives in the following locations:

  • /scripts/hermes. Those scripts contain logic to download the hermes tarball, unzip it, and configure the iOS build. They're invoked at pod install time if you have the hermes_enabled field set to true.
  • /sdks/hermes-engine. Those scripts contain the build logic that is effectively building Hermes. They were copied and adapted from the facebook/hermes repo to properly work within React Native. Specifically, the scripts inside the utils folder are responsible of building Hermes for all the Mac platforms.

To distribute a prebuilt for iOS, we rely on the build_hermes_macos Job on CircleCI. The job will produce as artifact a tarball which will be downloaded by the hermes-engine podspec (i.e. those are the artifacts for an execution for React Native 0.69).

I'm afraid this change is impacting me

We'd like to stress that this is essentially an organizational change on where Hermes is built and how the code is syncronized between the two repositories. The change should be fully transparent to our users.

Historically, we used to cut a release of Hermes for a specific version of React Native (e.g. v0.11.0 for RN0.68.x).

With 'Bundled Hermes', you can instead rely on a tag that will represent the version used when a specific version of React Native was cut.