Lerna 是一个 npm 模块管理工具,为项目提供了集中管理包的目录模式,如统一的 repo 依赖安装,package scripts 和 发布等特性
安装lerna,推荐全局安装:
npm i -g lerna
// mac 可能要加 sudo 管理員權限
sudo npm i -g lerna
monorepo 的全称是 Monolithic Repository, 是一种管理项目代码的方式,顾名思义就是只有一个仓库
以往项目中,对于不同模块通常就是键多个各自的仓库,然后各自做维护等,但是这样的坏处就在于,对于维护不是特别的方便如果想去查看别的模块的代码或者逻辑,或是一个需求涉及到多个模块的改动,那我们就必须去不同仓库查找,修改,并且可能又要各自部署,过程中会出现很多的差错,追根究底就是以为这样传统管理代码的方式过于分散,模块之间的联系不够集中
于是就诞生了 monorepo 的代码管理模式,就是在一个项目仓库(repo)中管理多个模块/包(package),不同于传统的每个模块分别建立一个仓库(repo)
目前不少大型开源项目都采用 monorepo 的方式,像是 babel, react, vue 都是,monorepo 只需要搭建一套脚手架,就可以做到构建、测试、发布多个package
目前最常见的 monorepo 解决方案是 Lerna 加上 yarn 的 workspaces 特性,基于 lerna 和 yarn workspace 的 monorepo 工作流。由于 yarn 和lerna 在功能上有较多的重叠,我们可以采用官方推荐的做法, 用 yarn 来处理依赖问题,用 lerna 来处理发布问题(发布到npm上)
初始化目录
首先创建项目,并安装相应的依赖
mkdir my-app && cd my-app
yarn init -y
yarn add -D lerna # 安装 lerna 为开发依赖
lerna init # 调用 lerna 初始化命令,生成 lerna.json 文件,创建 packages 目录
修改配置文件
执行 lerna init 命名后会生成默认的 lerna.json 文件,内容如下:
{
"packages": [
"packages/*"
],
"version": "0.0.0"
}
默认情况下 lerna 并不会使用 yarn workspaces,我们需要在lerna.json文件修改下配置:
修改1
{
"packages": [
"packages/*"
],
"version": "independent", // 【独立模式】每个包都有自己独立的版本号
"npmClient": "yarn", // 执行命令的client,默认为npm,我们设置为 yarn
"useWorkspaces": true, // 开启工作区模式 用 yarn workspaces 进行依赖管理
"message": "chore(release): publish" // lerna version 默认使用的 commit message 不符合 conventional commit 规范,修改一下
}
Lerna 的两种模式
Fixed(固定模式): 默认。所有package 共用一个版本号,比如:babel 任何 package 的 major change 均会>导致所有包都会进行 major version的更新
Independent(独立模式): 每个包都有自己独立的版本号。lerna会配合git,检查文件变动,只发布有改动的>package
修改2
同时将 package.json 中的 private 字段设置为 true,加入 workspaces 字段,并删除 version 、 main 等无用字段:
{
"private": true, ```// 私有的,不会被发布,是管理整个项目,与要发布的npm包解耦,避免 root 被发布出去
"workspaces": [ // 指定workspace路径
"packages/*"
]
}
创建 package
可以使用 lerna create 命令快速创建新的 package:
lerna create <my-package> 或者 lerna create <my-package> -y
在新建的 package 的 package.json 文件中,加入 publishConfig 字段:
{
...
"publishConfig": {
"access": "public" # 带 scope 的包需要设置为 public
}
}
安装依赖
默认所有依赖都会被安装在根目录下的 node_modules 中,如果不同 package 的依赖有版本冲突问题,就会放在 package 的 node_modules 中。
根目录下有一个 package.json 文件,各个 package 中又有自己的 package.json 文件,这时候其实依赖也可以分为全局和包两种级别了。
对于 devDependencies 依赖,装在全局还是包中其实区别不大,只是放在根目录下的 package.json 中方便统一维护版本,避免重复安装。
如果不同包对于某个 devDependencies 依赖没有特定的版本要求的话,建议直接装在根目录下。
但是 dependencies 就需要注意一下了, lerna 在发布时,会直接将 package 下的 package.json 原封不动发布出去,如果把 dependencies 写在根路径下的 package.json 中,开发的时候没有问题,但是发布出去被别人引用时,就缺失依赖了。
所以结论就是,对于 devDependencies 依赖,建议尽量装在根目录下:
yarn add <some-dev-dependency> -W -D
对于 dependencies ,在各个 package 中自行维护:
yarn workspaces <some-package> add <some-dependency>
yarn的workspace的常用命令
1、安装所有工作区依赖
// yarn install # 等价于 lerna bootstrap --npm-client yarn --use-workspaces
yarn install
2、根工作区安装依赖,在monorepo模式中,根工作区一般只有开发依赖,如测试、开发服务等
yarn add <pkg_name> -W -D
# 安装完成后,在根目录下的package.json中的devDependencies中,可以看到安装的依赖
# 但是在其他的package.json中的devDependencies中看不到安装的依赖的,但是可以使用
3、所有工作区安装共同的依赖
yarn workspace add <pkg_name> 没有这个命令,报错yarn workspace v1.22.19 error Unknown workspace "add".
4、给指定工作区安装指定的依赖
yarn workspace <workspace_name> add <pkg_name>
// 將 packageA 作為 packageB 的依賴進行安裝
yarn workspace [packageB的package.json中的name] add [packageA的package.json中的name]@版本号
yarn workspace @qwd/broswer add @qwd/core@1.0.0
5、类似的,删除依赖如下
yarn <add|remove> <pkg_name> -W -D
# -W: --ignore-workspace-root-check ,允许依赖被安装在workspace的根目录
# -D:作为devDependencies依赖安装
# -W -D 必须放在命令尾部,否则报错【yarn remove v1.22.19
# error Not enough arguments, expected at least 1.】 这一点没有npm 灵活
# 例子:管理根目录的依赖。
# 安装eslint作为根目录的devDependencies
yarn add eslint -D -W
yarn workspace remove <pkg_name> 没有这个命令,报错yarn workspace v1.22.19 error Unknown workspace "remove".
yarn workspace <workspace_name> remove <pkg_name> // 删除某一个workspace_name下的依赖
6、运行指定工作区的脚本命令
yarn workspace <workspace_name> run <script_name>
7、使用 yarn workspaces 的一个好处,就是可以快速调用所有 package 的某个命令,例如:
yarn workspaces run clean // 调用所有 package 的 clean 命令
# 这个命令执行的前提是需要在所有的包下的package.json文件中配置上clean命令才行
# 例如:在根目录的 package.json 中加入一些常用的命名:
{
"scripts": {
"build": "lerna run --stream --sort build", // 按照依赖拓扑进行构建
"clean": "yarn workspaces run clean", //这里配置了clean 命令 彼此独立,可以并行执行
"test": "yarn workspaces run test"
}
}
lerna常用命令
# 使用 lerna 标记版本,会根据哪些文件有变动,来提示你将哪些包的版本进行修改
# 并进行一次 git commit 提交,打上相应的 git tag
# 1. 更新包版本
# 2. git commit 和 git tag
# 3. 推送到 remote
lerna version
# 在上一步的基础上,生成 changelog 文件,以及根据 commit 来自动进行版本变动
lerna version --conventional-commits --yes
# lerna version 成功后,就可以使用 publish 命令发布到 npm 仓库中了
# 相当于 lerna version + lerna publish from-git
lerna publish
# 发布当前 commit 中打上 tag version 的包
lerna publish from-git
# 例如:如果 package1 必须在 package2 build 之后才能被 build,那么我们就要将 package1 作为依赖
# 添加到 package2 的 package.json 中。至于选择添加到 dependencies 还是 devDependencies 都可以,
# 取决于具体需求场景,但两者都是可以被 lerna 正确解析的拓扑结构
# 最后当拓扑结构都配置好后,我们就通过 lerna 提供的一个 --sort 参数告诉 lerna 要以拓扑顺序的方式
# 执行每一个 package的某脚本
lerna run --sort build
# 发布 package.json 中的 pkg.json 上的 version 在 registry(高于 latest version) 不存在的包
lerna publish from-packages
# yarn workspace负责一些依赖包的管理工作,最后发布到npm的时候,还是推荐使用 lerna 来进行发布
# 至于后面要不要跟设么参数,再碰到需要的时候,去根据实际情况去百度吧
lerna publish [param]
lerna bootstrap // 安装所有依赖项并链接任何交叉依赖项
//例: lerna bootstrap --npm-client yarn --use-workspaces
lerna exec // 在每个包中执行任意命令
//例: lerna exec 'yarn remove lodash' // 删除
lerna add // 安装依赖,支持交叉依赖
// lerna add packageA --scope=packageB
lerna add lodash // 为所有 package 增加 lodash 模块
// 为 @monorepo/utils 增加 lodash 模块
lerna add lodash --scope @monorepo/utils
// 为 @monorepo/utils 增加 内部模块@monorepo/components
lerna add @monorepo/components --scope @monorepo/utils
// 版本发布
lerna changed // 检查自上次发布以来哪些软件包已经更新
lerna diff // 自上次发布以来,对所有包或单个包进行区分
lerna publish // 发布版本
// 常用
lerna clean // 清除项目中所有 node_modules
lerna init // 初始化项目
lerna create // 创建项目中的子package
// 其它
lerna run // 在包含该脚本的包中运行 npm 脚本
lerna info // 查看信息
lerna import // 导入
lerna link // 软链
lerna version // 查看版本
lerna ls // 列出当前 lerna 项目中的公共包
Yarn Workspace与Lerna
Lerna 是社区主流的monorepo管理工具之一,集成了依赖管理、版本发布管理等功能。
使用Lerna管理的项目的目录结构和yarn workspace类似
Lerna的依赖管理是也基于yarn/npm,但是安装依赖的方式和yarn workspace有些差异:
Yarn workspace只会在根目录安装一个node_modules,这有利于提升依赖的安装效率和不同package间的版本复用。而Lerna默认会进到每一个package中运行yarn/npm install,并在每个package中创建一个node_modules。
目前社区中最主流的方案,也是yarn官方推荐的方案,是集成yarn workspace和lerna。使用yarn workspace来管理依赖,使用lerna来管理npm包的版本发布