Tuist 모듈화에 빠져보기

2026. 1. 24. 17:01·iOS

👋 Tuist 많이 사용한 개발자 알려주는 팁

안녕하세요! iOS 운영진 서원지입니다 ㅋㅋㅋ

이 글을 쓰게 된 계기는... 요즘 주니어 개발자분들이 Tuist를 하도 많이 써서요..

저도 그렇고. 거의 모든 프로젝트에서 Tuist를 써봤다 보니 경험 공유해 드리면 좋을 것 같더라고요!

제가 경험한 내용 위주로 작성했습니다. 더 좋은 방법 있으면 편하게 알려주세요 🙏


Tuist가 뭐길래 이렇게 난리야?

솔직히 처음 Tuist 접했을 때는 "이게 뭐가 좋은데?" 싶었어요 ㅋㅋ

README 보면 이렇게 쓰여있거든요:

"Xcode Project를 생성하거나 유지보수하거나 상호작용하는 Command Line Tool"

아 네... 뭔 소리인지 1도 모르겠더라고요 😅

대충 분석해 보니까

  • Xcode 프로젝트 파일을 코드로 관리하는 거더라고요
  • GUI에서 클릭클릭 하던 걸 Swift 코드로 작성
  • 팀 작업할 때 프로젝트 설정 충돌 안남
  • 모듈화 할 때 진짜 편함

"아~ 이거구나!" 싶어서 바로 도입해 봤는데... 진짜 편하더라고요!


설치부터 해보자 (삽질 경험담 포함)

mise로 설치하기

# 요즘 mise 쓰는 게 트렌드래요
mise install tuist
# 이것만 하면 안되고... (저도 여기서 삽질함 ㅠ)
mise use -g tuist
# 이제야 됩니다!
tuist --version

💡 삽질 포인트: mise install 만 하고 mise use -g 안 하면 command not found 나와요. 저도 여기서 30분 헤맸음 😡

첫 프로젝트 만들기

# 프로젝트 초기화 (여기서 Project.swift 파일 생성됨)
tuist init

# 실제 Xcode 프로젝트 생성 (여기가 핵심!)
tuist generate

# 빌드도 터미널에서 가능
tuist build

# 설정 파일들만 따로 편집
tuist edit

매번 tuist generate 하는 게 좀 귀찮긴 한데... 익숙해지면 괜찮아요!
(나중에는 자동화 만들었어욬ㅋㅋㅋ)


의존성 관리가 진짜 핵심이에요

여기가 진짜 중요한 부분이에요. 저도 처음엔 이해 안 됐는데 몇 번 써보니까 이해되더라고요.

Package.swift에서 모든 걸 관리

Plugin/DependencyPackagePlugin/Package.swift 파일에서 모든 외부 라이브러리를 선언합니다.

@preconcurrency import PackageDescription

#if TUIST
@preconcurrency import ProjectDescription

// 이 부분이 진짜 중요! Firebase 때문에 추가함
let packageSettings = PackageSettings(
  productTypes: [
    "FirebaseCore": .staticLibrary,
    "FirebaseAuth": .staticLibrary,
    "FirebaseFirestore": .staticLibrary,
    "FirebaseAnalytics": .staticLibrary,
    "FirebaseCrashlytics": .staticLibrary,
    "FirebaseRemoteConfig": .staticLibrary
  ]
)
#endif

let package = Package(
  name: "MyAwesomeProject", // 여기는 본인 프로젝트명으로!
  dependencies: [
    // Firebase (필수템)
    .package(url: "<https://github.com/firebase/firebase-ios-sdk>", from: "10.27.0"),

    // TCA (요즘 핫한 아키텍처)
    .package(url: "<https://github.com/pointfreeco/swift-composable-architecture>", exact: "1.18.0"),

    // Swift Concurrency 관련 유틸들
    .package(url: "<https://github.com/pointfreeco/swift-concurrency-extras.git>", from: "1.1.0"),

    // TCA 화면전환 관리
    .package(url: "<https://github.com/johnpatrickmorgan/TCACoordinators.git>", exact: "0.11.1"),

    // 네트워킹 (직접 만든 거 써봤어요)
    .package(url: "<https://github.com/Roy-wonji/AsyncMoya>", from: "1.1.0"),
    .package(url: "<https://github.com/Roy-wonji/WeaveDi.git>", from: "3.4.0")
  ]
)

Firebase 삽질담

Firebase 쓰시는 분들 주목! 저도 여기서 진짜 많이 삽질했어요...

왜 static library로?

Firebase 그냥 쓰면 링크 에러 나거든요. 특히 모듈화 할 때 진짜 골치아픔.

let packageSettings = PackageSettings(
  productTypes: [
    "FirebaseCore": .staticLibrary,        // 이렇게 static으로!
    "FirebaseAuth": .staticLibrary,        // 안그러면 링크 에러남
    "FirebaseFirestore": .staticLibrary,   // 진짜임...
    // ... 쓰는 Firebase 모듈 다 static으로
  ]
)

💡 꿀팁: #if TUIST 써서 Tuist에서만 이 설정이 적용되게 했어요. 일반 SPM에서는 무시됨!


enum으로 깔끔하게 정리하는 법

