티스토리 뷰

 

프로젝트를 진행하면서 깃헙에서 충돌이 자주 발생했었다. 만약 팀원 A가 파일 추가하고, 팀원 B가 설정을 변경했을 때 둘 다 .xcodeproj 파일에 영향을 주어 충돌이 발생했다.

또한 팀원이 프로젝트 설정을 변경했을 때 .pbxproj 파일은 XML 형식으로 나타나서 PR 리뷰를 하기 어려운 문제가 있었다.

 

추가적으로, 프로젝트에서 CocoaPods로 의존성 관리를 했지만, 팀원이 CocoaPods 사용 중인 것을 깜빡하고 SPM을 사용하면 두 의존성 관리 도구가 충돌해서 오류가 발생하는 상황도 있었다.

 

정리하자면 다음과 같은 문제가 있었다.

  •  xcodeproj 충돌 발생
  • .pbxproj 파일의 코드 확인 어려움
  • spm과 cocoapods 충돌 발생

이 문제들을 해결하기 위한 방법으로 Tuist라는 툴을 알게 되었는데 Tuist가 무엇이고 어떻게 적용하는지 알아보자.

 

📝 목차

1. Tuist란 무엇인가
2. Tuist 설치
3. Tuist 프로젝트에 적용

4. 프레임워크 추가 후 import 해보기
5. 라이브러리 설치 후 적용



1. Tuist란 무엇인가

 

 

What is Tuist? | Tuist

 

docs.tuist.dev

 

Tuist는 Xcode 프로젝트를 관리할 수 있는 툴이다.

기존에 Xcode에서 target, SPM, info, buid-setting 을 관리하던 것을 tuist라는 툴을 활용해서 할 수 있다.

 

🟢 장점

 

1️⃣ 코드로 설정하는 프로젝트 구조

 

Tuist는 Project.swift 파일을 통해 프로젝트의 구조와 모듈을 코드로 정의할 수 있다.

 

2️⃣ 모듈화 편리 및 모듈 간 의존성 관리

 

Tuist는 모듈 간 의존성을 명확하게 관리할 수 있어요. 각 모듈은 다른 모듈에 의존할 수 있으며, 이를 Project.swift에서 코드로 관리한다.
또한, 의존성 관리 도구인 CocoaPods, SPM, Carthage를 사용하되, Tuist의 설정에 맞춰 쉽게 통합할 수 있다.

 

그렇다고 "Tuist = 모듈화"인건 아니다. Tuist는 단지 모듈화를 할 수 있게 도와주는 도구일 뿐이다.

 

3️⃣ 빌드 속도 개선

 

필요하지 않은 모듈을 재빌드하지 않아서 전체 빌드 시간을 단축할 수 있다.

 

4️⃣ 충돌 회피 가능

 

  기존 방식 Tuist 방식
파일 추가/삭제 .xcodeproj 변경 → 충돌 Project.swift만 변경
의존성 관리 SPM/CocoaPods → 설정 꼬임 Tuist/Dependencies.swift로 통합
프로젝트 변경 PR 리뷰 .xcodeproj 비교 어려움 설정 코드만 리뷰 가능

 

Tuist는 프로젝트 설정을 코드로 선언하고, .xcodeproj 파일은 필요할 때 tuist generate로 새로 생성하게 된다.

또한 Git에는 .xcodeproj 파일을 올리지 않아서 충돌이 발생할 확률도 줄어든다.

 

🔴 단점

 

1️⃣ 러닝 커브

 

Xcode의 GUI에 익숙한 팀원이 tuist 코드 기반 프로젝트 설정 방식에 적응하기까지 시간이 걸릴 수 있다.

 

특히, Project.swift, Workspace.swift, Dependencies.swift 같은 파일 구조와 문법을 이해하고 관리해야 하므로, 초반 학습 부담이 있을 수 있다.

 

 

2️⃣ Tuist 의존성 

 

Tuist를 사용하면 프로젝트 설정이 Tuist에 종속되기 때문에, 만약 Tuist가 더 이상 유지보수되지 않거나 호환성 문제가 생기면 프로젝트 마이그레이션이 까다로울 수 있다.

 

=> "Xcode만 있으면 돌아가는 프로젝트"에서 Tuist 설치가 필수가 되기 때문에, 새 팀원이 프로젝트 받을 때 "Tuist 설치부터 해야 한다"는 장벽이 생길 수 있다.

 

 

3️⃣ Xcode와 동기화 문제

 

  • Tuist가 .xcodeproj 파일을 생성하긴 하지만, Xcode에서 설정을 직접 바꾸면 Tuist 코드와 동기화가 깨질 수 있다.
  • Tuist에서는 프로젝트 설정을 코드로 관리하므로, Xcode에서 설정 변경을 해도 Tuist 파일엔 반영이 안 됨 → 결국 Project.swift 코드만 믿고 가야 한다.

