Skip to main content

번들링된 Hermes

이 페이지는 Hermes와 React Native가 어떻게 빌드되는지에 대한 개요를 제공합니다.

앱에서 Hermes를 사용하는 방법에 대한 지침을 찾고 있다면, 다른 페이지에서 확인할 수 있습니다: Hermes 사용하기

caution

이 페이지는 기술적인 심층 분석을 제공하며, Hermes나 React Native 위에 확장 기능을 구축하는 사용자를 대상으로 합니다. React Native의 일반 사용자는 React Native와 Hermes가 어떻게 상호작용하는지에 대한 깊이 있는 정보를 알 필요가 없습니다.

'Bundled Hermes'란 무엇인가

React Native 0.69.0부터는 모든 React Native 버전이 Hermes 버전과 함께 빌드됩니다. 이 배포 모델을 Bundled Hermes라고 부릅니다.

0.69 버전부터는 여러분이 사용할 수 있는 React Native 버전마다 함께 빌드되고 테스트된 JS 엔진이 항상 제공됩니다.

'Bundled Hermes'로 전환한 이유

기존에는 React Native와 Hermes가 서로 다른 릴리스 프로세스와 버전 관리를 따랐습니다. 이로 인해 OSS 생태계에서 특정 Hermes 버전이 특정 React Native 버전과 호환되는지 명확하지 않아 혼란이 생겼습니다. 예를 들어, Hermes 0.11.0이 React Native 0.68.0과만 호환된다는 사실을 알아야 했습니다.

Hermes와 React Native는 모두 JSI 코드를 공유합니다 (Hermes JSI 코드React Native JSI 코드). 만약 두 JSI 코드가 동기화되지 않으면, Hermes 빌드가 React Native 빌드와 호환되지 않는 문제가 발생합니다. 이 ABI 호환성 문제에 대해 더 자세히 읽어볼 수 있습니다.

이 문제를 해결하기 위해, React Native 릴리스 프로세스를 확장하여 Hermes를 다운로드하고 빌드하도록 했습니다. 이를 통해 Hermes를 빌드할 때 단 하나의 JSI 코드만 사용되도록 보장했습니다.

이 덕분에 React Native 버전을 릴리스할 때마다 Hermes 버전도 함께 릴리스할 수 있게 되었고, 빌드된 Hermes 엔진이 릴리스하는 React Native 버전과 완벽히 호환되도록 할 수 있었습니다. 이렇게 함께 제공되는 Hermes 버전을 _Bundled Hermes_라고 부릅니다.

이 변경이 앱 개발자에게 미치는 영향

서문에서 언급했듯이, 여러분이 앱 개발자라면 이 변경 사항이 직접적인 영향을 미치지 않을 것입니다.

다음 단락에서는 투명성을 위해 내부적으로 어떤 변경을 했는지 설명하고, 그 배경을 설명합니다.

iOS 사용자

iOS에서는 여러분이 사용 중인 hermes-engine을 이동했습니다.

React Native 0.69 이전에는 사용자가 podspec을 통해 pod를 다운로드했습니다.

React Native 0.69부터는 react-native NPM 패키지 내부의 sdks/hermes-engine/hermes-engine.podspec 파일에 정의된 podspec을 사용하게 됩니다. 이 podspec은 React Native 릴리스 프로세스의 일환으로 Maven과 React Native GitHub 릴리스에 업로드된 Hermes의 사전 빌드된 tarball에 의존합니다 (예: 이 릴리스의 assets 참조).

Android 사용자

Android에서는 기본 템플릿의 android/app/build.gradle 파일을 다음과 같이 업데이트할 예정입니다:

diff
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.aarhermes-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 명령 프롬프트가 올바르게 설정되었는지 확인하세요. 이 명령 프롬프트에서 적절한 C++ 컴파일러 환경 변수가 설정되어 있어야 합니다.
  • Visual Studio 명령 프롬프트 내에서 npx react-native run-android로 앱을 실행하세요.

다른 엔진을 사용할 수 있나요?

네, 사용자는 Hermes를 자유롭게 활성화하거나 비활성화할 수 있습니다. (Android에서는 enableHermes 변수, iOS에서는 hermes_enabled를 사용) 'Bundled Hermes' 변경 사항은 Hermes가 빌드되고 번들링되는 방식에만 영향을 미칩니다.

React Native 0.70부터 enableHermeshermes_enabled의 기본값은 true로 설정됩니다.

이 변경 사항이 기여자와 확장 개발자에게 미치는 영향

여러분이 React Native 기여자이거나 React Native 또는 Hermes 위에 확장 기능을 구축 중이라면, Bundled Hermes가 어떻게 동작하는지 설명하는 이 부분을 계속 읽어보세요.

번들링된 Hermes는 내부적으로 어떻게 동작하나요?

이 메커니즘은 facebook/react-native 저장소 내부의 facebook/hermes 저장소에서 Hermes 소스 코드가 포함된 tarball을 다운로드하는 방식에 의존합니다. 다른 네이티브 의존성(Folly, Glog 등)에도 비슷한 메커니즘이 적용되어 있으며, Hermes도 동일한 설정을 따르도록 조정했습니다.

main 브랜치에서 React Native를 빌드할 때는 facebook/hermesmain 브랜치 tarball을 가져와 React Native 빌드 과정의 일부로 빌드합니다.

