Lerna 多包管理工具的萌新探索

What is Lerna ?

Lerna 是一个多包管理工具,最初是为了解决跨库调试的问题,后面衍生出比较多的执行命令方便调试和管理。

按照 lerna 文件组织结构,所有的 package 包都在 packages 目录里,外部只保留 package.json 配置文件即可。package 包是个完整的 npm 项目结构。

文件组织结构

my-lerna-repo/
  package.json
  packages/
    package-1/
      package.json
    package-2/
      package.json
复制代码

常用的关键性命令

初始化或升级项目(init)

创建一个 lerna 项目或把已存在的 git 仓库升级为 lerna 项目:

lerna init
复制代码

Lerna 会做两件事:

  • package.json 里的 devDependency 加入 lerna。
  • 创建 lerna.json 配置文件,存储当前 lerna 项目的版本号

创建新包(package)

lerna create newPackageName
复制代码

安装依赖(bootstrap)

所有包在自己的目录里安装依赖,即所有包都有对应其 package.jsonnode_modules 目录,同时 symlink 各个包和二进制包

lerna bootstrap
```该命令会做以下几件事:

1. `npm install` 每个软件包的所有外部依赖项;
2. 将所有 `packages` 相互依赖的Lerna `link` 在一起;
3. 在所有已安装的包里执行 `npm run prepublish`;
4. 在所有已安装的包里执行 `npm run prepare`;

##### --ignore

忽略某些依赖的安装,可以指定命令 `--ignore` 项,当然也可以配置在 `lerna.json` 更为通用。

#### 添加依赖

``` bash
lerna add <package>[@version] [--dev] [--exact] [--peer]
复制代码

添加操作可以使用所有过滤标签

# Adds the module-1 package to the packages in the 'prefix-' prefixed folders
lerna add module-1 packages/prefix-*

# Install module-1 to module-2 in devDependencies
lerna add module-1 --scope=module-2 --dev

# Install module-1 to module-2 in peerDependencies
lerna add module-1 --scope=module-2 --peer
复制代码

提升安装依赖 Hoisting

每个包都有自己的 package.json,安装依赖时都会在每个包里生成 node_modules 目录,通常这些包会有很多重复的依赖。Hoisting 的解决方法是把依赖关系提升到最顶层node_modules 目录,以此减少开发和构建副本包带来的额外时间和空间。

–hoist [glob]

该配置项把依赖安装至根目录,可以指定一个 glob 来避免在所有 packages 里生效。依赖项中的任何二进制文件都将 linknode_modules/.bin/ 目录中,如果未指定 glob,则默认为**(安装所有依赖至根目录)。

–nohoist [glob]
lerna bootstrap --hoist --nohoist = babel- *
复制代码

可以指定 不进行 hoist 的依赖

lerna bootstrap --hoist
复制代码
{
  "version": "0.0.0",
  "command": {
    "bootstrap": {
      "ignore": "component-*"
    }
  }
}
复制代码

运行各个包的 script

运行 lerna run 命令可以执行每个包 package.json 里的 script 同名脚本:

lerna run start # 执行所有包含有 start 的脚本
复制代码

packages/xxx-pk1/package.json


{
  "scripts":{
    "start": "some start command..."
  }
}
复制代码

packages/xxx-pk2/package.json

{
  "scripts":{
    "start": "some start command..."
  }
}
复制代码

xxx-pk1xxx-pk2 里的 start 都将被执行。

指定过滤标记

通过过滤标记过滤不需要执行的包。

lerna run start --scope xxx-pk1 # 只执行 xxx-pk1 里的 start 脚本
复制代码

这里需要注意的是xxx-pk1需要和package.json里的name字段一致,不然在目前的版本会运行错误。

并行执行标记:--parallel

如果有些包执行的比较久,可以指定 --parallel 使用 child processes 来并行处理每个包。

lerna run start --scope xxx-pk1 --scope xxx-pk2 --parallel
复制代码

建议在使用 –parallel 标志时,同时使用 –scope 标志限定范围,过多的子进程会损耗 shell 性能。

