monorepo是啥

在版本控制系统中,monorepo是一种软件开发策略,指将多项目的代码存储在同一仓库中。截止2017年,这种软件工程实践的各种形式已经存在了二十多年,但是一般概念直到最近才被命名。
Google,Facebook,Microsoft,Uber,Airbnb,以及Twitter均采用了特别庞大的monorepos,通过多样的策略去扩展用于庞大代码量和日常变更频次的构建系统和版本控制软件
---维基百科 https://en.wikipedia.org/wiki/Monorepo

monorepo与multi-repo

multi-repo的困境

相对于单个仓库来说开启新项目费时费事(创建仓库、项目架构(虽然有脚手架的话会方便些),多个项目汇总管理麻烦)
组件工具依赖复用及更新麻烦
重复安装公共依赖react、react-dom这些有多大都清楚
本地项目调试麻烦,这个项目依赖了另一个项目,那么你只能用 npm link 的方式将它 link 到需要调试的项目里面。一旦 link 的项目多了,手动去管理这些 link 操作就容易心累。

monorepo优势与局限

优势

便于代码复用
简化依赖管理
原子性提交(当一项工作分布在不同的仓库时,发布需要按一定顺序进行,当项目足够大时管理依赖间多样的版本会造成依赖地狱)
大型代码重构,便于确保整体功能重构后的可用性
跨团队协作灵活的代码从属关系,大家都可以参与改进

局限

缺少独立项目的版本信息
缺少独立项目的权限控制
需要更多的默认存储空间

随着前端项目的日益复杂,某些业务或者工具库通常涉及很多个仓库,时间一长,多个仓库(MultiRepo)的开发弊端日益显露,monorepo的管理方式得到了更多应用。

目前很多开源项目都用了 monorepo,比如VUE、REACT、Babel。
大家可以看一下React和Vue3的项目结构:
https://github.com/facebook/react/
https://github.com/vuejs/vue-next

monorepo要解决的问题

如何使同一仓库中的各个项目保持其独立性?

  1. 独立构建、打包、发布
  2. 公共模块及依赖间包的版本升级管理

常见解决方案

  1. 较基础的 Lerna+Yarn Workspaces,提供基本的多包依赖管理及独立发布功能

Lerna 是一个管理多个 npm 模块的工具,是 Babel 自己用来维护自己的 Monorepo 并开源出的一个项目。优化维护多包的工作流,解决多个包互相依赖,且发布需要手动维护多个包的问题。
yarn workspaces 是一种管理软件包的方式,与lerna在包管理上有一部分的功能重合;

yarn workspaces的应用: vue、react
来看看lerna的使用。babel/babel, facebook/jest, alibaba/rax 、taro、umi

在包管理上yarn相对与lerna可以减少包的重复安装,lerna则在分包构建发布上比较有有优势。所以有的项目结合了二者的优点进行了多项目管理的方案设计

2.Rush Stack(微软+开源)、Bazel构建系统 (Google)、Buck构建系统 (Facebook)、Nx等,提供从初始化、开发、构建、测试到部署的全流程能力,有一套比较完整的 Monorepo 基础设施,但定制,适配成本高。

Lerna+Yarn Workspaces实践

这里只根据基础功能列出了包管理生命周期中的关键命令,详细的代码以及lerna包管理实现的原理大家感兴趣的话可以点赞搜藏关注后续分析~~

打包

需求:各package独立打包:有公用打包配置的能力
 //包安装、同时安装各个子包需要的依赖
 yarn install
 yarn workspace cli add cli-shared-utils //将cli-shared-utils作为cli的依赖进行安装
 yarn workspaces add lodash //给所有的package安装依赖:
 yarn add -W -D typescript //给root 安装公用的依赖
 //清理环境
 lerna clean //清理所有的node_modules
 //按顺序构建(各个package之间存在相互依赖,如packageB只有在packageA构建完之后才能进行构建,否则就会出错,需要按拓扑排序的规则进行构建)
lerna run --stream --sort build

升级与发布

两种模式:
Independent mode:结合Git,检查文件变动,只发布有改动的packge。(设置方式1:创建项目的时候 可以通过 lerna init --independent 命令,启用独立模式管理软件包。设置方式2:修改 lerna.json 的 version 字段,修改为 independent, 用来开启独立模式)
Fixed/Locked mode(默认):把工程当作一个整体来对待。每次发布packges,都是全量发布,无论是否修改

//更新版本
//找出从上一个版本发布以来有过变更的 package
//提示开发者确定要发布的版本号
//将所有更新过的的 package 中的package.json的version字段更新
//将依赖更新过的 package 的 包中的依赖版本号更新
//更新 lerna.json 中的 version 字段
//根据commit信息自动生成该版本的CHANGELOG (配置conventionalCommits)
//提交上述修改,并打一个 tag
//推送到 git 仓库
lerna version //更新版本 

//发布新包
lerna publish  //包含了lerna version

lizziebing
82 声望4 粉丝