안녕하세요. 최고의 사용자 경험을 프론트엔드 개발로 끌어 내고 싶은 학생입니다.
프론트엔드 개발을 시작했을 때부터 지금까지 계속 웹 개발 공부에 집중을 하고 있었는데, 이번 방학 때 모바일뷰의 웹 프로젝트를 개발하면서" 이 서비스를 처음부터 앱으로 개발했으면 좋았겠다"라는 생각이 들었습니다.
웹 사이트에 적합한 프로젝트가 있고, 웹이 필요없고 모바일 앱에 대해서만 적합한 프로젝트가 있는데 이를 자유자재로 개발할 수 있는 프론트엔드 개발자가 되고 싶은 마음이 이번 방학에 강하게 들었습니다. 그래서 이에 대해서 알아보던 중 크로스 플랫폼 앱 개발이 가장 나에게 적합하다는 것을 알게 되었습니다. 본인처럼 크로스플랫폼 앱 개발은 하고 싶은데 무엇을 선택해야 할지 모르는 분들이 많을 거라 생각이 듭니다. 그래서 제가 react native를 선택한 이유에 대해서 정리하고 보다 더 선택의 도움이 되었으면 좋겠습니다~!
플러터(Flutter)말고 리액트 네이티브(react native)를 선택한 이유
1. 리액트 네이티브의 결과물
제가 UX 프론트엔드 개발에 관심이 많은만큼 좋아하는 플랫폼이 있는데, 대표적인 서비스 하나가 '토스(Toss)' 입니다. 토스 어플 또한 리액트 네이티브로 만들어졌고, 토스 앱과 같은 결과물이 크로스플랫폼 프레임워크를 통해 만들어졌다는 것이 엄청난 호감으로 다가왔습니다. 본인이 추구하는 프론트엔드 개발 우상이 토스(Toss)앱 이였는데, 이를 리액트 네이티브로 충분히 제작이 가능하다는 것이 리액트 네이티브(react native)를 선택한 가장 큰 이유 중 하나 였습니다.
토스 앱 오픈시간 1초를 줄이기까지
토스 앱을 켜는 시간 1초를 줄이기까지의 과정과 시행착오를 소개합니다.
toss.im
왜 토스가 리액트 네이티브를 선택했는지에 대한 이유를 알려주는 기술 블로그 글입니다. 한번 들어가서 읽어보세요 :) 이 외에도 메타, 마이크로소프트, 쇼피파이, 넷플릭스, 소니 등의 큰 기업에서도 이 기술을 사용중이라고 알고 있습니다.
2. JavaScript, TypeScript, JSX사용
React 기반 웹 프로젝트만 4개를 진행한 결과로 얻은 지식과 경험을 크로스 플랫폼 앱 개발에 대해서 똑같이 적용할 수 있다는 것이 큰 매력이였습니다. 물론 조금씩은 다르겠지만, Flutter와 같이 Dart 언어를 새로 학습하고 적용하면서 트러블슈팅에 대한 노력의 시간들을 절약할 수 있다는 것 또한 React Native를 선택한 이유 중 하나입니다.
자바스크립트의 장점
React Native에서는 기본적으로 파일 시스템에서 JavaScript를 읽어 오기 때문에 웹과 달리 네트워크로 인한 로딩을 없앨 수 있습니다. 그래서 속도도 상당히 빠르게 개발할 수 있습니다. 특히 Hermes라는 javaScript의 엔진이 React Native의 성능을 개선되도록 설계되었다고 합니다. 이는 모바일 기기의 작은 RAM 용량과 느린 플래시의 한계로 고안된 아키텍처입니다.
Hermes의 주요 성능
1. 바이트 코드 사전 컴파일
일반적으로 자바스크립트 엔진은 자바스크립트 코드 소스가 로드되고 이를 파싱해서 바이트 코드를 생성합니다. 이 단계를 실행시간을 지연시킵니다. 하지만 Hermes는 모바일 앱 빌드 프로세스의 일부로 실행되는 사전 컴파일러를 사용합니다. 이를 통해서 초기 로딩속도를 줄일 수 있습니다.
자료출처
Hermes: An open source JavaScript engine optimized for mobile apps, starting with React Native
Mobile applications are growing larger and more complex. Larger apps using JavaScript frameworks often experience performance issues as developers add features and complexity. These issues are gene…
engineering.fb.com
3. 토스의 ESBuild 적용 사례
토스의 SLASH 23에서 React Native의 번들러를 Metro에서 esbuild로 교체하여 빌드 속도를 2분에서 10초로 줄였다는 결과물을 보고 기존 빌드속도때문에 크로스플랫폼 선택의 고민이 사라졌습니다.
기존 React Native 개발 환경은 페이스북에서 개발한 번들러 'Metro'를 사용하고 있습니다. metro는 webpack처럼 모든 자바스크립트 파일을 하나로 모아 제공하는 번들러입니다. 이는 개발 환경에 적합하지만, 성능이 매우 느리고, 컴퓨터 환경에 따라 빌드오류가 나타나는 현상이 있습니다.
이 문제점을 보완하기 위해서 토스에서는 React Native 소스코드를 분석해 esbuild로 번들러를 교체했습니다. 이로 인해 빠른 성능과 일관적인 빌드 결과물을 보장합니다. 이에 대해서 간단하게 왜 metro가 빌드속도가 느리고 일관된 개발환경을 제공하지 못했는지에 대한 이유를 정리해보았습니다.
metro
Metro 번들러는 다음과 같은 3가지 과정으로 동작합니다.
여기서 Transformation 과정때문에 빌드속도가 느린 원인이였습니다.
모든 모듈은 Transformation 과정을 거치며 작동합니다. 이 과정은 babel을 이용해서 React Native가 이해할 수 있는 형식으로 변환하는 과정인데, 이는 CPU 코어 수에 따라 병렬 처리 됩니다. 여기서 babel이 가진 문제점은 플러그인들에 의해 빌드 속도가 느려질 수 있다는 것입니다.
babel은 transformation 연산을 모든 코드에 대해서 적용합니다. 이는 호환성 측면에서는 좋을 수 있지만, 속도가 느려지는 트레이드 오프 현상이 발생하는 문제점이 있습니다. 이러한 문제점을 React Natvie에 ESBuild를 적용한다면 해결할 수 있습니다. 그 이유는 React의 node module은 이미 commonJS를 지원하기 때문에 굳이 babel을 통해서 작업을 수행할 필요가 없기 때문이죠.
토스 프론트 플랫폼팀에서는 Metro와 ESBuild 모두 번들러로서 기본적으로 세 가지 역할을 하는데 이 각각의 역할에 대한 설정을 동일하게 맞춘다면 ESBuild로 대체할 수 있다고 생각하고 적용했습니다.
Resolution
Metro와 ESBuil가 가장 다른점은 확장자입니다. 웹 개발에서는 '.ts', '.tsx', '.js'처럼 단순한 확장자를 사용하는 반면 React Native에서는 '.ios.js', '.android.js', '.native.js' 와 같은 확장자를 사용합니다.
그래서 ESBuild에서도 이 특별한 확장자들에 대응해야 합니다.
await esbuild.build({
resolveExtenstions: [
'.ios.ts', '.ios.tsx', '.ios.js',
'.native.ts', '.native.tsx', '.native.js',
'.ts', '.tsx', '.js',
],
})
그래서 resolveExtensions' 설정으로 대응하는 방법을 생각합니다. react native에서 사용하는 특별한 확장자를 대응합니다.
Load
React Native에서는 특이한 문법들을 많이 사용합니다. 이런 문법들을 대응하기 위해서는 Load를 하는 방법에 대해서도 정의를 해야 합니다. 모든 파일의 Flow 문법을 포함하는 경우 Babel로 컴파일을 넣어서 Flow문법을 사용할 수 있는 자바스크립트 코드로 바꿔줍니다. 이렇게 리액트 네이티브의 Flow문법과 TypeScript 그리고 worklet 함수에 대응하도록 코드를 작성해 특이한 문법에 대응합니다.
build.onLoad({ filter: /.*/ }, async (args) => {
const { path } = args;
const contents = await fs.promises.readFile(path, 'utf-8');
/** react-native는 JavaScript 대신 flow를 사용함 */
if (hasFlowSyntax(contents)) {
return /** flow 타입 정보를 삭제한 내용 */;
}
/** react-native-reanimated는 babel로 컴파일해야 함 */
if (hasReanimatedSyntax(contents)) {
return /** babel로 컴파일한 내용 */;
}
return /** esbuild 기본 동작 */;
});
Optimization
Metro와 달리 ESBuild는 'Tree Shaking'을 지원하여 사용되지 않는 import들을 자동으로 제거해서 파일크기를 줄일 수 있습니다. Minification(파일 크기 압축) 역시 ESBuild와 Metro 모두 지원합니다.
이로 인해서 ESBuild를 사용하는 것만으로도 JavaScript 파일 크기를 상당히 줄일 수 있었습니다.
이 외에도 Metro가 제공하는 기능들에 대해서도 위처럼 각각을 대응시켜서 React Native에 ESBuild를 사용할 수 있게끔 적용했습니다.
참고자료
React Native, Metro를 넘어서(2) | 요즘IT
‘React Native, Metro를 넘어서’ 1회에서는 번들러가 무엇인지와 번들러의 역할로 Resolution, Load, Optimization에 관해 소개했습니다. 1부 마지막에서 파일 크기를 줄이기 위한 Optimizaton을 간단히 이야기
yozm.wishket.com
결과적으로 Metro 에서 ESBuild 적용을 통해서 일관적인 빌드 결과, 수동으로 '--reset-cache' 옵션을 이용해서 빌드하는 과정 삭제로 인한 개발 경험 향상, 빌드 속도 10분의 1 가량 감축, Tree Shaking으로 인한 파일 크기 감소라는 엄청난 결과를 도출했습니다.
4. 기타
위 큰 세가지 이외에도 React Native를 선택한 이유가 있습니다.
- 활발한 커뮤니티로 인한 지속적인 발전
- Expo 프레임워크
- CodePush : app store 과정을 거치지 않고 바로 업데이트
크로스 플랫폼 선택에는 React Native에 대한 선택의 이유를 작성해보았습니다. 이는 지극히 저의 주관적인 생각이고, 크로스플랫폼 선택에 저와 같이 고민이 있으시는 분들은 조금이나마 도움이 되셨으면 좋겠습니다.