如果团队沿着本系列把模块扩展到几十个,就会遇到一种新的疲惫感。
每增加一个模块就要重复配置,项目文件冲突依然存在,而且不同成员的模块配置还会有细微差异。
Tuist 正是为了解决这个问题。简单来说,它把 Xcode 项目文件从仓库中移除,改用 Swift 代码声明并生成项目。
本文将总结 Tuist 解决的问题、Project.swift 的基本用法,以及在大型团队中发挥价值的二进制缓存。基于 2026 年 7 月的 Tuist 4。
Tuist 解决了哪些问题?
核心是把 pbxproj 的所有权从人转移给工具。
在常见的 iOS 项目中,project.pbxproj 会提交到仓库。添加文件、修改 target 设置都会改动它,而它的格式也难以阅读,因此出现合并冲突时很难处理。
在 Tuist 项目中不会提交这个文件,而是提交名为 Project.swift 的声明。
| 对比 | 普通项目 | Tuist 项目 |
|---|---|---|
| 仓库中保存的内容 | project.pbxproj | Project.swift(Swift 代码) |
| 项目文件 | 手动管理 | 每次通过 tuist generate 生成 |
| 合并冲突 | pbxproj 中频繁发生 | Swift 代码 diff 中很少发生 |
| 添加模块 | GUI 操作 + 重复配置 | 调用一行函数 |
项目文件变成生成产物后,就不再是合并冲突的目标。将它加入 .gitignore 即可。
Project.swift 是什么样的?
关键在于模块定义是 Swift 代码,因此可以把重复配置封装成函数。
// Project.swift
let project = Project(
name: "MyApp",
targets: [
.target(
name: "MyApp",
destinations: .iOS,
product: .app,
bundleId: "com.example.myapp",
sources: ["Sources/**"],
dependencies: [
.target(name: "FeatureSearch"),
.target(name: "CoreNetwork"),
]
),
]
)
到这里,它看起来可能和 SPM(Swift Package Manager)的 Package.swift 很像。区别在于可扩展性。
将团队标准的模块形式定义为辅助函数后,新增功能模块真的只需一行代码。
// 团队标准:功能模块 = 源码 + 测试 + 演示应用套件
let searchModule = Target.featureModule(name: "Search")
let orderModule = Target.featureModule(name: "Order")
// 每个模块包含若干 target,配置在辅助函数中统一 3
如果有 30 个模块,使用 pbxproj 就要重复操作 30 次设置界面;使用 Tuist 则只需向数组中添加名称。成员之间配置不一致的可能性也随之消失。
内置依赖图可视化功能。只需执行一次 tuist graph,就能绘制模块依赖关系,方便直观看到循环依赖,或上一篇文章中警告过的“所有人都依赖的臃肿模块”。
二进制缓存:构建速度的下一步
上一篇文章提到,模块化可以缩小重新编译的范围;Tuist 缓存则更进一步。
tuist cache 会预先构建每个模块,并将其保存为二进制文件(framework)。之后执行 tuist generate 时,未发生变化的模块会用缓存二进制替代源码。
- 如果我只在开发搜索功能:只以源码形式打开搜索模块,其余几十个模块都以构建完成的二进制形式接收。
- 即使是全量构建,实际上也只剩下“我的模块 + 链接”。
使用远程缓存后,团队和 CI 可以共享这些二进制文件。我的机器无需重新构建同事已经构建过的模块。这就是大型团队能将全量构建时间从分钟降到秒级的原因。
什么时候适合引入,什么时候会过度?
Tuist 很强大,但引入它也意味着把一个工具加入团队的必需依赖。
| 情况 | 判断 |
|---|---|
| 少于 10 个模块,小型团队 | 使用 SPM 本地包就足够 |
| 几十个模块,pbxproj 每周都发生冲突 | 引入价值很高 |
| CI 和团队构建时间开始造成成本问题 | 仅缓存功能就足以成为引入理由 |
| 团队完全没有精力负责构建系统 | 需要考虑学习曲线和跟进更新的成本 |
如果决定引入,建议先用 Tuist 管理新模块,再逐步迁移现有 target,而不是一次性全面切换。XcodeGen 是更轻量的替代方案,只负责生成项目;如果不需要缓存,也可以一并评估。
面试中可以这样回答
问:为什么要引入 Tuist 这样的项目生成工具?
因为从仓库中移除 pbxproj 可以消除合并冲突,而用 Swift 代码声明项目配置可以标准化模块模板。此外,二进制缓存还能跳过未变化模块的重新构建,降低模块化的管理成本,同时放大构建速度收益。
问:随着模块数量增加,如何从团队层面缩短构建时间?
引入模块级二进制缓存,用预构建产物替代未变化的模块,再通过远程缓存让团队和 CI 共享。开发者只以源码形式打开自己正在开发的模块,因此全量构建成本会与工作范围成正比。
至此,模块化系列结束。我们从边界和内聚性出发,依次讲到依赖方向、分层结构、SPM、构建速度,最后来到 Tuist。
按顺序实践这些方法,你获得的不只是“构建更快”,还会拥有一个“不再害怕修改”的代码库。

![[模块化 #6] 用 Tuist 轻松实现 iOS 模块化 封面图](/assets/images/posts/2461e64e-988b-43c4-a75f-59b167bfa642/1.jpg)