一口气讲清楚 Monorepo、Turborepo、pnpm、Changesets 到底是什么?

你肯定遇到过这种情况:项目里同时有前端、后端、公共组件,放在一个仓库嫌乱,拆成多个仓库又改一个公共函数要在五个项目里各改一遍。于是出现了 Monorepo、Turborepo、pnpm、Changesets 这四个词。它们不是互相替代,而是分别解决工程化中不同层面的问题。读完之后,你会明白它们各自解决什么、技术原理是什么、彼此之间是什么关系,以及在实际项目中该如何组合使用。


一、先搞清楚一件事:为什么会有这些工具?

前端工程化发展到今天,一个中型项目往往包含多个应用(Web、小程序、Node 服务)和多个共享包(UI 组件库、工具函数、类型定义)。传统的多仓库(Polyrepo)模式有两个致命痛点:

  1. 代码复用难:改一个公共函数,要在 5 个仓库里各改一遍,还要各自发版。
  2. 依赖管理乱 :每个仓库都重复安装 reactlodash,磁盘空间爆炸,版本不同步还容易出 bug。

于是工程界开始借鉴谷歌、Facebook 的做法,把多个项目放进同一个仓库------这就是 Monorepo。但光放进去还不够,你还需要:

  • 一个包管理器来高效处理依赖(pnpm)
  • 一个构建编排器来加速构建和任务执行(Turborepo)
  • 一个版本管理工具来帮你自动发版和生成 changelog(Changesets)

这四个工具不是互相替代,而是互补的,分别解决前端工程化中不同层面的问题。


二、Monorepo:把多个项目放进同一个"家"

2.1 一句话定义

Monorepo 是一种代码仓库组织策略,在一个 Git 仓库里管理多个相互独立但又相互依赖的项目(应用、库、服务)。

2.2 跟 Polyrepo 有什么区别?

维度 Polyrepo(多仓库) Monorepo(单仓库)
代码复用 发布 npm 包或复制粘贴 直接通过 workspace 引用源码
依赖管理 每个仓库独立安装依赖,重复浪费 依赖提升到根目录,一处安装全局使用
跨项目改动 改一个公共函数需改 N 个仓库 只需改一次,所有项目立即生效
权限控制 按仓库隔离,精细但麻烦 可通过 CODEOWNERS 实现目录级权限
CI/CD 每个仓库单独构建,资源分散 只构建受影响的项目,可并行执行
学习成本 低,各项目独立 需理解 workspaces、任务编排等概念

2.3 一个简单的目录结构

perl 复制代码
my-monorepo/
├── apps/              # 应用程序
│   ├── web/           # React 前端
│   ├── admin/         # 后台管理系统
│   └── api/           # Node 后端
├── packages/          # 共享包
│   ├── ui/            # 组件库
│   ├── utils/         # 工具函数
│   └── config/        # 共享配置(ESLint、TS)
├── package.json
├── pnpm-workspace.yaml # 工作区配置
└── turbo.json          # Turborepo 配置

2.4 技术挑战

  • 依赖提升带来的幽灵依赖 :项目可能引用未在自身 package.json 声明的包(因为被提升到了根目录),导致部署时遗漏依赖。
  • 构建性能:随着项目增多,全量构建会越来越慢,需要增量构建和缓存。
  • 权限与协作:需要合理的 CODEOWNERS 和分支策略,避免一个人改崩整个仓库。

三、pnpm:比 npm 更聪明的包管理器

3.1 一句话定义

pnpm 是一个高性能的包管理器,它通过内容可寻址存储符号链接实现多项目间依赖的全局去重,比 npm/yarn 更快、更省磁盘空间。

3.2 跟 npm / yarn 有什么区别?

维度 npm / yarn(传统) pnpm
依赖存储 每个项目 node_modules 都复制一份依赖 全局 store 存储一份,通过硬链接复用
磁盘占用 100 个项目 = 100 份 react 100 个项目 = 1 份 react
安装速度 慢,重复下载 快,已下载过的直接从缓存链接
幽灵依赖 存在(项目可访问未声明的包) 不存在,严格的依赖隔离
Monorepo 支持 需要 workspaces 配置 原生支持,通过 pnpm-workspace.yaml

