一口气讲清楚 Monorepo、Turborepo、pnpm、Changesets 到底是什么? 你肯定遇到过这种情况项目里同时有前端、后端、公共组件放在一个仓库嫌乱拆成多个仓库又改一个公共函数要在五个项目里各改一遍。于是出现了 Monorepo、Turborepo、pnpm、Changesets 这四个词。它们不是互相替代而是分别解决工程化中不同层面的问题。读完之后你会明白它们各自解决什么、技术原理是什么、彼此之间是什么关系以及在实际项目中该如何组合使用。一、先搞清楚一件事为什么会有这些工具前端工程化发展到今天一个中型项目往往包含多个应用Web、小程序、Node 服务和多个共享包UI 组件库、工具函数、类型定义。传统的多仓库Polyrepo模式有两个致命痛点代码复用难改一个公共函数要在 5 个仓库里各改一遍还要各自发版。依赖管理乱每个仓库都重复安装react、lodash磁盘空间爆炸版本不同步还容易出 bug。于是工程界开始借鉴谷歌、Facebook 的做法把多个项目放进同一个仓库——这就是 Monorepo。但光放进去还不够你还需要一个包管理器来高效处理依赖pnpm一个构建编排器来加速构建和任务执行Turborepo一个版本管理工具来帮你自动发版和生成 changelogChangesets这四个工具不是互相替代而是互补的分别解决前端工程化中不同层面的问题。二、Monorepo把多个项目放进同一个“家”2.1 一句话定义Monorepo 是一种代码仓库组织策略在一个 Git 仓库里管理多个相互独立但又相互依赖的项目应用、库、服务。2.2 跟 Polyrepo 有什么区别维度Polyrepo多仓库Monorepo单仓库代码复用发布 npm 包或复制粘贴直接通过workspace引用源码依赖管理每个仓库独立安装依赖重复浪费依赖提升到根目录一处安装全局使用跨项目改动改一个公共函数需改 N 个仓库只需改一次所有项目立即生效权限控制按仓库隔离精细但麻烦可通过 CODEOWNERS 实现目录级权限CI/CD每个仓库单独构建资源分散只构建受影响的项目可并行执行学习成本低各项目独立需理解 workspaces、任务编排等概念2.3 一个简单的目录结构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 份 react100 个项目 1 份 react安装速度慢重复下载快已下载过的直接从缓存链接幽灵依赖存在项目可访问未声明的包不存在严格的依赖隔离Monorepo 支持需要workspaces配置原生支持通过pnpm-workspace.yaml3.3 怎么配置 pnpm workspace在项目根目录创建pnpm-workspace.yamlpackages:-apps/*-packages/*然后执行pnpm install。pnpm 会自动把apps/和packages/下的每个子目录当作一个 workspace 包并通过符号链接让它们互相引用。3.4 常用命令pnpminstall# 安装所有依赖pnpmaddreact-w# 给根目录添加依赖-w 表示 workspace rootpnpm--filterwebaddlodash# 只给 web 应用添加 lodashpnpm--filterweb 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{$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/web和apps/admin。如果手动去修改这些包的package.json版本号并各自生成 changelog非常繁琐且容易漏。Changesets 自动化了这个流程。5.3 工作流程开发者改代码 ↓ pnpm changeset # 交互式选择要升级的包、填写变更描述 ↓ 生成 .changeset/*.md 文件提交到 Git ↓ CI / 发布时运行 pnpm changeset version ↓ 自动升级版本号、更新 changelog、删除 .changeset 文件 ↓ pnpm publish -r # 发布所有变更的包到 npm5.4 技术挑战与 CI/CD 集成需要在 PR 合并后自动运行version命令并提交需要配置 GitHub Actions 或 GitLab CI。依赖升级的传递性如果你改了底层包上层包是否要强制升级Changesets 可以自动处理但需要正确配置updateInternalDependencies。六、四者的关系一张图讲清楚工具角色定位解决的核心问题类比Monorepo代码组织策略多个项目如何放进同一个仓库盖一栋大楼框架pnpm包管理器如何快速、节省空间地安装依赖大楼的水电管道系统Turborepo任务编排器如何加速构建、测试、lint 等任务大楼的电梯调度系统Changesets版本管理如何自动化发版和生成 changelog大楼的物业管理系统它们的协作关系开发者修改代码在 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 version和publish。场景四已有大量 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 配置”。