脚手架系列
脚手架系列 - 比较 lerna 和 lerna + yarn workspace 和 pnpm
lerna 可以做的事
- 初始化lerna项目
- 包管理 涉及 add link bootstrap create 命令
- 批量执行命令
- 批量更新版本
- 批量发布
脚手架系列 - Lerna 使用介绍这节的最后一段,我们提到lerna包管理的一些问题:
-
lerna add\clean\bootstrap 命令都是只对packages下项目有效,所以新拉项目安装依赖,需要
npm install + lerna bootstrap
一起才能安装上所有依赖 -
lerna add 为 packages 下对应项目安装独立 node_modules ,不会在根目录下安装, 即
不存在提升
,所以相同依赖包会在每个package下重复安装一份 -
需要在根目录 node_modules 安装包要用 npm install
所以,普遍会使用 yarn workspace
包管理 代替 lerna 包管理这部分,于是lerna + yarn workspace 一起用,lerna 只管发布这部分
- yarn 处理依赖安装工作(只想做好包管理工具);
- lerna 处理发布流程。
- 会提交到git 仓库
- 会在git仓库打tag
- 会发布到npm 仓库
yarn workspae 和 lerna
配置
- 在
lerna.json
中声明使用yarn workspace
进行依赖管理:
{
...
"npmClient": "yarn",
"useWorkspaces": true
}
- 在
root/package.json
下必需包含workspaces
数组,与lerna.json
下的packages
保持一致:
{
"private": true, // 工作空间不需要发布
...
"workspaces": ["packages/*"]
}
yarn install
代替 npm install + lerna bootstrap
-
相同包提升到 根目录 node_modules
-
指向内部项目 npm link 软连接
yarn [workspaces / workspace] add / remove
- 为每个 package 都安装指定依赖:
yarn workspaces add react // 为每个 packages/package.json 都增加依赖项
yarn add react // 根目录 package.json 增加依赖项
- 为指定的 package 安装特定依赖:
yarn workspace package1 add react react-dom // package1 是包名 部署文件夹名
yarn workspace package1 add package2 // package1 依赖 package2
lerna add [内部未发布的包] --scope [安装到目标包] // 因为未发布的包使用yarn workspace会报错
yarn run [workspaces / workspace]
yarn run test // 运行 根目录 package.json 中 test 命令
yarn workspaces run test // 运行所有 packages 下 package.json 的test命令
yarn workspace package1 run test // 运行 package1 的 package.json 中的 test 命令
为什么要用lerna 的 publish呢
因为 yarn workspaces publish 没有这个命令,所有publish还是用lerna的
关于 Babel 放弃 lerna 的解释
1. we have been running on a patched lerna version for years, because lerna doesn't support anymore publishing only changed packages while keeping the versions in sync
2. Yarn workspaces are way faster than `lerna bootstrap` in this repository
3. We needed to use Yarn's `workspace:` protocol, but lerna doesn't support it
4. We were using a very small subset of Lerna's features
yarn workspace 有什么问题呢
在
yarn + lerna 中的方案是配置自动抬升,这种方案会存在依赖滥用的问题,因为抬升到顶层后是没有任何限制的,一个依赖可能加载到任何存在于顶层
node_modules 存在的依赖,而不受他是否真正依赖了这个包,这个包的版本是多少的影响。
就是说,比如packages/项目 的package.json中没有依赖包,但是因为所有包都提升到顶层了,所以所有项目都可以使用没有依赖的包,这样单独安装项目后,就会报错
monorepo 方案的劣势
- 项目粒度的权限管理变得非常复杂:无论是 Git 还是其他 VCS 系统,在支持 monorepo 策略中项目粒度的权限管理上都没有令人满意的方案,这意味着 A 部门的 a 项目若是不想被 B 部门的开发者看到就很难了。(好在我们可以将 monorepo 策略实践在「项目级」这个层次上,这才是我们这篇文章的主题,我们后面会再次明确它);
- 新员工的学习成本变高:不同于一个项目一个代码仓库这种模式下,组织新人只要熟悉特定代码仓库下的代码逻辑,在 monorepo 策略下,新人可能不得不花更多精力来理清各个代码仓库之间的相互逻辑,当然这个成本可以通过新人文档的方式来解决,但维护文档的新鲜又需要消耗额外的人力;
- 对于公司级别的 monorepo 策略而言,需要专门的 VFS 系统,自动重构工具的支持:设想一下 Google 这样的企业是如何将十亿行的代码存储在一个仓库之中的?开发人员每次拉取代码需要等待多久?各个项目代码之间又如何实现权限管理,敏捷发布?任何简单的策略乘以足够的规模量级都会产生一个奇迹(不管是好是坏),对于中小企业而言,如果没有像 Google,Facebook 这样雄厚的人力资源,把所有项目代码放在同一个仓库里这个美好的愿望就只能是个空中楼阁。