普通视图

发现新文章,点击刷新页面。
今天 — 2026年1月18日首页

Monorepo入门

作者 Hyyy
2026年1月18日 00:35

1. Monorepo 介绍

核心价值:把“需要一起演进的一组项目”放在同一个版本空间里,从而让跨项目改动(API 变更、重构、升级)能在一次提交里完成并验证

Monorepo 是把多个相关项目/包放在同一个 Git 仓库中管理的策略,有助于跨项目联动修改、内部包共享更顺畅、统一规范与 CI、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。

Monorepo 提倡了开放、透明、共享的组织文化,这种方法已经被很多大型公司广泛使用,如 Google、Facebook 和 Microsoft 等。

2. Monorepo 演进

image.png

2.1 阶段一:单仓库巨石应用(Monolith)

初期很爽:一个仓库、一个 package.json、一个 node_modules、一个构建流程,但随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith。

问题在于:业务一旦变大,就容易出现:

  • 模块边界不清晰、改动影响范围越来越大
  • 构建/测试变慢
  • 多人协作冲突多

于是团队会自然想到:“拆开”,故此迎来阶段二。

注意:这里的 Monolith 是“一个应用越长越大”。它和后面的 Monorepo(多个包/项目同仓)不是同一个概念。

2.2 阶段二:多仓库多模块应用

把系统拆成多个仓库(例如:组件库仓库、业务 A 仓库、业务 B 仓库),会带来立竿见影的收益:

  • 每个仓库更小、owner 更明确、权限更清晰
  • 每个模块可以独立发版
  • 单仓库的 CI 看起来更快(只跑自己的)

代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo。

但当仓库越来越多,新的成本也会越来越明显:

  • 联动修改很难“原子化”:改组件库 API 后,你需要发布组件库,然后业务仓库分别升级、分别修、分别跑 CI。
  • 版本同步链路变长:底层库升级,上层一堆仓库要跟着升级验证。
  • 工程配置容易漂移:eslint/tsconfig/构建脚本在多个仓库逐渐不一致,治理难度上升。

这时候团队会意识到:拆仓库解决了局部自治,但放大了“协作与一致性”的成本。

2.3 阶段三:单仓库多模块应用

随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 Monorepo。

当“跨仓库联动成本”超过收益时,Monorepo 就变得有吸引力:

  • 改公共包 + 改所有使用方,可以在一个 PR 一次性完成并验证
  • 配置集中化,工程规范更易统一
  • 公共能力更容易沉淀成 packages,减少复制粘贴和重复造轮子

当然,Monorepo 也不是没有代价:

  • 仓库会变大(clone、索引、IDE 负担上升)
  • 如果没有“按影响范围执行(affected)+ 缓存”,CI 可能会变慢)

3. Monorepo 优劣

image.png

