ReactNative 빌드 살펴보기

js bundle 파일을 중심으로 훑어봅니다

Reactnativehermesbundle
62025-02-05

ReactNative의 빌드는 JS코드, android, iOS 각각의 플랫폼에서 유기적으로 빌드를 해야한다. 빌드 주체가 3배가 되니 에러가 9배는 더 많이 생기는것 같다.

ReactNative는 React를 사용한다면 쉽게 진입할 수 있다. 나 또한 그런 케이스였다. React 원툴 신입개발자로 입사했는데 ReactNative 앱 개발 업무를 하게되었다. 피쳐 개발은 React랑 별 차이가 없었는데 빌드, 배포 할 때는 머리가 많이 빠졌다.

ReactNative 개발을 하면서 전체 시간의 95%는 JavaScript단을 개발하는데 쓰이지만 스트레스의 90%는 나머지 5%의 네이티브 단에서 받았던것 같다.

이 글에서는 ReactNative의 빌드 과정을 JS번들 파일을 중심으로 살펴보겠다.

번들링

시작은 번들링이다. ReactNative로 개발하면서 수 많은 JS, JSX, 이미지, 아이콘 등의 파일들을 추가하는데 이 JS파일들과 Assets들을 하나로 번들링을 해준다. 웹 개발에서는 WebPack, Vite 같은 툴들을 사용하지만 ReactNative는 Metro, ESBuild가 널리 쓰인다.

make bundle file

babel로 ES6+ 코드를 오래된 버전(보톤 ES5)으로 변환, 압축, 난독화 한다. 그러면 이렇게 흉측한 bundle 파일이 생성된다.

bundle file sample

런타임

JIT 컴파일러

보통 웹개발에서는 JS로 번들파일을 생성하면 이걸 서버에 올리고 브라우저가 받아서 실행한다. 크롬 브라우저의 V8 엔진은 아래와 같이 동작한다.

v8 engine

JavaScript는 interpreter 언어이지만 V8 엔진을 돌리면서 부분 최적화를 실행한다. interpreter 실행중인 프로그램을 실시간으로 최적화 컴파일을 한다는데 그래서 크롬이 메모리를 그렇게 많이 먹나 싶다. 이렇게 브라우저에서 부분 컴파일을 하는것도 컴파일이라고 JIT(Just In Time) Compiler 라고 한다.

번외로 이런 과정을 제트엔진에 빗대어서 네이밍 한것은 멋지다고 생각한다.

React Native 에서도 디버깅 환경에서 크롬 브라우저를 사용하는데 그럴때도 이 V8 엔진을 사용한다.

AOT 컴파일러

hermes engine

ReactNative는 모바일 환경에서 Hermes 라는 JS엔진을 사용한다. JS bundle을 빌드 시점에서 bytecode로 컴파일 한다. 이전에는 JSC(JavaScriptCore) 라는 사파리 엔진을 사용했는데 이제는 hermes가 국룰이다. 미리 컴파일 하는 방식을 AOT(Ahead of Time) Compiler라고 한다.

찾아보기 전까지는 미리 컴파일한 AOT가 JIT보다 성능이 좋을것 이라고 생각했었는데 JIT가 동적으로 최적화를 하기 때문에 성능면에서 좋다고 한다. 하지만 동적으로 최적화 작업을 하기 때문에 메모리 사용량이 더 많다. 즉 성능과 메모리는 트레이드 오프 관계다.

javascript runtime

위에서 만든 bundle 파일을 .apk, .ipa 파일로 패키징 해서 우리의 핸드폰에 앱을 설치할 수 있다. 그럼 이 JS 번들 파일은 JavaScript이므로 JavaScript Runtime에서 실행된다. 그런데 우리는 React Native에서 View, Text와 같은 React Native의 태그를 사용했다. 이것들은 React에도 존재하지 않고 swift나 kotlin으로 개발 할 때는 존재하지 않는 태그들이다. 카메라, GPS, 전화걸기 등의 기능도 물론 네이티브 기능이지만 화면을 렌더링 하는것 조차 네이티브의 기능을 사용한다. View는 ios는 UIView로, android에서는 ViewGroup 등으로 대체된다.

코드 실행 흐름

디버그 환경

debug workflow

디버그 환경에서 전체 flow다. 디버그 환경에서 실행될 때는 번들파일을 패키징 하지 않고 Metro가 로컬서버에 올려두고 사용한다.

개발중 새로고침 하면 앱에 실시간으로 적용되는 HMR(Hot Module Replacement)이 가능한 이유이다.

릴리즈 환경

release workflow

Release 환경에서의 flow다.

릴리즈 환경에서는 번들 파일을 앱에 패키징 한다. 하지만 디버그 환경에서와 보았듯이 다른 위치에 있는 번들파일을 실행 할 수 있기 때문에 코드푸시가 가능하다.