3.3 怎么配置 pnpm workspace?

在项目根目录创建 pnpm-workspace.yaml

yaml 复制代码
packages:
  - "apps/*"
  - "packages/*"

然后执行 pnpm install。pnpm 会自动把 apps/packages/ 下的每个子目录当作一个 workspace 包,并通过符号链接让它们互相引用。

3.4 常用命令

bash 复制代码
pnpm install                 # 安装所有依赖
pnpm add react -w            # 给根目录添加依赖(-w 表示 workspace root)
pnpm --filter web add lodash # 只给 web 应用添加 lodash
pnpm --filter web dev        # 只运行 web 应用的 dev 脚本

3.5 技术挑战

  • 原生工具链兼容性 :一些旧的 npm 脚本或工具假设 node_modules 是平铺结构,在 pnpm 下可能不工作(可通过 shamefully-hoist 解决)。
  • 学习成本 :开发者需要理解 --filter、workspace 协议("ui": "workspace:*")等概念。

四、Turborepo:让构建任务"快如闪电"

4.1 一句话定义

Turborepo 是一个高性能的任务编排器,专门为 Monorepo 设计。它会缓存每个任务的输入输出,第二次运行相同输入时直接跳过执行,从而实现秒级重构建。

4.2 跟普通 npm run 脚本有什么区别?

维度 普通脚本 Turborepo
执行方式 按顺序串行执行 自动并行执行(依赖关系不变)
缓存 内容寻址缓存,相同输入直接返回缓存结果
增量构建 需要手动实现 自动检测哪些项目变了,只构建受影响的部分
远程缓存 不支持 支持云缓存,团队成员共享构建缓存
依赖感知 自动识别 dependsOn,按拓扑顺序构建

4.3 Turborepo 工作原理

Turborepo 用 管道(pipeline) 定义任务之间的关系。一个典型的 turbo.json

json 复制代码
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],      // 先构建依赖包,再构建当前包
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": {
      "cache": false,               // 开发模式不缓存
      "persistent": true
    },
    "lint": {
      "dependsOn": ["^lint"]       // 先跑依赖包的 lint
    },
    "test": {
      "dependsOn": ["build"]       // 先 build 再 test
    }
  }
}

缓存机制:Turbo 会计算任务输入(源代码、依赖的 task 输出、环境变量)的哈希值。如果哈希值没有变化,直接输出之前缓存的产物,执行时间从分钟级降为毫秒级。

4.4 技术挑战

  • 缓存失效过于保守 :如果你的任务输入包含不必要的大文件(如 node_modules),缓存命中率会很低。
  • 远程缓存需要服务器:团队共享缓存需要自己部署或使用 Vercel 的 Remote Cache。

五、Changesets:版本管理不再痛苦

5.1 一句话定义

Changesets 是一个用于 Monorepo 的版本管理和 changelog 生成工具。它让你在提交代码时记录变更意图,然后一键批量发布所有需要升级的包。

5.2 为什么需要它?

在 Monorepo 中,你改了 packages/utils,可能会同时影响 apps/webapps/admin。如果手动去修改这些包的 package.json 版本号,并各自生成 changelog,非常繁琐且容易漏。Changesets 自动化了这个流程。

5.3 工作流程

bash 复制代码
开发者改代码
    ↓
pnpm changeset      # 交互式选择要升级的包、填写变更描述
    ↓
