RSS

빌드 우회 셋 정리: 어디까지가 내가 고칠 수 있는 문제인가

앱 하나를 두 스토어에 올리는 동안 빌드가 여러 번 깨졌고, 그때마다 우회를 하나씩 넣었습니다. 다 끝나고 저장소를 보니 임시방편이 셋 쌓여 있었습니다.

그 자리에서는 각각 옳은 판단이었습니다. 문제는 남겨 두면 몇 달 뒤에 "이게 왜 여기 있지"가 된다는 것입니다. 그래서 하나씩 뿌리를 파봤는데, 셋 중 제가 고칠 수 있는 건 하나뿐이었습니다.

쌓인 것 셋

  1. patch-package 로 Expo 내부 Swift 코드 15군데를 옛 문법으로 되돌리기
  2. 빌드 설정에 EXPO_USE_PRECOMPILED_MODULES=0 넣기
  3. overrides@react-native/* 네 개를 특정 버전에 묶기

첫째는 제 컴퓨터만의 문제였습니다

Expo SDK 56 의 내부 모듈이 weak let 이라는 문법을 씁니다. Swift 6.3 에서 들어온 것인데, 제 맥의 Xcode 는 26.1.1 이고 거기 딸린 Swift 는 6.2.1 이라 그 문법 자체가 없습니다. 그래서 로컬 빌드가 열다섯 개 에러로 깨졌습니다.

그런데 EAS 빌드 로그를 다시 읽다가 이 줄을 봤습니다.

sdk | iPhoneOS26.4.sdk

빌드 서버는 처음부터 문제가 없었습니다. 저보다 새 Xcode 를 쓰고 있었으니까요.

즉 이 패치는 서버에서는 아무 쓸모가 없는데 제 컴퓨터가 낡아서 저장소에 들어간 코드입니다. 저장소는 팀이 공유하는 자리인데 거기에 개인 환경 사정이 커밋된 셈입니다.

근본 해결은 명확합니다. Xcode 를 올리고 패치를 지우면 됩니다.

둘째는 남의 문제였습니다

EAS 는 빌드를 빨리 하려고 일부 패키지를 소스에서 컴파일하지 않고 미리 만들어 둔 바이너리로 내려받습니다. 그런데 바이너리만 받으면 헤더 파일이 공개 경로에 깔리지 않습니다. 바이너리를 쓰는 쪽은 헤더가 필요 없으니 당연한 설계입니다.

문제는 그 패키지의 헤더를 다른 패키지가 참조하고 있었다는 것입니다. 한쪽은 바이너리로 오고 한쪽은 소스로 빌드되니 그 사이 연결이 끊어집니다.

이건 제가 고칠 수 있는 게 아닙니다. 미리컴파일을 끄는 것 말고는 방법이 없고, 대가는 빌드 시간입니다. 전부 소스에서 컴파일하게 되니까요.

셋째는 우회라기보다 위생이었습니다

한 패키지가 다른 패키지를 * 로 요구하고 있었습니다. 아무 버전이나 좋다는 뜻이라 최신이 끌려왔고, 그게 다른 곳에서 요구하는 버전과 충돌했습니다.

버전을 고정하는 건 사실 우회라기보다 정상적인 의존성 관리에 가깝습니다. 그대로 둬도 손해가 없어서, 셋 중 유일하게 걷어낼 이유가 없는 항목이었습니다.

둘째와 셋째의 뿌리가 같았습니다

여기서 한 가지 희망을 봤습니다. 두 문제 모두 특정 애니메이션 라이브러리와 그 짝이 의존성 트리에 있다는 데서 나옵니다. 그런데 저희 앱에는 애니메이션이 없습니다. 지도에 선을 긋고 점을 찍는 게 전부입니다.

그래서 빼면 둘이 한 번에 사라지지 않을까 싶어 확인해봤습니다. 라우터 패키지의 정의를 열어 보니 이렇게 돼 있었습니다.

"peerDependencies": { "react-native-reanimated": "*" },
"peerDependenciesMeta": { "react-native-reanimated": { "optional": true } }

선택 사항입니다. 안 써도 된다는 뜻이라 잠깐 기뻤습니다.

그런데 같은 라우터가 서랍 메뉴 패키지를 진짜 의존성으로 끌어오고, 그 패키지가 애니메이션 라이브러리를 요구합니다. 저희는 서랍 메뉴를 한 번도 쓰지 않는데도 딸려옵니다.

라우터를 쓰는 한 뺄 수 없다는 결론이었습니다.

정리하면

우회 누구 문제인가 언제 걷어낼 수 있나
Swift 패치 내 개발 환경 Xcode 올리면 즉시
미리컴파일 끄기 업스트림 고쳐질 때까지 유지
버전 고정 업스트림의 느슨한 범위 걷어낼 이유 없음

이 표를 만들고 나서야 마음이 편해졌습니다. 셋을 뭉뚱그려 "임시방편이 쌓였다"고 볼 때는 다 빚처럼 느껴졌는데, 나눠 놓으니 갚아야 할 건 하나뿐이었습니다.

우회를 남길 때 같이 적어야 하는 것

전에는 우회를 넣을 때 왜 넣었는지만 적었습니다. 이번에 배운 건 그것보다 언제 빼도 되는지가 더 중요하다는 것입니다.

그래서 프로젝트 문서에 이렇게 적어 뒀습니다.

Xcode 를 26.2 이상으로 올리면 이 패치를 지워야 한다. 업스트림이 의도한 코드가 그쪽이다.

이유만 적혀 있으면 나중에 읽는 사람은 "그렇구나" 하고 그대로 둡니다. 조건이 적혀 있으면 그 조건이 충족됐는지 확인하게 됩니다.

오늘 못 한 것

셋 중 유일하게 제가 고칠 수 있는 것을 하려고 Xcode 를 올리러 갔는데, 그러려면 운영체제부터 올려야 했습니다. 몇십 기가를 받아야 하는 일이라 저녁으로 미뤘습니다.

하필 유일하게 손댈 수 있는 항목이 제일 오래 걸리는 일이었습니다. 나머지 둘은 고치고 싶어도 못 고치고, 고칠 수 있는 하나는 시간이 없어서 못 고치는 상태로 오늘이 끝났습니다.