=> Xcode 설정을 바꾸지 않고, Tuist 설정 파일만 관리해야 한다. (하지만 Xcode GUI에 익숙한 팀원들에게는 불편할 수 있음...)

 

 

=> 장기적으로 프로젝트를 유지보수해야 하거나, 코드 기반으로 프로젝트를 관리하는 게 중요하다면 Tuist 도입이 효율적일 수 있다. 다만, 단점들도 분명히 존재하므로 팀원들과 충분히 상의한 후 적용하는 것이 좋을 것 같다.

 


2. Tuist 설치

 

1️⃣ mise 설치 및 버전확인

 

# mise 설치
curl https://mise.run | sh

# mise 버전확인
$ ~/.local/bin/mise --version

 

 

2️⃣ shell에 연결

 

echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
echo 'eval "$(~/.local/bin/mise activate zsh)"' >> ~/.zshrc
echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish

 

echo $SHELL을 입력해서 출력 확인해 보면 bash, zsh 중 뭔지 나온다.

 

나는 zsh이므로 두번째를 사용했다.

 

3️⃣ node.js 설치 및 node.js 전역 설정

 

# 설치 및 설정
mise use --global node@20

# 버전 확인
$ node -v

 

4️⃣ mise로 Tuist 설치

 

mise install tuist

 

🧐 주의

만약 install로 Tuist를 설치하셨다면 프로젝트 폴더에서 Tuist 생성이 안될 수 있다고 한다.

그래서 use -g 를 사용해서 전역설정을 해줘야 된다.

 

mise use -g tuist

 

 


3. Tuist 프로젝트에 적용

 

 

1️⃣ 처음 Tuist 프로젝트 생성 - tuist init

 

tuist init --path ios --template swiftui

 

이렇게 하니까 계속 init에 --template라는 옵션이 없다고 나와서 찾아보니 tuist init으로도 설정할 수 있는 걸 알았다.

tuist init으로 프로젝트 생성해 보자.

 

나는 프로젝트 새로 만드는 거여서 첫 번째로 했다.

 

 

이렇게 설정해 주다가 Authentication이 나오는데 여기서는 https://~ 여기 링크에 접속해서 로그인해 주면 된다.

 

 

Tuist 프로젝트 만들기 성공~~!!!

 

파일 확인해 보면 이렇게 잘 만들어졌다

 

2️⃣ 프로젝트 수정 - tuist edit

 

tuist edit

 

이 명령어는 프로젝트 정의를 수정할 때 사용하는 명령어다.

Tuist/Project.swift 파일을 열어서 프로젝트를 정의하게 되는데, 이걸 바로 편집할 수 있는 임시 Xcode 프로젝트를 만들어준다.

 

터미널에 tuist edit을 입력하면 바로 xcode가 실행되면서 수정 화면이 나온다.

 

 

3️⃣ 설정된 버전 설치 - tuist install

 

 

원래는 tuist fetch를 사용했었는데 tuist install로 바뀐 것 같다. 

 

만약 설정 파일을 수정했는데, Tuist 버전이 다르면 generate 명령어가 아예 안 돌아갈 수도 있다.

그래서 edit으로 파일 수정한 후 generate 하기 전에 버전 맞추는 용도로 install을 해줘야 한다고 한다.

 

4️⃣ 최종 프로젝트 생성 - tuist generate

 

generate는 edit에서 수정된 파일에 따라서 프로젝트를 생성한다.

Tuist/Project.swift 파일에 정의된 내용을 바탕으로 실제 프로젝트 파일을 생성하게 된다.

 

 

generate한 후 파일을 확인하면 .xcodeproj와 .xcworkspace가 생긴 것을 확인할 수 있다. 

 


4. 프레임워크 추가 후 import 해보기

 

TuistStudy는 제공하고 싶은 app으로 하고, NetworkKit은 framework로 설정해서 TuistStudy에서 NetworkKit를 import해서 사용할 수 있도록 해보자.

 

tuist edit으로 다음과 같이 수정한다.

 

import ProjectDescription