生成 .changeset/*.md 文件(提交到 Git)
    ↓
CI / 发布时运行 pnpm changeset version
    ↓
自动升级版本号、更新 changelog、删除 .changeset 文件
    ↓
pnpm publish -r    # 发布所有变更的包到 npm

5.4 技术挑战

  • 与 CI/CD 集成 :需要在 PR 合并后自动运行 version 命令并提交,需要配置 GitHub Actions 或 GitLab CI。
  • 依赖升级的传递性 :如果你改了底层包,上层包是否要强制升级?Changesets 可以自动处理,但需要正确配置 updateInternalDependencies

六、四者的关系:一张图讲清楚

工具 角色定位 解决的核心问题 类比
Monorepo 代码组织策略 多个项目如何放进同一个仓库 盖一栋大楼(框架)
pnpm 包管理器 如何快速、节省空间地安装依赖 大楼的水电管道系统
Turborepo 任务编排器 如何加速构建、测试、lint 等任务 大楼的电梯调度系统
Changesets 版本管理 如何自动化发版和生成 changelog 大楼的物业管理系统

它们的协作关系:

bash 复制代码
开发者修改代码(在 Monorepo 中)
        ↓
pnpm 负责安装依赖,链接 workspace 包
        ↓
Turborepo 负责按需执行任务(build、test、lint),利用缓存加速
        ↓
开发完成后,提交 PR
        ↓
PR 合并到 main 分支
        ↓
CI 运行 Changesets:自动升级版本、生成 changelog
        ↓
pnpm publish -r 发布到 npm

七、技术选型指南:实际工程中怎么组合?

场景一:个人项目或小团队(2-5 人,3-5 个包)

  • 推荐pnpm + Monorepo 就够了,不需要 Turborepo(构建不慢)和 Changesets(手动改版本号也能接受)。
  • 操作 :直接用 pnpm workspace,在根目录写几个 npm scripts 串行执行 build

场景二:中型项目(5-20 人,10-20 个包,构建耗时 > 2 分钟)

  • 推荐pnpm + Turborepo + Monorepo,用 Turborepo 的缓存和并行能力加速 CI。
  • 版本管理:可以暂时手动改版本,也可以用 Changesets 但非强制。

场景三:大型项目 / 开源库(多人协作,频繁发版,包之间有复杂依赖)

  • 推荐pnpm + Turborepo + Changesets + Monorepo,全套上齐。
  • 额外 :配置远程缓存(如 Vercel Remote Cache)让团队成员共享构建结果;设置 CI 自动执行 changeset versionpublish

场景四:已有大量 npm 包,准备迁移到 Monorepo

  • 步骤 :先用 pnpm import 把现有 package-lock.json 转成 pnpm-lock.yaml;然后逐步把相关仓库移入 packages/,调整 import 路径;最后引入 Turborepo 优化 CI。

💎 写在最后

回到最开始的问题:为什么需要 Monorepo、Turborepo、pnpm、Changesets 这四个工具?

  • Monorepo 给你一个容纳多项目的大房子。
  • pnpm 给你高效的管道系统,让依赖管理快如闪电。
  • Turborepo 给你智能的电梯,让构建任务不再重复劳动。
  • Changesets 给你规范的物业管理,让版本发布井井有条。

它们不是"银弹",但当你团队规模膨胀、项目耦合加深时,这套组合拳能让你从"复制粘贴工程师"进化为"工程化架构师"。

如果你也在搭建 Monorepo,或者被多仓库的代码复用问题折磨过,点个赞让我看到。赞多的话,下一篇写"如何从零落地一个 pnpm + Turborepo + Changesets 的 Monorepo 项目,包含完整 CI 配置"。

相关推荐
linsk19982 小时前
Rollup 官方插件 @rollup/plugin-inject 详解
前端工程化
IT_陈寒2 小时前
React性能优化踩的坑,这个错你可能也会犯
前端·人工智能·后端
zhangxingchao2 小时前
AI应用开发三:RAG技术与应用
前端·人工智能·后端
摘星小杨2 小时前
如何在前端循环调取接口,实时查询数据
开发语言·前端·javascript
Hilaku3 小时前
从搜索排名到 AI 回答? 先聊一聊 AI 可见度工具 BuildSOM !
前端·javascript·程序员
zzmgc43 小时前
纯静态 + Web Worker + 虚拟滚动:我是怎么让浏览器吃下 10MB JSON 不卡的
前端·架构
辰同学ovo3 小时前
用 Chrome DevTools MCP 给 AI 写的页面做“质检“
前端·人工智能·chrome devtools
乌托邦3 小时前
uni-mini-ci:让 uniapp 小程序构建后自动预览和上传
前端·vue.js·uni-app
豹哥学前端3 小时前
前端工程化实战:从包管理到 Vite 配置,一套下来全明白
前端·javascript·vite