매번 TargetDependency.external(name: "긴 이름의 라이브러리") 이렇게 쓰기 싫잖아요? ㅋㅋㅋ

Plugin/DependencyPackagePlugin/ProjectDescriptionHelpers/Extension+TargetDependencySPM.swift 파일 만들어서:

import ProjectDescription

public extension TargetDependency {
  enum SPM {} // SPM용 네임스페이스
}

public extension TargetDependency.SPM {
  // 이렇게 하면 오타도 안나고 자동완성도 됨!
  static let asyncMoya = TargetDependency.external(name: "AsyncMoya", condition: .none)
  static let weaveDi = TargetDependency.external(name: "WeaveDi", condition: .none)
  static let composableArchitecture = TargetDependency.external(name: "ComposableArchitecture", condition: .none)
  static let tcaCoordinator = TargetDependency.external(name: "TCACoordinators", condition: .none)
  static let concurrencyExtras = TargetDependency.external(name: "ConcurrencyExtras", condition: .none)
}

이제 각 모듈에서 이렇게 쓸 수 있어요:

dependencies: [
  .SPM.composableArchitecture,  // 깔끔!
  .SPM.weaveDi,                // 오타 걱정 없음!
  .SPM.asyncMoya              // 자동완성 됨!
]

진짜 편해요! 😍


제가 주로 쓰는 라이브러리들

라이브러리 용도 개인적 평가
ComposableArchitecture TCA 아키텍처 ⭐⭐⭐⭐⭐ (강추!)
ConcurrencyExtras Swift Concurrency 확장 ⭐⭐⭐⭐ (LockIsolated 짱)
Collections 고성능 컬렉션 ⭐⭐⭐⭐ (Deque 좋음)
TCACoordinators 화면전환 관리 ⭐⭐⭐⭐ (TCA 쓰면 필수)
AsyncMoya 네트워킹 ⭐⭐⭐ (직접 만든 거라..)
WeaveDi DI ⭐⭐⭐ (심플함)

진짜 솔직한 후기

좋은 점들:

  • 한 곳에서 모든 의존성 관리: 진짜 깔끔함
  • 프로젝트 설정 버전관리: Git으로 관리되니까 좋음
  • 팀 작업 시 충돌 없음: Xcode 파일 merge 지옥에서 해방!
  • 빌드 최적화: 모듈별로 빌드해서 빠름

아쉬운 점들:

  • 초기 세팅 복잡: 처음 할 때 좀 헤맸어요
  • 러닝커브: Swift 코드로 프로젝트 설정하는 게 처음엔 어색함
  • 업데이트: 너무 자주 됨

꿀팁들

1. 점진적으로 도입하세요

기존 프로젝트에 갑자기 도입하면 멘탈 터져요. 새 모듈부터 시작하시길!

2. 템플릿 만들어두세요

비슷한 모듈 구조 계속 만들 거면 템플릿 만들어두면 편해요.

3. 캐시 활용하세요

빌드 빨라지려면 캐시 필수예요. Tuist Cloud도 있던데... 아직 안 써봄 ㅋㅋ


마무리

Tuist 진짜 좋은데 처음엔 좀 어려워요. 하지만 한번 익숙해지면 다른 걸로 못 갑니다!

특히 팀 프로젝트할 때 프로젝트 파일 충돌 나는 거 진짜 스트레스였는데, Tuist 쓰고 나서 그런 걱정 없어졌어요.

아직 안 써보신 분들은 토이프로젝트부터 시작해 보세요! 금방 매력에 빠질 거예요 ㅋㅋㅋ

다음 글 예고: Plugin 만들기, 고급 설정들 다뤄볼 예정입니다!


작성자: iOS 운영진 서원지

GitHub: https://github.com/Roy-wonji

'iOS' 카테고리의 다른 글

Tuist Plugin 만들기 + Settings 설정까지 완전 정복!  (0) 2026.04.05
[iOS] Tuist를 쓰면서 Asset 코드 생성은 직접 만들기로 한 이유  (0) 2026.03.28
Tuist 모듈 자동화 CLI 자동화 만들기  (0) 2026.02.25
[iOS] 당연하게 쓰던 메서드에게 뒤통수 맞아보기  (0) 2026.01.06
'iOS' 카테고리의 다른 글
  • Tuist Plugin 만들기 + Settings 설정까지 완전 정복!
  • [iOS] Tuist를 쓰면서 Asset 코드 생성은 직접 만들기로 한 이유
  • Tuist 모듈 자동화 CLI 자동화 만들기
  • [iOS] 당연하게 쓰던 메서드에게 뒤통수 맞아보기
dynamic-ddd
dynamic-ddd
역할의 경계를 넘어 유저에게 도달하는 프로덕트를 완성해온 메이커들의 커뮤니티입니다.
  • 인기 글

  • dynamic-ddd
    dynamic-ddd 님의 블로그
    dynamic-ddd
  • 전체
    오늘
    어제
    • 분류 전체보기 (9)
      • iOS (5)
      • Android (2)
      • Design (2)
  • 공지사항

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
dynamic-ddd
Tuist 모듈화에 빠져보기
상단으로

티스토리툴바