2025.09.01

理解 Monorepo:多包管理的概念

🚀 什么是 Monorepo

  • 简洁定义:将多个相互关联的项目或库集中在一个 Git 仓库中进行统一管理、开发和发布。
  • 形象类比:它就像一个**“超级工厂”**,里面有多个独立运行的生产线(子项目),但所有生产线都共享一套标准化的工具、基础设施和中央管理系统。

✨ 为什么选择 Monorepo

优势解决的问题Alien v
省心 🧹 (统一配置)每个项目都需要重复配置 ESLint, Prettier, CI 等工具。统一工具链,一处配置,全局生效,消除配置碎片化
省时 ⏱️ (高效协作)跨项目改动需要频繁切换仓库,提交多次原子化提交,一次提交即可覆盖所有相关项目改动,提升协作效率。
省空间 💾 (依赖优化)多仓库重复安装相同的依赖依赖提升 (Hoisting),共享依赖安装在根目录,节省磁盘空间
省沟通 💬 (集中透明)联调、排查问题和版本对齐复杂代码集中可见,加速联调、版本同步和问题定位。

🎯最佳使用场景

  • 高内聚性:存在大量内部相互依赖的包/模块(如核心库、工具层、业务组件库)。
  • 标准统一化:需要强制推行统一的代码标准(tsconfig, eslint, prettier)。
  • 联动发布需求:当某个核心包更新时,依赖它的所有包都需要同步发版。

🔍 Monorepo vs. Multi-repo

特性Monorepo (集中式)Multi-repo (分散式)
仓库数量1 个大仓库N 个小仓库
跨包协作非常流畅,本地即可引用复杂,需要发布到 npm 或使用 Link
管理复杂度CI/CD 流程统一CI/CD 流程分散,版本对齐困难

🗂 典型目录结构

minivue/
  packages/
    shared/
    reactivity/
    vue/
  pnpm-workspace.yaml
  package.json

⚠️ 易踩的坑与规避

  • 坑 1:子包缺少 name 或版本 🧱
    • 现象:workspace 无法链接,或 filter 无法命中
    • 解决:每个子包 package.json 必须包含 name;版本可简化为 0.0.0
  • 坑 2:依赖循环 ♻️(A 依赖 B,B 又依赖 A)
    • 现象:构建或运行异常、类型推断混乱
    • 解决:抽取 shared 层打破环,或下沉到更基础的包
  • 坑 3:路径引用混乱 🧭
    • 现象:TS 能过但运行时找不到,或反之
    • 解决:统一使用包名导入(@vue/shared),尽量避免跨包相对路径
  • 坑 4:版本管理失控 📦
    • 现象:部分包忘记升级,导致行为不一致
    • 解决:使用 changeset/自研脚本,或统一 workspace:*

🧰 workspace 玩转 Monorepo

1) 根目录配置(只做一次)🏗️

  • pnpm-workspace.yaml
packages:
  - packages/*
  • package.json 常见配置:
{
  "private": true,
  "packageManager": "pnpm@X.Y.Z",
  "scripts": {
    "build": "pnpm -r --filter ./packages... run build",
    "dev": "pnpm -r --parallel --filter ./packages/reactivity run dev"
  }
}

2) 子包如何相互引用 🔗

  • 在子包 package.json 里:
{
  "dependencies": {
    "@vue/shared": "workspace:*"
  }
}
  • 含义 📝:优先链接本地 workspace 的 @vue/shared,不从 npm 下载。

3) 常用命令 🛠️

  • 安装依赖(根目录执行): pnpm install
  • 按包执行脚本: pnpm --filter @scope/pkg run dev
  • 对全部包执行: pnpm -r run build
  • 只对依赖链执行: pnpm -r --filter @scope/pkg... run build
  • 装其他包 pnpm install @vue/shared --workspace --filter reactivity