React Native 의 환경 (1. JS 엔진과 번들러)

eeensu·2026년 2월 8일

React Native

목록 보기
1/41

JS 엔진

웹 개발자에게 익숙한 V8(크롬 엔진)은 PC 환경에 최적화되어 있다. 반면, 모바일은 배터리, CPU, 메모리가 훨씬 열악하다. 이 문제를 해결하기 위해 Facebook(Meta)이 직접 만든 엔진이 Hermes이다.

1. JIT vs AOT (가장 결정적인 차이)

이 개념이 성능의 핵심이다.

  • Web (V8 엔진 - JIT 컴파일)

    • 브라우저가 자바스크립트 소스 코드(텍스트)를 다운로드한다.
    • 애플리케이션이 켜는 순간에 이 텍스트를 읽고(Parsing), 기계어로 번역(Compile)한다.
    • 문제점 : 번역하는 동안 CPU가 치솟고, 사용자는 그동안 '흰 화면'이나 '멈춘 화면'을 보게 된다. (초기 로딩 속도 저하).
  • RN (Hermes 엔진 - AOT 컴파일):

    • 개발자가 빌드(Build)하는 시점에 내 컴퓨터가 JS 코드를 미리 기계가 읽기 쉬운 '바이트코드(Bytecode)'로 다 번역해버린다.
    • 앱(폰)에는 이 번역된 결과물만 들어간다.
    • 장점 : 폰은 번역할 필요 없이 그냥 읽기만 하면 된다. 그래서 앱이 켜지는 속도가 압도적으로 빠르다.

2. 모바일 맞춤형 메모리 관리

웹 브라우저는 메모리가 넉넉한 PC를 가정하고 메모리 청소(GC)를 한다. 하지만 Hermes는 모바일을 위해 설계되었다.

  • 작은 힙(Heap) 메모리 : 모바일은 램(RAM)이 부족하므로, Hermes는 메모리를 아주 적게 차지하도록 설계되었다.
  • On-Demand : 필요한 만큼만 메모리를 쓴다. V8처럼 미리 거대한 메모리 공간을 확보하지 않는다. 덕분에 저사양 안드로이드 폰에서도 앱이 잘 죽지 않는다.

3. 개발자가 겪게 될 실무 차이

V8은 코드가 좀 엉성해도 실행 시점에 JIT가 알아서 최적화해주거나 봐주는 경우가 있다. 하지만 Hermes는 미리 컴파일을 해야 하므로 문법적 오류나 표준에 맞지 않는 코드에 더 민감할 수 있다.

  • eval() 사용 불가 : 문자열을 코드로 실행하는 eval() 함수는 보안상, 성능상 Hermes에선 막혀있다. AOT 컴파일 모델에서 런타임에 임의 코드를 생성/실행하는 eval()이 구조적으로 맞지 않기 때문이다.

  • 디버깅 : 크롬 개발자 도구를 띄우면 예전엔 변수명이 이상하게(최적화된 이름으로) 보였다. 하지만 최신 Hermes는 'Source Map' 기술이 좋아져서, 원본 코드를 보며 디버깅하는 데 문제가 없다.




번들러

웹의 Webpack/Vite와 역할은 같지만, 네이티브 앱의 특성을 처리하기 위해 훨씬 더 복잡한 일을 한다.

1. 파일을 하나로 합치기

웹은 JS 파일을 여러 개로 쪼개서(Code Splitting) 필요할 때 로딩하는 게 좋은 최적화 방법이다. 하지만 RN은 기본적으로 하나의 거대한 JS 파일(index.bundle)을 만든다.

  • 이유 : 모바일 파일 시스템에서 수천 개의 작은 파일을 읽는 것보다, 큰 파일 하나를 읽는 게 훨씬 빠르기 때문이다.

  • Metro의 역할 : 프로젝트 내의 모든 JS 파일(node_modules 포함)을 긁어모아서, 순서를 정렬하고 하나의 파일로 직렬화(Serialization)한다.


2. 플랫폼별 확장자 자동 처리

이게 웹팩보다 Metro가 강력한 점이자, RN 개발의 핵심 패턴이다. 만약 Button.js라는 컴포넌트를 만들었는데, iOS와 안드로이드 디자인이 완전히 달라야 한다면?

  • Web: 코드 안에서 if (isIOS) ... else ... 분기 처리를 해야 한다. 코드가 지저분해진다.
  • RN (Metro): 파일 이름을 다르게 만든다.
    • Button.ios.js
    • Button.android.js
import Button from './Button'; (확장자 없이 import)

빌드할 때, iOS 빌드면 .ios.js를 가져오고, 안드로이드면 .android.js를 자동으로 가져간다. 덕분에 코드가 아주 깔끔해진다.


3. 의존성 그래프 (Dependency Graph)와 캐시

Metro는 npm start를 하자마자 프로젝트의 모든 파일 관계도(그래프)를 그린다. A 파일이 B를 import하고, B는 C를 import하고... 이 지도를 메모리에 갖고 있다.

  • 델타 번들링 : 소스 코드 한 줄을 고치면, 전체를 다시 묶는 게 아니라 변경된 부분(Delta)만 계산해서 앱으로 쏴준다. 그래서 수정 사항이 0.1초 만에 폰에 반영된다.

  • 캐시 이슈의 원인 : 이 '그래프'를 빠르게 하려고 캐싱을 엄청나게 한다. 그런데 가끔 꼬이면(예: 라이브러리 버전 업 후), Metro는 옛날 그래프를 보고 있어서 에러가 난다. 그래서 RN 개발자들은 "뭔가 이상하면 캐시 리셋(npm start -- --reset-cache)"이 습관을 들이면 좋다. 어쩔 수 없는 숙명이다...

profile
안녕하세요! 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글