빌드 단계 속도 향상
React Native 앱을 빌드하는 과정은 비용이 많이 들고 개발자의 시간을 몇 분이나 소모할 수 있다. 프로젝트가 커지고 React Native 개발자가 여러 명인 대규모 조직에서는 이 문제가 더욱 두드러질 수 있다.
빌드 시간에 미치는 영향을 줄이기 위해, 이 페이지에서는 빌드 시간을 개선할 수 있는 몇 가지 제안을 공유한다.
개발 중에는 하나의 ABI만 빌드하기 (Android 전용)
안드로이드 앱을 로컬에서 빌드할 때, 기본적으로 4가지 Application Binary Interfaces (ABIs)를 모두 빌드한다: armeabi-v7a
, arm64-v8a
, x86
, x86_64
.
하지만 로컬에서 빌드하고 에뮬레이터나 실제 기기에서 테스트하는 경우라면, 모든 ABI를 빌드할 필요는 없다.
이렇게 하면 네이티브 빌드 시간을 약 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에서 안드로이드 앱을 빌드하고, 다른 아키텍처의 빌드를 병렬화하기 위해 매트릭스를 사용할 때 유용하다.
원한다면 프로젝트의 최상위 폴더에 있는 gradle.properties
파일을 사용해 이 값을 로컬에서 재정의할 수도 있다:
# 이 속성을 사용해 빌드할 아키텍처를 지정할 수 있다.
# CLI에서도 재정의할 수 있다:
# ./gradlew <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
앱의 릴리스 버전을 빌드할 때는, 일상적인 개발 워크플로에서 사용하는 ABI뿐만 아니라 모든 ABI에서 동작하는 apk/app bundle을 빌드해야 하므로, 이러한 플래그를 제거하는 것을 잊지 말아야 한다.
컴파일러 캐시 활용하기
C++나 Objective-C 같은 네이티브 빌드를 자주 실행한다면, 컴파일러 캐시를 사용하는 것이 도움이 될 수 있다.
주로 두 가지 타입의 캐시를 활용할 수 있다: 로컬 컴파일러 캐시와 분산 컴파일러 캐시다.
로컬 캐시
다음 지침은 Android와 iOS 모두에서 작동한다.
Android 앱만 개발한다면 바로 진행해도 된다.
iOS 앱도 함께 개발한다면 아래 XCode 특별 설정 섹션의 지침을 따르면 된다.
네이티브 빌드의 컴파일을 캐싱하기 위해 ccache를 사용할 것을 권장한다.
Ccache는 C++ 컴파일러를 감싸고, 컴파일 결과를 저장하며, 이전에 저장된 중간 컴파일 결과가 있으면 컴파일을 건너뛴다.
Ccache는 대부분의 운영체제에서 패키지 관리자를 통해 설치할 수 있다. macOS에서는 brew install ccache
로 설치한다.
또는 공식 설치 가이드를 따라 소스에서 설치할 수도 있다.
그런 다음 두 번의 깨끗한 빌드를 수행한다(예: Android에서 yarn react-native run-android
를 실행한 후, android/app/build
폴더를 삭제하고 동일한 명령을 다시 실행). 두 번째 빌드가 첫 번째보다 훨씬 빠르다는 것을 확인할 수 있다(몇 분이 아니라 몇 초 내에 완료된다).
빌드 중에 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 특정 설정
iOS와 XCode에서 ccache
가 올바르게 작동하게 하려면 ios/Podfile
에서 React Native의 ccache 지원을 활성화해야 한다.
에디터에서 ios/Podfile
을 열고 ccache_enabled
줄의 주석을 해제한다.
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: 아래 줄의 주석을 해제
:ccache_enabled => true
)
end
CI 환경에서 이 접근 방식 사용하기
Ccache는 macOS에서 /Users/$USER/Library/Caches/ccache
폴더를 사용해 캐시를 저장한다. 따라서 CI 환경에서도 해당 폴더를 저장하고 복원해 빌드 속도를 높일 수 있다.
하지만 몇 가지 주의할 점이 있다:
-
CI에서는 캐시 오염 문제를 방지하기 위해 완전히 깨끗한 빌드를 수행하는 것을 권장한다. 앞서 언급한 접근 방식을 따르면 네이티브 빌드를 4개의 다른 ABI에서 병렬로 실행할 수 있으며, 이 경우 CI에서
ccache
가 필요하지 않을 가능성이 높다. -
ccache
는 캐시 적중을 계산하기 위해 타임스탬프를 사용한다. 이 방식은 CI에서 잘 작동하지 않는데, 파일이 매번 CI 실행 시 다시 다운로드되기 때문이다. 이 문제를 해결하려면 파일 내용의 해시를 기반으로 동작하는compiler_check content
옵션을 사용해야 한다.
분산 캐시
로컬 캐시와 마찬가지로, 네이티브 빌드에 분산 캐시를 사용하는 것을 고려할 수 있다. 특히 빈번하게 네이티브 빌드를 수행하는 대규모 조직에서 유용할 수 있다.
이를 위해 sccache를 사용할 것을 권장한다. sccache의 분산 컴파일 빠른 시작 가이드를 참고해 이 도구를 설정하고 사용하는 방법을 확인할 수 있다.