1. 为什么需要Monorepo刚入行那会儿我最头疼的就是管理公司十几个前端项目。每次公共组件库更新版本都要手动同步到各个项目经常漏掉一两个导致线上事故。后来接触了Google的代码管理方式才发现原来他们用一个仓库管理了所有项目——这就是Monorepo的雏形。Monorepo单一代码仓库本质上是一种项目管理策略它把多个相关项目放在同一个代码仓库里管理。比如你可能有前端项目、后端服务、移动端应用、公共工具库等传统做法是为每个项目创建独立仓库MultiRepo而Monorepo则选择将它们集中管理。我经历过最典型的MultiRepo痛点某个核心工具库升级后需要挨个修改20多个项目的package.json版本号。有次漏改了一个边缘项目三个月后排查线上bug时才发现它还在用老版本。而改用Monorepo后所有项目自动引用最新代码这种问题再没出现过。2. 搭建Monorepo基础环境2.1 环境锁定Volta实战去年团队新来的实习生用Node 18跑我们的老项目结果一堆兼容性问题。后来我们全面改用Volta管理Node环境再没出现过我本地是好的这种问题。安装Volta只需要一行命令curl https://get.volta.sh | bash在项目根目录执行版本锁定volta pin node16.14 volta pin yarn1.22这会在package.json生成锁定配置volta: { node: 16.14.2, yarn: 1.22.17 }实测发现Volta比nvm更可靠当你在项目目录执行命令时它会自动切换到你指定的Node版本连npm install都不需要额外操作。我们团队现在所有新项目都强制要求配置Volta环境问题投诉减少了90%。2.2 目录结构设计刚开始用Monorepo时我犯过把所有项目平铺在根目录的错误。后来参考了Vue3的源码结构总结出这套方案. ├── apps/ │ ├── web-admin/ # 后台管理系统 │ └── mobile-app/ # 移动端应用 ├── packages/ │ ├── core-lib/ # 核心工具库 │ └── ui-components/ # 公共组件 ├── scripts/ # 全局脚本 └── package.json # 根配置关键原则业务应用放在apps目录按产品线划分公共模块放在packages目录每个都是独立npm包所有项目使用scope/name命名比如mycorp/web-admin3. 依赖管理与工作区3.1 Yarn Workspaces实战第一次看到node_modules里出现mycorp开头的本地包时我才真正理解Workspaces的威力。在根package.json配置{ private: true, workspaces: [apps/*, packages/*] }执行yarn install后会发生三件事所有重复依赖会被提升到根node_modules本地包会建立软链接就像发布的npm包一样可以跨项目直接引用比如import {Button} from mycorp/ui-components我们有个性能监控SDK被10多个项目共用以前每次更新要手动复制文件现在只需要在packages里修改所有项目立即生效。3.2 依赖优化技巧遇到过最坑的问题是循环依赖。比如A包引用B包B包又引用A包导致构建失败。后来我们制定了三条规则单向依赖原则依赖关系必须形成有向无环图使用yarn workspaces info命令检查依赖树在CI流程中加入依赖检查步骤另一个实用技巧是控制依赖版本。在根目录添加resolutions字段可以强制统一版本resolutions: { react: 18.2.0, react-dom: 18.2.0 }4. 工程化配置方案4.1 统一代码规范接手过从MultiRepo迁移来的项目每个子项目都有自己风格的ESLint配置简直噩梦。现在我们的方案是根目录放基础配置.eslintrc.base.jsmodule.exports { extends: [airbnb, prettier], rules: { react/prop-types: off } }子项目继承配置并扩展module.exports { extends: [../../.eslintrc.base.js], rules: { no-console: error } }配合Husky在提交时自动检查npx husky add .husky/pre-commit yarn lint:staged4.2 智能构建系统用Lerna管理构建时最痛苦的是每次都要全量构建。后来我们引入增量构建方案lerna run build --since main --include-dependencies这个命令只会构建自main分支以来修改过的包及其依赖项。结合TurboRepo后构建时间从原来的15分钟降到平均2分钟。5. 高级应用场景5.1 微前端集成去年我们将公司Portal改造成微前端架构Monorepo成了关键支撑。架构如下packages/ ├── micro-fe-core/ # 微前端运行时 ├── app-shell/ # 基座应用 apps/ ├── product-center/ # 产品中心子应用 └── order-system/ # 订单系统子应用通过Workspaces的特性子应用可以直接引用core包进行联调发布时又能自动分离。配合Lerna的版本管理完美解决了微前端版本协同问题。5.2 移动端多平台管理React Native项目时我们这样组织代码apps/ ├── mobile-ios/ ├── mobile-android/ packages/ ├── native-core/ # 平台无关逻辑 └── native-bridge/ # 平台特定实现通过lerna add建立依赖关系lerna add mycorp/native-core mycorp/mobile-ios mycorp/mobile-android这种结构下业务逻辑写在native-core平台差异由bridge处理双端代码复用率达到85%。6. 迁移实战指南6.1 已有项目迁移上周刚帮兄弟部门迁移他们的客服系统总结出这套流程使用lerna import导入已有项目lerna import ~/projects/legacy-system --destapps/legacy修正依赖引用lerna add mycorp/shared-utils apps/legacy逐步重构第一阶段物理共存逻辑独立第二阶段抽离公共模块到packages第三阶段建立项目间依赖关系6.2 常见避坑指南踩过最深的坑是Git性能问题。当代码量超过5GB后常规Git操作变得极慢。最终解决方案使用git sparse-checkout按需加载添加.gitignore规则忽略构建产物定期执行git gc压缩历史另一个痛点是IDE卡顿。VSCode用户建议关闭自动索引files.watcherExclude: { **/.git/objects/**: true, **/node_modules/**: true }