一、为什么现在很多项目都在玩Monorepo?
很多人最近可能听过Monorepo这个词,它本质就是把多个代码包放在同一个Git仓库里,而不是每个包单独开一个仓库。举个生活化的例子:假设你做了三个东西,一个是用来做按钮的UI组件,一个是用来发请求的工具函数,还有一个是前端业务页面。如果用多仓库,你得给这三个分别开三个抽屉,找组件要开第一个抽屉,找工具要开第二个,改组件后还要单独更新工具和页面的版本,特别麻烦;但用Monorepo就像把三个抽屉都放在同一个柜子里,改完按钮组件,工具和页面直接就能用,不用来回折腾发布、安装的步骤,这就是为什么现在越来越多项目用它。
1.1 Monorepo的实际好处
除了刚才说的代码复用,Monorepo还有两个核心好处:一是统一版本,三个包的版本可以一起管,不会出现业务页用的组件还是旧版本的情况;二是协作方便,多人开发的时候,同一个仓库里改东西,不用跨仓库提交,减少沟通成本。
1.2 Monorepo的麻烦事儿
不过Monorepo也不是万能的,它也有麻烦:比如包多了之后,依赖管理会乱,比如工具函数改了,业务页没及时关联;还有就是仓库太大,拉取代码或者执行命令会变慢。这时候就需要一个“大管家”来帮忙,Lerna就是这个管家。
二、Lerna是什么?能解决Monorepo的啥问题?
Lerna是专门给Monorepo做包管理的工具,用Node.js开发,属于前端工程化里常用的小工具,它的核心作用就是把Monorepo里的多个包统一管起来,不用你手动处理每个包的版本、依赖和发布。
2.1 Lerna的核心功能
简单说,Lerna能做三件事:第一,统一所有包的版本,比如你把所有包都更到1.2.0,不用一个个改package.json;第二,处理跨包依赖,比如业务包依赖工具包,Lerna能自动检测,改了工具包后,业务包会自动关联;第三,批量发布,你要发布所有包到npm,Lerna一键就能搞定,不用每个包单独发。
2.2 Lerna适用的场景
不是所有项目都适合用Lerna,它特别适合满足这几个条件的项目:第一,有2个以上需要复用的包(比如UI组件、工具函数);第二,团队人数多,需要多人协作开发;第三,想解决跨包依赖混乱、版本不一致的问题。如果你只是做一个单页应用,没有复用的包,那用Lerna反而会增加负担。
三、Lerna在Monorepo场景下的适配评估
要判断项目是否要加Lerna,得从几个维度来看:首先看项目规模,包越多,Lerna的价值越大;然后看团队协作,多人开发的话,Lerna能减少很多沟通成本;最后看后续扩展性,项目如果未来要加更多复用包,Lerna能适配。
3.1 技术选型的核心判断标准
核心看三个点:第一,现有项目的Monorepo结构是不是已经成型?如果还没搭,用Lerna初始化会更方便;第二,团队会不会用Node.js?因为Lerna是Node生态的,要是团队没人熟Node,可能要花点时间学;第三,有没有批量操作的需求?比如要经常更新多个包的依赖,那Lerna的批量命令能省很多时间。
3.2 Lerna的优缺点分析
优点刚才说了不少,再细化一下:第一,配置简单,初始化只要几个命令,就能自动生成必要的配置文件;第二,功能全,从开发到发布的所有包管理操作都能覆盖;第三,社区成熟,很多项目都在用,遇到问题能找到解决办法。缺点也有:第一,仓库太大的话,命令执行慢,比如lerna list可能要等几秒;第二,对新手不太友好,刚用的时候容易搞混配置文件;第三,不适合单包项目,用了反而累赘。
3.3 Lerna的注意事项
用Lerna的时候要注意这几点:第一,初始化后不要随便改lerna.json里的packages路径,默认是放packages文件夹,改了之后命令会找不到包;第二,依赖要写固定版本,比如"@my/utils": "1.0.0",不要用^或者~,避免拉到旧版本;第三,定期清理废弃的包,删掉后要在根package.json的workspaces里去掉对应路径,不然会占空间;第四,发布前一定要测试,先运行lerna run build,确保所有包能正常构建,别到发布的时候才报错。
四、Node.js生态下Lerna的完整使用示例
这里用单一技术栈(Node.js + Lerna)做示例,每一步都带清晰注释,方便新手跟着操作:
# 第一步:装Lerna,用国内镜像加快下载速度,避免卡
npm install -g lerna --registry=https://registry.npmmirror.com
# 第二步:创建Monorepo的根文件夹,名字随便起,这里叫my-monorepo
mkdir my-monorepo
# 第三步:进入这个文件夹,后面的命令都要在这执行
cd my-monorepo
# 第四步:初始化Lerna项目,会自动生成两个关键文件:lerna.json(存Lerna配置)和根package.json(开启npm workspaces,用来管理多包依赖)
lerna init
初始化完成后,根目录会多一个packages文件夹,用来放所有的子包,接下来我们创建两个子包:一个是公共工具包utils,一个是业务包app:
# 创建utils包,会自动在packages/utils下生成package.json等文件
lerna create utils
# 创建app包,同理生成packages/app
lerna create app
# 让app依赖utils包,这里用Lerna的add命令,自动修改app的package.json,不用手动改
lerna add @my-monorepo/utils --scope=@my-monorepo/app
最后,我们来测试Lerna的版本统一功能:比如把所有包的版本更到1.1.0,只要运行一个命令:
# 统一所有包的版本为1.1.0,Lerna会自动修改每个包的package.json的version字段
lerna version 1.1.0
这个例子里,所有命令都用国内镜像,避免新手遇到网络问题,每一步的注释都说明白做了什么,不会让大家懵。
评论
围绕“Lerna技术选型决策:Monorepo包管理场景下的适配与评估方法”参与讨论