let appProject = Project(
    name: "TuistStudy",
    targets: [
        .target(
            name: "TuistStudy",
            destinations: .iOS,
            product: .app,
            bundleId: "io.tuist.TuistStudy",
            infoPlist: .extendingDefault(
                with: [
                    "UILaunchScreen": [
                        "UIColorName": "",
                        "UIImageName": "",
                    ],
                ]
            ),
            sources: ["Sources/**"],
            resources: ["Resources/**"],
            dependencies: []
        ),
        .target(
            name: "TuistStudyTests",
            destinations: .iOS,
            product: .unitTests,
            bundleId: "io.tuist.TuistStudyTests",
            infoPlist: .default,
            sources: ["Tests/**"],
            resources: [],
            dependencies: [.target(name: "TuistStudy")]
        ),
    ]
)
let networkProject = Project(
    name: "NetworkKit",
    targets: [
        .target(
            name: "NetworkKit",
            destinations: .iOS,
            product: .framework,
            bundleId: "io.tuist.NetworkKit",
            infoPlist: .extendingDefault(
                with: [
                    "UILaunchScreen": [
                        "UIColorName": "",
                        "UIImageName": "",
                    ],
                ]
            ),
            sources: ["Sources/**"],
            dependencies: []
        )
    ]
)

 

차이점을 조금 보자면 각각의 target의 Product가 .app과 .framework로 설정이 되어있고 NetwrokKit에는 Resoures 폴더가 필요 없어서 추가하지 않았다.

 

이제 각각의 Project에 필요한 Sources와 Resoures 디렉터리를 추가해 준다.

 

 

이렇게 다 추가해 준 후 tuist install -> tuist generate를 꼭 해줘야 수정한 파일이 적용되어서 프로젝트가 만들어진다. 

 

이제 생성된 프로젝트 파일을 확인하면 TuistStudy와 NetworkKit이 생긴 걸 확인할 수 있다.

 

 

이제 프로젝트를 실행할 수 있도록 Project 폴더 내부에 Add Files to ""로 Sources 폴더와 Resources 폴더를 추가해 준다.

 

만들어진 폴더 가져오기

 

그럼 이렇게 추가된 걸 확인할 수 있다.

 

 

📌 NetworkKit import 하기

 

이제 TuistStudy에서 NetworkKit을 import로 불러와 사용할 수 있게 해 보자.

 

다시 tuist edit 한 후, TuistStudy의 Project 파일에 dependencies를 추가해 준다.

 

 

이제 ContenView에서 import를 하면 NetworkKit을 찾지 못한다.

 

그 이유는 NetworkKit의 Sources 폴더에 파일이 없어서 import가 안된 것이기 때문에 파일을 하나 추가해 주자.

그냥 간단한 문자열을 출력해 보는 코드를 넣었다.

 

  • NetworkKit -> Sources에 파일 추가
import SwiftUI

public extension View {
    func printLog() {
        print("NetworkKit")
    }
}

 

  • NetworkKit import 성공 후, pringLog() 함수 호출해 보기
import SwiftUI
import NetworkKit

public struct ContentView: View {
    public init() {}

    public var body: some View {
        Text("Hello, World!")
            .padding()
            .onAppear {
                printLog()
            }
    }
}

 

그럼 이렇게 실행해 보면 "NetworkKit"가 잘 출력되는 걸 확인할 수 있다.

 

 

tuist graph 하면 이렇게 의존성을 사진으로 딱 보여주는데, NetworkKit을 의존하고 있는 것으로 잘 나오고 있다.

 

 


5. 라이브러리 설치 후 적용

 

📌  라이브러리 설치하기

 

마지막으로 라이브러리 설치 후 프로젝트에 적용하는 걸 해보자.

먼저 Tuist edit을 한 후 Tuist 폴더의 Package 파일에 dependencies를 추가해 주자.

 

나는 Alamofire을 추가하기 위해 .package()로 넣어줬다.

 

 

그리고 NetworkKit에 dependencies로 Alamofire을 넣어줘야 한다.

 

 

다시 tuist install -> tuist generate를 해준 후, NetworkKit에서 import Alamofire을 하면 오류가 발생하지 않고 성공적으로 잘 가져오는 걸 확인할 수 있다.

 

다시 tuist graph를 하면 다음과 같이 의존관계를 한눈에 확인할 수 있다.

 


💡느낀점💡

 

Tuist를 통해 Target 간 의존성을 명확하게 정의하고, 모듈화 된 구조를 유지할 수 있어서 프로젝트의 전체 흐름을 직관적으로 파악할 수 있다는 게 큰 장점으로 다가왔다. 특히 .pbxproj 같은 복잡한 설정 파일을 직접 다루지 않아도 돼서, 협업 시 발생할 수 있는 충돌 관리 부담이 줄어드는 부분이 강력한 이점이라고 생각된다. 하지만 러닝커브가 높기 때문에 어떤 프로젝트에 적용해야 할지는 좀 고민해봐야 할 것 같다.

 

그래도 익숙해지면 유지보수성과 확장성이 훨씬 개선된 프로젝트 관리가 가능할 것 같다!!

 


출처

https://1000one.tistory.com/80

https://velog.io/@junlight94/Tuist%EC%84%A4%EC%B9%98-%EB%B0%8F-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%81%EC%9A%A9

https://docs.tuist.dev/en/

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함