릴리스 브랜치(예: 0.69-stable)에서 React Native를 빌드할 때는 두 저장소 간의 코드 동기화를 위해 Hermes 저장소의 태그를 사용합니다. 사용된 특정 태그 이름은 React Native의 릴리스 브랜치 내 sdks/.hermesversion 파일에 저장됩니다(예: 0.69 릴리스 브랜치의 파일).

이 접근 방식은 git 서브모듈과 유사하다고 볼 수 있습니다.

Hermes를 기반으로 빌드하는 경우, React Native 빌드 시 사용된 Hermes 버전을 이해하기 위해 이러한 태그를 활용할 수 있습니다. 태그 이름에는 React Native 버전이 명시되어 있습니다(예: hermes-2022-05-20-RNv0.69.0-ee8941b8874132b8f83e4486b63ed5c19fc3f111).

Android 구현 세부 사항

이 기능을 Android에서 구현하기 위해 React Native의 /ReactAndroid/hermes-engine 내부에 새로운 빌드를 추가했습니다. 이 빌드는 Hermes를 빌드하고 패키징하는 작업을 처리합니다 (자세한 내용은 여기 참조).

이제 React Native main 브랜치에서 다음 명령어를 실행하여 Hermes 엔진을 빌드할 수 있습니다:

bash
// 디버그 버전의 Hermes 빌드
./gradlew :ReactAndroid:hermes-engine:assembleDebug
// 릴리스 버전의 Hermes 빌드
./gradlew :ReactAndroid:hermes-engine:assembleRelease

여러분의 머신에 cmake, ninja, python3 같은 추가 도구를 설치할 필요가 없습니다. 빌드가 NDK 버전의 도구를 사용하도록 설정되어 있기 때문입니다.

Gradle 소비자 측면에서도 작은 개선 사항을 제공했습니다: releaseImplementationdebugImplementation에서 implementation으로 전환했습니다. 이는 새로운 hermes-engine Android 아티팩트가 빌드 변형을 인식하기 때문에 가능합니다. 따라서 엔진의 디버그 빌드가 앱의 디버그 빌드와 올바르게 매칭됩니다. 여기서는 staging이나 다른 빌드 타입/플레이버를 사용하더라도 커스텀 설정이 필요하지 않습니다.

그러나 이로 인해 템플릿에 다음 줄이 필요해졌습니다:

exclude group:'com.facebook.fbjni'

이는 React Native가 fbjni를 prefab 방식이 아닌 방식(즉, .aar 파일을 압축 해제하고 .so 파일을 추출하는 방식)으로 사용하기 때문입니다. Hermes-engine 및 다른 라이브러리들은 prefab을 사용하여 fbjni를 소비합니다. 우리는 이 문제를 해결하기 위해 이슈를 처리 중이며, 향후 Hermes 임포트가 한 줄로 가능하도록 할 예정입니다.

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 Job의 일부로 빌드됩니다. 이 Job은 아티팩트로 tarball을 생성하며, 이 tarball은 React Native 릴리즈가 공개될 때 hermes-engine podspec에 의해 다운로드됩니다 (React Native 0.69를 위한 build_hermes_macos에서 생성된 아티팩트 예시).

사전 빌드된 Hermes

사용 중인 React Native 버전에 대해 사전 빌드된 아티팩트가 없는 경우(예: main 브랜치의 React Native를 사용 중일 수 있음), Hermes를 소스에서 빌드해야 합니다. 먼저, pod install 중에 macOS용 Hermes 컴파일러인 hermesc가 빌드됩니다. 그런 다음, build-hermes-xcode.sh 스크립트를 사용하여 Xcode 빌드 파이프라인의 일부로 Hermes 자체가 빌드됩니다.

Hermes 소스 코드로 빌드하기

React Native의 main 브랜치를 사용할 때는 항상 Hermes를 소스 코드로 빌드합니다. 안정적인 React Native 버전을 사용 중이라면, CocoaPods를 사용할 때 CI 환경 변수를 true로 설정하여 Hermes를 소스 코드로 강제 빌드할 수 있습니다: CI=true pod install.

디버그 심볼

Hermes의 사전 빌드된 아티팩트는 기본적으로 디버그 심볼(dSYMs)을 포함하지 않습니다. 앞으로 각 릴리스마다 이 디버그 심볼을 배포할 계획입니다. 그때까지 Hermes의 디버그 심볼이 필요하다면 소스 코드에서 Hermes를 직접 빌드해야 합니다. 빌드 디렉토리에는 각 Hermes 프레임워크와 함께 hermes.framework.dSYM 파일이 생성됩니다.

이 변경 사항이 저에게 영향을 미치는 것 같아요

이 변경 사항은 기본적으로 Hermes가 빌드되는 위치와 두 저장소 간 코드 동기화 방식에 대한 조직적 변화임을 강조하고 싶습니다. 이 변경은 사용자에게 완전히 투명하게 이루어져야 합니다.

과거에는 특정 React Native 버전에 맞춰 Hermes 릴리즈를 진행했습니다 (예: v0.11.0 for RN0.68.x).

'Bundled Hermes'를 사용하면 특정 React Native 버전이 릴리즈될 때 사용된 버전을 나타내는 태그에 의존할 수 있습니다.