场景 MultiRepo MonoRepo
代码可见性 ✅ 代码隔离,研发者只需关注自己负责的仓库
❌ 包管理按照各自owner划分,当出现问题时,需要到依赖包中进行判断并解决。
✅ 一个仓库中多个相关项目,很容易看到整个代码库的变化趋势,更好的团队协作。
❌ 增加了非owner改动代码的风险
依赖管理 ❌ 多个仓库都有自己的 node_modules,存在依赖重复安装情况,占用磁盘内存大。 ✅ 多项目代码都在一个仓库中,相同版本依赖提升到顶层只安装一次,节省磁盘内存,
代码权限 ✅ 各项目单独仓库,不会出现代码被误改的情况,单个项目出现问题不会影响其他项目。 ❌ 多个项目代码都在一个仓库中,没有项目粒度的权限管控,一个项目出问题,可能影响所有项目。(
开发迭代 ✅ 仓库体积小,模块划分清晰,可维护性强。
❌ 多仓库来回切换(编辑器及命令行),项目多的话效率很低。多仓库见存在依赖时,需要手动 npm link,操作繁琐。
❌ 依赖管理不便,多个依赖可能在多个仓库中存在不同版本,重复安装,npm link 时不同项目的依赖会存在冲突。
✅ 多个项目都在一个仓库中,可看到相关项目全貌,编码非常方便。
✅ 代码复用高,方便进行代码重构。
❌ 多项目在一个仓库中,代码体积多大几个 G,git clone时间较长。
✅ 依赖调试方便,依赖包迭代场景下,借助工具自动 npm link,直接使用最新版本依赖,简化了操作流程。
工程配置 ❌ 各项目构建、打包、代码校验都各自维护,不一致时会导致代码差异或构建差异。 ✅ 多项目在一个仓库,工程配置一致,代码质量标准及风格也很容易一致。
构建部署 ❌ 多个项目间存在依赖,部署时需要手动到不同的仓库根据先后顺序去修改版本及进行部署,操作繁琐效率低。 ✅ 构建性 Monorepo 工具可以配置依赖项目的构建优先级,可以实现一次命令完成所有的部署。

4. Monorepo 场景

场景一:大型项目与多项目协作

  • 场景:企业或团队维护多个紧密关联的项目(如前端、后端、工具库等)。
  • 优势:集中管理代码,方便跨项目修改和协作,避免代码分散导致的重复劳动。

场景二:共享代码与依赖

  • 场景:多个项目共用组件库、工具函数或配置(如 UI 组件、通用 SDK)。
  • 优势:直接引用内部模块,避免多仓库的版本同步问题,确保依赖一致性。

场景三:统一构建与持续集成(CI/CD)

  • 场景:需要标准化构建、测试和部署流程。
  • 优势:集中配置 CI/CD,仅针对变更部分触发构建(增量构建),提升效率。

何时谨慎使用?

  • 代码量过大:需要考虑构建性能、代码可维护性
  • 权限管理复杂:需细化目录权限控制
  • 团队独立性高:若子团队高度自治,多仓库可能更灵活

5. Monorepo 工具

在采用 Monorepo(单一仓库)架构的软件开发中,工具的选择是至关重要的。合适的 Monorepo 工具能够帮助团队更高效地管理大规模代码库、提升协同开发体验以及优化构建和部署流程。

直至 2026 年年初,目前在前端界比较流行的 Monorepo 工具有 Pnpm WorkspacesYarn Workspacesnpm WorkspacesRushTurborepoYalc、和 Nx

5.1 依赖管理工具

没有 workspace/工具链时:A 包要用 B 包,只能 npm link、复制代码、或走相对/绝对路径,非常别扭且容易错。

负责“怎么安装依赖、怎么把 workspace 包链接起来”

pnpm workspace 是包管理器层面的工作区能力

  • 支持 monorepo 内部包之间用“包名”互相依赖(不是路径引用),并自动链接到本地源码
  • pnpm 有全局的内容存储(store),不同项目/不同 workspace 之间可以复用同版本依赖;再通过链接把依赖组织到各包的 node_modules 结构中。:直观效果:同一个依赖不需要在 N 个地方复制 N 份。
  • 依赖安装更快、更省空间(全局 store 复用 + 链接)
  • 默认依赖隔离更严格,可显著减少“幽灵依赖”

强烈推荐使用Pnpm Workspaces 作为 Monorepo 项目的依赖管理工具😍😍😍

  • pnpm:通过全局 store + 链接方式,通常既省空间又更严格

5.1.1 避免幽灵依赖

npm/yarn 安装依赖时,存在依赖提升,某个项目使用的依赖,并没有在其 package.json 中声明,也可以直接使用,这种现象称之为 “幽灵依赖”;随着项目迭代,这个依赖不再被其他项目使用,不再被安装,使用幽灵依赖的项目,会因为无法找到依赖而报错,而 pnpm 彻底解决这个问题

所谓幽灵依赖,可以理解为:

某个包没有在自己的 package.json 声明依赖,但因为安装结构/提升等原因,代码依然能 import 到它,直到某天依赖结构变化才突然报错。

pnpm 默认对依赖访问更严格,能更早暴露“未声明却在使用”的问题,让错误更早出现、定位更容易。

什么是幽灵依赖

先提问:你觉得“一个包能 import 某个依赖”的前提是什么?

正常答案应该是:

这个包的 package.json 里 dependencies/devDependencies 声明了它。

幽灵依赖就是:没声明,但居然还能 import 并运行成功

最小例子(用 npm/yarn 经典安装方式更容易出现):

假设是 monorepo:

  • 根 package.json 没有 lodash
  • packages/a/package.json 声明了 lodash
  • packages/b/package.json 没声明 lodash

但在 packages/b/src/index.ts 里写了:

import _ from "lodash";

在 npm/yarn(node_modules 提升/hoist)  的某些安装结果下,lodash 可能被“提升”到了更上层的 node_modules,导致 b 虽然没声明,也能“碰巧”找到 lodash,于是:

  • 开发阶段:你以为没问题
  • 某天 a 删除了 lodash 或版本变化/安装结构变化:b 突然就挂了

这就像:你家隔壁有个锤子,你没买但你一直去借用;直到隔壁搬家,你才发现自己其实从来没拥有它。

为什么 pnpm 更容易避免?

pnpm 的默认策略更“严格”:

  • 每个 package 能访问到的依赖,基本只限于它声明的那一圈(通过链接+隔离结构实现)
  • 所以 b 没声明 lodash,就更容易直接报错(这反而是好事:早发现早修)

一句话总结你可以写进文章:

幽灵依赖:未在当前包的 package.json 声明,却因为依赖提升等原因在运行时能被解析到的依赖;pnpm 通过更严格的依赖隔离,能显著减少这类问题。

5.1.2 依赖安装耗时长

MonoRepo 中每个项目都有自己的 package.json 依赖列表,随着 MonoRepo 中依赖总数的增长,每次 install 时,耗时会较长。使用 pnpm 按需安装及依赖缓存,相同版本依赖提升到 Monorepo 根目录下,减少冗余依赖安装;

那么 Monorepo 与包管理工具(npm、yarn、pnpm)之间是一种怎样的关系?

这些包管理工具与 monorepo 的关系在于,它们可以为 monorepo 提供依赖安装与依赖管理的支持,借助自身对 workspace 的支持,允许在 monorepo 中的不同子项目之间共享依赖项,并提供一种管理这些共享依赖项的方式,这可以简化依赖项管理和构建过程,并提高开发效率。

5.1.3 构建打包耗时长

问题:多个项目构建任务存在依赖时,往往是串行构建 或 全量构建,导致构建时间较长,可以使用增量构建,而非全量构建;也可以将串行构建,优化成并行构建。

npm、yarn、pnpm 等是用来管理项目依赖、发布包、安装依赖的工具,他们都提供了对工作区(workspace)的支持,允许在单个代码库中管理多个项目或包。这种工作区支持在单个代码库中同时开发、测试和管理多个的项目,而无需使用多个独立的代码仓库。

这些包管理工具与 monorepo 的关系在于他们可以为 monorepo 提供依赖安装与依赖管理的支持,借助自身对workspace的支持,允许在monorepo中的不同子项目之间共享依赖项,并提供一种管理这些共享以来想的方式,这可以简化依赖项管理和构建过程,并提高开发效率。

硬链接指向同一份文件数据,因此可以复用磁盘空间。

5.2 任务编排/构建系统

如果说 Workspace(pnpm/yarn/npm)解决的是“依赖怎么装、包怎么互相链接”,那么任务编排/构建系统解决的就是 “该跑哪些任务、按什么顺序跑、能不能并行、能不能跳过,以及结果能不能复用”

它通常会提供几类核心能力:

  • 依赖图(Task Graph):根据 package 之间的依赖关系,自动推导任务执行顺序
    例如:先 build packages/ui,再 build apps/web
  • 受影响范围计算(Affected):只要改动没有影响到某些包,就不跑它们的 build/test/lint
    例如:只改了 packages/ui,就只重跑 ui 及其依赖它的应用(web/admin),而不是全仓库全量跑。
  • 并行执行(Parallelism):没有依赖关系的任务可以并行跑,显著缩短 CI 时间。
  • 缓存与增量构建(Caching):同样的输入(代码、锁文件、环境)产生同样的输出时,可以直接复用上次结果
    支持本地缓存和远程缓存(Remote Cache),对 CI 提速非常明显。
  • 统一脚本入口:把“每个包自己维护的一堆脚本”抽象成可治理、可观测的流水线。

没有任务编排/增量构建时,Monorepo 常见痛点会很快出现:

  • CI 只能“全量 build / 全量 test”,仓库越大越慢
  • 任务执行顺序靠人维护,容易写错、漏跑
  • 同样的构建在本地和 CI 反复做,重复劳动
  • 发布流程复杂:多个包的 build/test/version/publish 缺少统一的依赖顺序和可追溯性

因此,在中大型 Monorepo 里,通常会引入以下工具来解决“任务编排 + 缓存 + 增量构建”的问题:

  • Turborepo:上手快、理念清晰,适合前端 Monorepo 的 build/test/lint 编排与缓存。
  • Nx:能力更完整(affected、代码生成、约束治理、可视化依赖图等),适合更复杂的多应用/多语言场景。
  • Rush:偏企业级工程治理与发布流程管理,常见于大型组织的多包管理体系中。

6. 总结

  • Monorepo 并不是银弹,而是一种权衡工程管理与项目协作复杂性的最佳实践之一。适用于项目关联紧密、需频繁联动、强调一致性的中大型团队/企业。
  • 通过引入现代的包管理工具(如 pnpm workspace)和任务编排系统(如 Turborepo、Nx),Monorepo 管理的优势可以最大化,同时减轻依赖和构建上的压力。
  • 采用 Monorepo 可以促进团队协作、统一规范和复用代码,但也需留意仓库增大、权限细化等实际挑战。
  • 是否采纳 Monorepo,需结合企业项目规模、团队协作方式、基础设施支持等多方面因素综合考量。
  • 总之,合理组合工具和规范,才能真正发挥 Monorepo 的价值,为团队降本增效。
❌
❌