Lerna 包版本管理

修改包版本号git push通过 version 命令来实现:

lerna version 1.0.1 # explicit
lerna version patch # semver keyword
lerna version       # select from prompt(s)
复制代码

这里 lerna 会做几件事情:

  1. 确认所有包都是最新包,这里主要通过 git 来确认;
  2. 弹出版本选择提示框,来指定版本号;
  3. 修改包元数据以反映新版本,并在 root 包和每个 package 包中运行适当的生命周期脚本
  4. Commit 那些已更改的 package.json 文件并打上版本 tag
  5. Pushgit 远程仓库;

在执行 version 命令前,需要执行一次 git commit 来记录此次更改。如果没有执行,version 命令将不认为这次有新版本需要发布,强制发布(–force-publish)例外。

强制修改所有版本号: --force-publish

lerna version --force-publish = package-2,package-4 #强制对所有软件包进行版本控制
lerna version --force-publish
复制代码

跳过 Commit/Tag 操作: --no-git-tag-version

默认会提交被修改版本号的 package.json 文件并打版本 tag。

跳过 Push 操作: --no-push

默认会执行 git push 操作,通过 --no-push 可以禁止:

lerna version --no-push
复制代码

两种模式:锁定 vs 独立

Lerna 项目有两种模式:Fixed/Locked mode (default) | Independent mode,他们对应包版本号管理的两种方式。

Fixed/Locked mode (default)

这模式下所有包的版本同步一个主版本号,即 lerna.json 里的 version

{
  "version": "0.0.0"
}
复制代码

Independent mode

该模式下,每个包可以独立维护自己的版本号,如果要指定独立运行模式,在 lerna.json 里指定 version 配置如下:

{
  "version": "independent"
}
复制代码

在 CI 环境下的优化配置

–amend

正常情况,version 命令会生成一次新的 commit 来记录 package.json 里版本号的改变,通过 –amend 选项将改变合并到当前的 commit,并标记 tag,同时会忽略 push 操作。

lerna version --amend
# commit message is retained, and `git push` is skipped.
复制代码

–yes

取消弹框确认提示,所有操作默认通过。

Lerna 的包发布(Publish)

lerna publish              # 发布上次发版发生改变的包
lerna publish from-git     # explicitly publish packages tagged in the current commit
lerna publish from-package # explicitly publish packages where the latest version is not present in the registry
复制代码

Lerna 永不发布被标记为私有的包("private": true in the package.json

每个包的 Publish 配置

每个包通过指定 package.jsonpublishConfig 字段来改变 publish 的一些行为

access

默认情况被 scope 的包(例:@my-scope/app)都是访问受限的,需要指定公共访问。

{
    "publishConfig": {
    "access": "public"
  }
}
复制代码
registry

指定包的发布仓库。

{
"publishConfig": {
    "registry": "http://my-awesome-registry.com/"
  }
}
 
复制代码

lerna.json 配置

{
  "version": "1.1.3",
  "npmClient": "npm",
  "command": {
    "publish": {
      "ignoreChanges": ["ignored-file", "*.md"],
      "message": "chore(release): publish",
      "registry": "https://npm.pkg.github.com"
    },
    "bootstrap": {
      "ignore": "component-*",
      "npmClientArgs": ["--no-package-lock"]
    }
  },
  "packages": ["packages/*"]
}
复制代码
  • version: 当前项目的版本;

  • npmClient:指定安装客户端,模式采用 npm install 安装,可以使用 yarn 代理安装,提升安装速度;

  • command.publish.ignoreChanges:指定一组 globs 数组,在发布时,忽略打到包内;

  • command.publish.message:发布会生成覆盖(假如有–amend 选项)一条 commit ,这里可以自定义 commit 消息;

  • command.publish.registry:指定发布仓库;

  • command.bootstrap.ignore:指定一组 globs数组,来忽略某些依赖的安装;

  • command.bootstrap.npmClientArgs::可以给npm install 传递变量;

  • packages:指定一组 globs 数组,来确定包的位置,默认值:[“packages/*”];

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享