背景与痛点
👋“大家好,我想在开始前问大家一个问题:假设你在工作多年后,准备启动一个自己的全栈产品:有前端管理后台、App、小程序,还有后端服务、后台接口……如果这些模块你都要自己维护,代码分散在多个仓库里,版本要手动控制,部署也要到处点命令,大家有没有想过一个更统一、高效的方式🙋“有没有人曾经为这些事头疼过?”➡️ “今天我们要聊的就是:Monorepo + Turborepo
有人会说 pnpm 不是也能进行包管理 进行工作空间管理嘛
单纯使用 pnpm 就能实现 Monorepo 项目我们都知道,因为它原生支持 workspace,但是它也依然存在一些缺点,例如:
- 任务运行策略:虽然 pnpm 支持工作空间间的依赖管理和一些任务的并行执行,但是它并不那么灵活或高效地处理跨包的构建、测试和发布任务比如增量构建和任务缓存,可以显著提高大型 Monorepo 的开发和持续集成的效率。
- 自定义构建和发布流程:pnpm 在自定义构建流程、测试流程和发布流程方面的能力有限。对于需要高度定制化工作流的复杂 Monorepo 项目,可能需要额外的脚本或配置来满足这些需求。
- 构建效率:在没有专门的构建缓存机制的情况下,pnpm 对于大型 Monorepo 项目的构建效率可能不如使用了缓存策略的工具。这可能导致在持续集成/持续部署(CI/CD)环境中,构建和部署的时间增长。
- 高级任务调度和资源管理:pnpm 本身可能不提供高级的任务调度和资源管理特性,如限制并行任务数目以避免过度占用系统资源,或者根据任务的资源使用情况动态调整优先级。
尽管 pnpm 为 Monorepo 提供了强大的支持,并且在许多场景下都能很好地工作,但在需要复杂的任务运行策略、细粒度的任务控制以及高效的任务执行优化时,可能会遇到一些问题,在这种情况下我们可能就需要通过额外的工具、脚本或工作流来补充或优化 pnpm 的使用。
Monorepo 简介 & 价值
Monorepo(Monolithic Repository),即“单体代码仓库”,Monorepo 是一种项目代码管理方式,指单个仓库中管理多个项目,有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。Monorepo 提倡了开放、透明、共享的组织文化,这种方法已经被很多大型公司广泛使用,如 Google、Facebook 和 Microsoft 等。
Monorepo 工具的演变过程
🛠️ 早期:手动管理 & 静态打包
- 最早公司自己手写 shell 脚本串联多个子项目
- 不支持依赖图构建、缓存等能力
- 工具匮乏、容易出错,维护成本高
🪜 第一阶段:Lerna(2015 起)
- 第一个广泛使用的 JS Monorepo 工具
- 以 lerna bootstrap 管理依赖
- 适合 library 场景,但构建能力弱,不适合现代大型应用
- 随着 Yarn Workspaces、pnpm 的发展,Lerna 功能逐渐被取代
🚀 第二阶段:Nx、Rush、Bazel 等现代工具
- 支持:
- 任务依赖图构建
- 分布式缓存
- 细粒度构建优化
- Nx:前端友好,支持 React、Angular、Nest,CLI 强大, 还支持flutte、Go
- Rush:适合大规模企业级场景(微软开发)
- Bazel:谷歌内部方案,配置复杂但性能强大(如 Google Maps)
⚡ 第三阶段:Turborepo(Vercel 推出,2021)
- 上手简单,零配置集成 pnpm/Yarn/NPM
- 强调构建缓存、任务管道(pipeline)机制
- 默认支持现代前端框架(Next.js、React、TS)
- 轻量但强大,尤其适合中大型项目和独立开发者
为什么是 Turborepo?
工具 | 介绍 | 优点 | 缺点 |
Rush | 由Microsoft开发,为大型Monorepo项目提供全面的支持。具有完整的生态系统,自动版本管理和并行构建。学习曲线较陡峭,更适用于大型项目。 | 1、完整生态系统 2、自动版本管理 3、并行构建 | 1、学习曲线较陡峭 2、对小型项目可能显得过于庞大 |
Turborepo | 旨在提供高度可配置的Monorepo解决方案,支持自定义构建流程和任务。灵活性较高,适用于各种项目。 | 1、高度可配置 2、支持自定义构建流程 | 1、相对较新,可能缺乏一些成熟的功能和社区支持 |
Lerna | 专注于管理具有多个包的JavaScript项目,提供了一组工具用于优化Monorepo的管理。支持并行构建,版本管理等。 | 1、专注于JavaScript项目 2、并行构建 3、版本管理方便 | 1、学习曲线较陡峭 2、配置不够灵活 |
Yarn Workspaces | Yarn的一部分,提供了一种Monorepo管理方案,允许多个包共享相同的 node_modules 。轻量级,易于上手。 | 1、轻量级 2、易于上手 | 1、功能相对比较单一 |
Pnpm Workspaces | Pnpm的一部分,提供了与Yarn Workspaces类似的功能,支持多个包共享依赖。通过符号链接进行高效的依赖管理。 | 1、高效的依赖管理 2、易于上手 | 1、功能相对比较单一 2、需要适应符号链接的概念 |
Yalc | 允许在不发布到npm仓库的情况下共享本地包,适用于本地开发和测试。 | 1、本地包共享方便 | 1、可能不适用于所有场景,特别是在需要发布到公共npm仓库时 |
npm Workspaces | npm的一部分,提供了在Monorepo中管理包的功能。与Yarn Workspaces类似,但在某些方面有所不同。 | 1、与npm集成 | 1、功能相对简单 |
Nx | 针对Angular项目的工具,提供了一套强大的Monorepo管理功能,包括构建、测试、文档生成等。专注于提高Angular项目的开发效率。 | 1、针对Angular项目优化的强大功能集 | 1、针对非Angular项目可能显得过于专业化,学习曲线较陡峭 |
上手简单,零配置集成 pnpm/Yarn/NPM
Turborepo 是一个高性能的构建系统,专为 JavaScript 和 TypeScript 的 Monorepo 项目设计。它提供了一种高效管理和构建项目中多个包的方式,通过缓存先前构建和测试的结果来显著减少重复工作的需要,从而加快开发和持续集成的流程。Turborepo 旨在提高大型 Monorepo 项目的构建效率,特别是在复杂的项目中,它可以处理依赖关系、执行任务、并确保构建的正确性和效率。
- 多任务并行处理
- 更快的增量构建
- 云缓存
- 任务管道
- 基于约定的配置
多任务并行处理

