Lerna 是什么
A tool for managing JavaScript projects with multiple packages.
Lerna 是一个管理工具,用于管理包含多个软件包(package)的 JavaScript 项目。
解决什么问题
为了代码共享, 大型项目会将代码分成多个代码仓库为独立的包(package).
如果某个包更改, 需要反向要求依赖该包的包升级依赖版本, 包少的时候还不是很成问题, 但当依赖链错综复杂时, 这个升级依赖的过程会极为痛苦.
为了解决这个问题, 如 Babel, React 等项目会将多个包放到一个代码仓库进行管理, 此种管理方式称为: Monorepo. Lerna 是一个优化 Monorepo 工作流的工具.
Lerna 工作模式
一个仓库下有多个包, 那么每个包的版本号如何管理?
Lerna 支持两种模式: Fixed/Locked mode (default) 和 Independent mode 前者是所有包使用同一个版本号, 后者是每个包独立版本号.
lerna.json
含有配置项 "version": "independent"
表示使用 Independent mode.
否则 lerna.json
中的 version
即为所有包的共用版本号.
lerna init
默认初始化为 Fixed/Locked mode, 推荐使用.
独立版本号会导致版本依赖关系错综复杂, 长期维护会混乱.
如何使用
安装
npm install --global lerna
初始化项目
git init lerna-repo && cd lerna-repo
lerna init
得到的目录结构
lerna-repo/
packages/
package.json
lerna.json
常用命令
lerna init
初始化 或 升级 当前仓库为 lerna 模式.
lerna bootstrap
安装子包依赖. 相当于每个子包下执行 npm i
.
根目录的依赖并不会安装.
lerna create <name>
新增子包
lerna add <package> [–dev] [–scope=module]
新增依赖, 默认会在每个包中添加对应依赖. 通过 --scope
参数指定仅特定包增加此依赖.
lerna run [script]
每个子包中执行对应的script命令.
lerna exec
每个子包中执行对应的命令. 例: lerna exec -- ls
与 lerna run
的区别在于执行的命令是 shell 不是 package.json 中的 scripts.
lerna version
创建新的版本. 会自动维护跟目录及子包package.json中的版本号, 子包直接的依赖版本号也会自动更新.
lerna clean
删除所有子包中的 node_modules 目录. 根目录的 node_modules 不会删除.
更优体验 = Lerna + Yarn
配置 lerna 使用 yarn 管理依赖
在 lerna.json
中配置 "npmClient": "yarn"
即可.
配置 lerna 启用 yarn Workspaces
- 配置
lerna.json/useWorkspaces = true
; - 配置根目录
package.json/workspaces = ["pacages/*"]
, 此时 lerna.json 中的packages
配置项将不再使用; - 配置根目录
package.json/private = true
;
上面三个配置项需同时开启, 只开启一个 lerna 会报错.
此时执行 lerna bootstrap
等价于 lerna bootstrap --npm-client yarn --use-workspaces
等价于 yarn install
由于 yarn 会自动 hosit
依赖包, 无需再 lerna bootstrap
时增加参数 --hoist
(加了参数 lerna 也会报错)
依赖管理
安装在根目录: yarn add -W xxx
安装包: yarn workspace <module> add xxx
or lerna add --scope=<module> xxx
为所有子包安装包 lerna add xxx
or lerna exec -- yarn add xxx
删除根目录包: yarn remove -W xxx
删除包: yarn workspace <module> remove xxx
or lerna exec --scpope=<module> -- yarn remove xxx
为所有子包删除包 lerna exec -- yarn remove xxx
Lerna 与 Yarn 分工
包管理的能力交给Lerna, 如版本管理; 依赖管理的能力交给Yarn, 如依赖包的安装删除;
常见问题
如何使用 yarn
learn.json 中配置 “npmClient": "yarn"
子包之间如何依赖
直接安装对应包即可.
lerna add xxx [–scope=module]
子包共用dev包
比如 eslint/typescript/husky 等包没必要安装多份.
npm i xxx --save-dev
yarn add xxx --dev -W
注意 -W
参数.
如何删除依赖
learn exec [--scope=module] -- npm uninstall xxx
learn exec [--scope=module] -- yarn remove xxx
yarn workspace <module> remove xxx
避免共用依赖安装多份
建议使用 yarn 会有更好体验, 以下文字针对 npm 场景.
如所有子包都依赖 lodash
, 每个子包的node_modules都会安装一份会浪费磁盘空间.
可以通过 lerna bootstrap --hoist
将共用的包安装到根目录的 node_modules
目录.
--hosit
参数不适用 yarn, 但其实 yarn 会自动优化避免包被安装多份.
可以配置 lerna.json/command.bootsrap.hoist = true
以省去每次都输入 --hoist
参数.
参考文档
官方文档: https://lerna.js.org/ 基于lerna和yarn workspace的monorepo工作流 lerna+yarn workspace+monorepo项目的最佳实践