Expo

5년 전에 RN 개발자에게 실망감을 주었던 Expo가 달라졌어요?

Expo는 프레임워크가 되었다. 파일 기반 라우팅, 네이티브 표준 라이브러리 등을 제공하는 정도로 발전했다. (5년 전에는 둘 다 불가능 했다.) 거기다 EAS(Epo Application Services)를 통해 Expo를 이용하는 개발자에게 빌드 부터 배포에 들였던 시간을 줄여준다.

Expo Tutorial

프로젝트 생성 명령어

npx create-expo-app@latest

보일러 플레이트 코드 제거하는 명령어 ( DX 좋고요! )

npm run reset-project

reset-project 까보자~ DX를 위하여~

코드를 보면 생각보다 간단하다.

app-example 폴더를 만들고 기존 예제 코드를 옮기고 app 폴더를 만들고 꼭 필요한 파일만 생성하면 끝!

이런 스크립트가 “어떤 폴더 지우고 어떤 파일을 복사-붙여넣기” 하세요 같은 문서 보다 백만배 더 효과적이다.

expo router

expo router는 파일 기반 라우팅을 제공하는 프레임워크이다. ( 요즘에는 ChatGPT로 질문하면, 프레임워크와 라이브러리의 차이를 너무나도 쉽게 할 수 있어서 세상 참 좋아졌다. )

프레임워크이므로 몇가지 사용 규칙을 살펴보자.

  • app 폴더: 라우터와 레이아웃만 포함하는 폴더, 이 폴더에 포함된 파일은 앱에서 화면이고 웹에서는 페이지가가 된다.
  • app/_layout.tsx 파일: 일관성 유지를 위한 해더, 탭 바 같은 공유 UI 요소를 정의하는 곳
  • 파일 이름 컨벤션
    • index 파일은 부모 폴더의 이름과 일치하는 경로를 가지므로 경로 세그먼트 추가 필요 없음
    • app/index.tsx 파일은 / 라우트와 매칭 된다.
  • 라우트 파일은 default 값으로써 React 컴포넌트로 export 된다.
    • default로 export 되지 않은 값 expo-router에 의해 렌더링 되지 않는다.
  • ios, android, web을 네비게이션 탐색 구조를 공유한다.

react-navigation 으로 부터 탈출!

“(tabs)” 폴더

(tabs) 이름을 가진 폴더는 탭 네비게이션을 정의하는 곳이다. ( 잘 쓰이지 않겠지만 이중삼중으로 tabs 내비게이션을 구성할 수 있다. ) _layout.tsx 파일에서 탭 네비게이션을 정의하면 된다.

expo router ?!

expo router에 어떤 발전이 있었는 지 보자.

  • 웹에서 가장 뛰어난 파일 시스템 라우팅 개념을 접목하였다고 한다. ( 아주 자화자찬이 …)
  • 지연 평가를 통하여 최적화도 되어있다고 한다.
  • 웹 SEO를 위하여 빌드 타임에 정적 렌더링을 지원한다.

그리고 몇가지 특이사항도 보고 넘어가자.

  • React Navigation과 같이 사용할 수 있지만… 당연히 새앱에서는 Expo Router만 사용하기를 권장한다.
  • Wix의 React Native Navigation을 Expo Go에서 호환이 안되어서 사용하지 못 한다.
  • 서버 측 렌더링은 기본적으로 지원하지 않아서 추가 설정을 해야한다. ( 소스코드를 살펴보니, metro를 이용하여 SSR을 지원하려는 흔적이 보인다. )
  • 웹 번들러로 Metro web을 사용한다.

expo router의 파일 기반 네비게이션 시스템은 어떻게 만들어져있을까?

까보고 싶어서 양이 엄청나게 많다… 단순히 하나의 라이브러리로 만들기에는 규모가 크다. 그래서인지 여러 패키지를 의존하고 있다.

expo-router를 설치할 때 같이 설치하는 의존성 패키지들

react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar

package를 까보자… expo-router의 package.json을 살펴보니, @react-navigation에 의존하고 있는 것으로 확인되었다. 그럼… expo-router의 핵심 부분은 파일 기반 라우터를 처리하는 코드로 구성되어 있을 것으로 추측된다.

코드 파일을 읽고 가공하는 일은 주로 babel로 처리하니 expo-router-plugins.ts를 살펴보자. 코드만 보아서는 이해가 되지 않아서, 다른 파일을 찾아보자.

결국은 react-navigation으로 구성되어 있으니, react-navigation을 사용할 때 처럼 App을 등록하는 부분이 있을 거 같아 찾아보니 이 파일을 찾았다.

Head.Provider는 무시해도 될 거 같아보이고, ExpoRoot를 살펴보니 ctx가 어떻게 만들어지는 지만 알면, 파일 기반 네비게이션을 위한 라우터 정보를 어떻게 만드는 지 알 수 있을 것으로 추측된다. ctx에 담겨오는 children가 어떻게 만들어지는만 보면 될것으로 추측됨!

_ctx.js

require.context는 webpack 컴파일러가 지원하는 특수 기능으로, 특정 기본 디렉토리에서 일치하는 모든 모듈을 가져올 수 있습니다. 그런데… webpack은 웹에서만 사용될 터인데… expo의 모바일 번들링 당시에는 메트로를 사용하는 것일텐데, 무언가 잘못 추측하고 있는 거 같다. 음… 중간 과정을 놓친 거 같지만 ctx를 통해서 app 폴더의 트리 구조 정보를 받아올 것으로 추측된다.

expo의 라우터를 정의하는 파일을 찾았으니, 이 파일을 기반으로 역으로 추적해보자. 문맥을 잃어버림 … ( Expo Router 개발자들은 DX를 위아혀 얼마나 딥다이브 하고 있는 것인지… 이걸 개발하였던 배경지식이 있는 사람만 제대로 이해 할 수 있는 수준처럼 느껴진다. )

도움을 받을 수 있을 지 모르지만 Help!을 요청해보자.

아쉽지만 튜토리얼의 다음 단계로 넘어가자.