增量构建
“你是否遇到过,明明只改了一个小组件,却要重头构建几十个模块?那你需要的就是 增量构建!”
增量构建(Incremental Build)是指在项目构建过程中,只重新构建发生变化的部分,而跳过那些没有变更的模块或任务,从而大幅度提升构建效率。
增量构建意味着在构建过程中,只有自上次成功构建以来发生变化的部分才会被重新构建,而未更改的部分则会跳过,直接使用上次构建的结果。
Turborepo 首先分析项目的依赖图,包括识别各个包之间的依赖关系。这是增量构建的基础,确保只有当依赖的包发生变化时,依赖它们的包才会被重新构建。
使用文件指纹(或哈希)技术来确定文件自上次构建以来是否发生了更改。通过比较文件的当前指纹与存储在缓存中的上一次构建指纹,Turborepo 能够快速识别哪些文件需要重新构建。
Turborepo 利用先进的缓存机制来存储构建结果,包括编译后的代码、测试结果等。如果检测到某个包或任务自上次构建以来没有变化(基于文件指纹比较),Turborepo 将跳过这些任务的执行,并直接使用缓存中的结果。
云缓存
暂时不过多介绍
Turborepo 核心概念
DependsOn
DependsOn 是一种配置属性,它允许你明确指定任务之间的依赖关系。通过使用 DependsOn,你可以确保在执行某个任务之前,其所有依赖的任务都已经完成。这是构建复杂 Monorepo 项目时确保正确执行顺序的关键机制。
cache
cache 表示是否缓存,通常我们执行 dev 命令的时候会结合 watch 模式,所以我们一般在项目启动模式下不需要开启 turbo 缓存机制
OutputMode
选项 | 描述 |
full | 显示所有输出(默认) |
hash-only | 仅显示任务的哈希值 |
new-only | 仅显示缓存未命中的输出 |
errors-only | 仅显示任务失败的输出 |
none | 隐藏所有任务输出 |
{ "$schema": "https://turborepo.com/schema.json", "ui": "tui", "tasks": { "build": { "dependsOn": ["^build"], <-- DependsOn 依赖关系 "inputs": ["$TURBO_DEFAULT$", ".env*"], "outputs": [".next/**", "!.next/cache/**"], }, "lint": { "dependsOn": ["^lint"] }, "check-types": { "dependsOn": ["^check-types"] }, "dev": { "cache": false, <-- cache 缓存 "persistent": true } } }
项目中的落地实践
首先先创建一个事例项目 pnpm dlx create-turbo@latest npx create-next-app@latest pnpm create vue@latest
演示build lint 等 任务构建
实施过程中的踩坑与注意事项
问题 | 解决方式或注意点 |
输出未配置导致缓存不生效 | 加上 "outputs": ["dist/**"] |
Dev 模式误命中缓存 | 对 dev 任务配置 "cache": false |
多人协作缓存错乱 / CI 无效 | 使用 turbo remote cache + .turbo 设置 |
涉及 App / iOS 项目缓存无效 | 建议 App 项目脱离 turbo 管理,单独部署 |
输出路径不一致导致命中失败 | 保证构建产物路径、内容稳定(如路径 hash) |