Lerna笔记

2,323 阅读5分钟

lerna

Lerna 是一个用来优化托管在 Git/NPM 上的多 package 代码库的工作流的一个管理工具,可以让你在主项目下管理多个子项目,从而解决了多个包互相依赖,且发布时需要手动维护多个包的问题。

解决场景

// module-1 package.json
{

    "name": "module-1",
    
    "version": "1.0.0",
    
    "dependencies": {
    
        "module-2": "^1.0.1"
    
    }

}

// module-2 package.json
{
    "name": "module-2",
    "version": "1.0.1",
    "dependencies": {}
}

如上所示,module-1依赖于module-2的。当module-2修改后,需要做如下操作:

  1. 修改module-2版本号,发布。
  2. 修改module-1的依赖关系,修改module-1的版本号,发布。

如何使用lerna

安装

yarn global add lerna

初始化文件结构

// 配置文件
 - packages(目录)
 - lerna.json(配置文件)
 - package.json(工程描述文件)
 
// 文件结构
--packages
	--module-1
		package.json
	--module-2
		package.json
--lerna.json
--package.json

lerna.json

{
  "version": "1.0.0",
  "npmClient": "yarn",
  "command": {
    "publish": {
      "ignoreChanges": ["ignored-file", "*.md"]
    },
    "version": {
      "conventionalCommits": true
    }
  },
  "packages": [
    "packages/*"
  ],
  "ignoreChanges": [
    "**/*.md"
  ]
}
  • version: 当前仓库版本,当设为independent时开启独立模式
  • npmClient: 执行命令的client,默认为npm,可以设为yarn
  • command:指令预设
    • command.bootstrap: 对bootstrap指令预设。如设置hoist属性为true可以把所有模块的依赖包提升到根目录。
    • command.publish.ignoreChanges: 设置不会包含进lerna change/publish操作的文件路径,使用它来避免一些非重要改动时的版本更新,比如更新README.md中的拼写错误。
    • version:对lerna version(包含publish过程)进程设置。
      • conventionalCommits:生成CHANGELOG
  • packages:用于定位package的文件路径
  • useWorkspaces: 在所有workspaces所匹配的项目路径下会执行统一的yarn命令,包含测试、安装依赖或执行脚本。默认为false。同时依赖包会提升到根目录,子包会依赖根目录到模块。
  • ignoreChanges:忽略某些文件的变动。

工作模式

Fixed/Locked mode (default)

在publish的时候,会在lerna.json文件里面"version": "0.1.5",依据这个号,进行增加,只选择一次,其他有改动的包自动更新版本号。

Independent mode

每次publish时,您都将得到一个提示符,提示每个已更改的包,以指定是补丁、次要更改、主要更改还是自定义更改。

命令

创建或者改造为lerna项目

lerna init

创建一个包

lerna create package-a

// 创建一个b,放在package-b目录下面(package-b需要先在根目录的workspaces中指定)

lerna create b pakcage-b

添加所有package中的依赖

lerna add dep-name

// 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
lerna add module-1 --scope=module-2

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

// Install module-1 in all modules except module-1
lerna add module-1

// Install babel-core in all modules
lerna add babel-core

列出所有的包

lerna list

导入本地已经存在的包

lerna import /xxx/xxx/xx

移除所有package中的依赖

lerna exec -- yarn remove dep-name

给指定package中添加依赖

lerna add dep-name --scope module-a

移除指定package中的依赖

lerna目前并没有remove这种命令,需要在对应package的package.json中删除对应依赖,然后执行lerna bootstrap即可。

在package-a中引入package-b

lerna add package-a --scope package-b

执行所有package中的script命令

// 指定test指令
lerna run test --stream

运行任意命令在每个包

lerna exec -- < command > [..args] # runs the command in all packages
lerna exec -- rm -rf ./node_modules
lerna exec -- protractor conf.js
lerna exec --scope my-component -- ls -la

执行指定package中的script命令

lerna exec --scope package-a -- yarn run dev

项目包建立软链

lerna link

删除所有包的node_modules目录

lerna clean

列出下次发版lerna publish 要更新的包

lerna changed
  1. 需要先git add,git commit 提交。
  2. 然后内部会运行git diff --name-only v版本号,搜集改动的包,就是下次要发布的

发布

对更新后的包发布新版本;使用新版本号标记;升级所有npm和git中的库

lerna publish [--npm-tag [tagname], --canary/-c, --skip-git, --force-publish [packages]]

// 发布alpha测试版本
lerna publish --pre-dist-tag alpha prerelease

// 强制升级发包
lerna publish --force-publish

// 发布正式patch版本
lerna publish --force-publish --pre-dist-tag latest patch

如果包名是带scope的,如name: @vue/cli,需要在该包的package.json下指定:

 "publishConfig": {
    "access": "public"
  }

lerna publish过程:

  1. 调用lerna version
  • 找出从上一个版本发布以来有过变更的 package
  • 提示开发者确定要发布的版本号
  • 将所有更新过的的 package 中的package.json的version字段更新
  • 将依赖更新过的 package 的 包中的依赖版本号更新
  • 更新 lerna.json 中的 version 字段
  • 提交上述修改,并打一个 tag
  • 推送到 git 仓库
  1. 使用 npm publish 将新版本推送到 npm

设置指定版本

lerna version 1.0.1 # 明确的
lerna version patch # semver 关键字
lerna version       # 从提示中选择

lerna version [major | minor | patch | premajor | preminor | prepatch | prerelease]
# 使用下一个语义版本值,这将跳过“为…”选择新版本的提示

其它指令

  • lerna bootstrap[--independent/-i]: lerna bootstrap,install+模块软链
  • lerna import : 将本地路径中的包导入到packages/,并提交操作记录

其它配套的依赖

  • commitizen:格式化提交格式。
  • cz-lerna-changelog:lerna定制的提交规范。package添加如下配置:
{
  "name": "root",
  "private": true,
  "scripts": {
    "c": "git-cz"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-lerna-changelog"
    }
  },
  "devDependencies": {
    "commitizen": "^3.1.1",
    "cz-lerna-changelog": "^2.0.2",
    "lerna": "^3.15.0"
  }
}
  • husky:拦截继承git hook,自定义钩子脚本

一些约定

采用 Monorepo 结构的项目,各个 package 的结构最好保持统一

  • package 入口统一为 index.js
  • 各 package 源码入口统一为 src/index.js
  • 各 package 编译入口统一为 dist/index.js
  • 各 package 统一使用 ES6 语法、使用 Babel 编译、压缩并输出到 dist
  • 各 package 发布时只发布 dist 目录,不发布 src 目录
  • 各 package 注入 LOCAL_DEBUG 环境变量, 在index.js 中区分是调试还是发布环境,调试环境 ruquire(./src/index.js) 保证所有源码可调试。发布环境 ruquire(./dist/index.js) 保证所有源码不被发布。

参考文章