前言
最近在公司搭建脚手架,使用最近市面上🔥的Monorepo模式进行包管理。原因以下几点:
- 借鉴Vue Cli和CRA
- Cli主要包含base-create、server、utils、plugin几个模块,通过Monorepo,使模块容易拆分、集中管理。
- 开发方便,通过yarn workspace 使模块间的相互引用变得更容易
repo
这里先介绍两种项目代码管理方式(monorepo、multirepo)。
Monorepo 就是将多个项目放在一个仓库中进行管理
monorepo所带来的就是代码集中化管理,各个模块间的相互依赖变得简单、清晰。对于一个大型项目来说,模块的拆分尤为重要,所以我认为对于模块耦合性较高的、或者说多个模块为一个项目服务的情况下,从管理和维护来讲,这个方案是一个不错的选择。当然它也有repo的体积变得很大、权限也不好分配等缺点。
Mutirepo 则相反是放在多个仓库中进行维护
mutirepo带来的就是代码的多元化管理,降低了各个项目或团队的耦合性,每个团队单独作战,维护各自唯一的package,对于独立的项目,也许是不错的管理方式,但也需要考虑重复性工作、团队沟通成本、repo管理成本等影响
借鉴网上的一张图很容易发现两者区别
两种方案各有千秋,需要考虑自己项目、团队的实际情况来进行选择,相信总有一款适合你
lerna
而monorepo的解决方案就是lerna 目前很多开源项目采用lerna来进行项目管理(Babel、vue-cli、create-react-app。。。)
模式
lerna提供两种模式
- Fixed/Locked(默认)
固定模式,项目维护一个版本号,也就是在lerna.json文件中,当运行lerna publish,如果某个模块在上次发布版本之后有了更新,那么他将会更新到新发布的版本,也就意味着你只能在你确定需要更新时才能发布一个新的版本(不能随便发啦!!!)
{
"packages": [
"packages/*"
],
"version": "0.0.0"
}
- Independent 独立模式,它允许Lerna中每个模块独立维护自己的版本号,也将导致你每次发布时,会有一个提示,针对本次更改的包指定他是patch、minor、major或者custom change
{
"packages": [
"packages/*"
],
"version": "independent"
}
命令
这里只介绍几种常用命令,详细请参考官方README。安装就不说了,全局安一下就完了
初始化
lerna init --independent // 模式参数,默认Fixed/Locked
创建子项目
lerna create <name>
顾名思义,该命令是在packages下创建一个新的package。
需要注意的一点是创建的目录是在lerna.json中配置,例子
"packages": [
"packages/@vue/*"
]
添加依赖
$ lerna add <package>[@version] [--dev] [--exact] [--peer]
安装本地或远程依赖包,需要注意的是,一次只能添加一个包(与yarn add 和 npm install不同)
当运行这个命令,lerna到底干了啥
- 会给每一个package返回内的应用安装依赖
- 修改每个应用的package.json文件
参数说明
| 参数 | 说明 |
|---|---|
| --dev | 开发环境依赖包 |
| --scope | 安装范围,当你想在某个应用安装时,应该需要它 |
举个🌰
给packages目录下所有前缀为prefix-的应用安装module-1依赖
$ lerna add module-1 packages/prefix-*
给module-2安装module-1
$ lerna add module-1 --scope=module-2
给所有应用安装module-1
$ lerna add module-1
发布
$ lerna publish
根据提示选择相应发布版本就OK
yarn
yarn相比npm优点
- 速度(并行安装、离线模式)
- 简洁(输出信息更加简洁,结合emoji增加趣味性)
- 更好的语义化 (add/remove)
yarn workspace
yarn workspace允许我们使用Monorepo的形式管理项目,在安装 node_modules 的时候它不会安装到每个子项目的 node_modules 里面,而是直接安装到根目录下面,这样每个子项目都可以读取到根目录的 node_modules。整个项目只有根目录下面会有一份yarn.lock文件。子项目也会被 link 到 node_modules 里面,这样就允许我们就可以直接用 import 导入对应的项目
- 注意 当我们开发node应用 或者不需要对项目进行打包操作,要慎用全局依赖,因为当我们使用lerna publish对项目进行发布时,是将每个子项目单独发布到npm上(也就是最终的依赖以子项目的package.json为准)
开启workspace
{
"name": "root",
"private": true, // 私有的,用来管理整个项目,不会被发布到npm
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^3.22.1"
}
}