结合 lerna 和 yarn workspace 管理多项目工作流

lljj_x

名词解释

  • 多个项目的代码放在在同一存储库中这种开发策略称之为 Monorepo
  • lerna Babel开发用来管理多包的工具,基于 Monorepo 理念在工具端的实现
  • yarn Facebook 贡献的 Javascript 包管理器
  • commitlint 用来规范git commit信息

背景

vue-json-schema-form 项目中,需要把 libdocdemo 放在同一个项目中管理,彼此独立,又可以相互依赖。

使用 yarn workspace 可以很好的解决上面的问题,搭配 lerna 做npm发布管理。目前大型仓库都使用这种方式,比如 Vue Vuepress 等。

由于 yarn workspacelerna 有较多的功能重叠,这里重叠的部分优先使用 workspace 。最后就是只有发布管理使用了 learn 其它使用 workspace

详细的可参考 https://github.com/lljj-x/vue... 配置。

创建项目

目录结构

├── packages
|   ├── lib
|   |   ├── package.json
|   ├── demo
|   |   ├── package.json
├── package.json
packages 下每个文件夹为一个单独完整的包

package.json配置

{
   "private": true, // 禁止发布
   "repository": "https://github.com/lljj-x/vue-json-schema-form",
   "workspaces": [
       "packages/lib",
       "packages/demo",
       // "packages/*" // 可以单个指定 也可直接配置 *
   ]
}

子package配置

子package即为每个独立的工作区。

如:packages/demo,使用 vue-cli

cd packages && vue create demo

demo/package.json 配置:

{
    "private": true, // 禁止发布

    "publishConfig": {
       "access": "publish" // 如果该模块需要发布,对于scope模块,需要设置为publish,否则需要权限验证
    }
}

yarn workspace

yarn install

安装所有依赖,包含子package依赖,如果子package之间存在相互依赖会通过创建软链的方式引用,而非npm下载,这里可能会影响webpack配置中使用 node_modules 做路径判断的地方。

yarn install

依赖树关系

yarn workspaces info

安装/删除依赖模块

单个package工作区

# packageA 安装 axios
yarn workspace packageA add axios

# packageA 移除 axios
yarn workspace packageA remove axios
packageA 是需要安装依赖的包名,即 package.json 中的 name 字段,而非目录名

root package

# root package 安装 commitizen
yarn add -W -D commitizen

# root package 移除 commitizen
yarn remove -W commitizen

运行单个 package 的scripts 命令

# 运行packageA 的dev命令
yarn workspace packageA dev
# 这里是在每个工作区运行 run build 命令
yarn workspaces run build
Tips:这里运行命令的时候不会检测依赖树关系,只是 package.json 文件 workspaces 配置工作区逐个运行,这里推荐使用 lerna build 见下文 lerna build

到这里对于不需要推送npm的情况下已经可以满足基本需要了。

lerna

目前使用lerna主要来做发布和版本管理

  • 全局安装
npm i -g lerna
  • 初始化一个项目
lerna init

包含两种工作模式:

  1. Fixed/Locked mode (default)

固定模式,默认 packages下的所有包共用一个版本号(version),会自动将所有的包绑定到一个版本号上(该版本号也就是 lerna.json 中的 version 字段),所以任意一个包发生了更新,这个共用的版本号就会发生改变。

  1. Independent mode

独立模式,允许每一个包有一个独立的版本号,在使用 lerna publish 命令时,可以为每个包单独制定具体的操作,同时可以只更新某一个包的版本号。

lerna.json 中的 version 字段指定为 independent 即可,或者 lerna init --independent 命令初始化

lerna.json 文件配置大致如下

{
    "npmClient": "yarn",
    "useWorkspaces": true, // 使用yarn workspaces
    "version": "0.0.1", // 当前版本 或者 independent 独立模式 
    "command": {
        "version": {
            "allowBranch": "master",
            "exact": true,
            "ignoreChanges": [
                "**/*.md"
            ],
            "message": "build: release version %v"
        }
    }
}

lerna clean

清除所用的 node_modules 目录

lerna clean

lerna diff

显示修改内容 类似git diff

lerna diff

lerna ls

列出所有的子package

lerna ls -l

lerna changed

列出修改过的子package

lerna changed

lerna build

build 所有子package,​子package分别执行 build--sort ​参数可以控制以拓扑排序规则执行命令

lerna run --stream --sort build

lerna version

lerna version 的作用是进行 version bump,支持手动和自动两种模式

手动确定新版本

# 按着提示选择版本即可
lerna version

自动确定版本

自动根据 conventional commit 规范确定版本

存在feat提交: 需要更新minor版本
存在fix提交: 需要更新patch版本
存在BREAKING CHANGE提交: 需要更新大版本
# 生成changelog文件以及根据commit来进行版本变动
lerna version --conventional-commits

# 生成changelog文件以及根据commit来进行版本变动,不提示用户输入版本
lerna version --conventional-commits --yes

可参见官方文档 lerna version

version 成功后会自动推送当前分支,可以结合配置 lerna.json文件 commandversion字段 配置允许version的分支,commit 信息等

{
    "npmClient": "yarn",
    "useWorkspaces": true,
    "version": "0.0.1", 
    "command": {
        "version": {
            "allowBranch": "master",
            "exact": true,
            "ignoreChanges": [
                "**/*.md"
            ],
            "message": "build: release version %v"
        }
    }
}

lerna publish

lerna publish 的功能可以即包含version的工作,也可以单纯的只做发布操作。

可参见官方文档 lerna publish

lerna publish

lerna publish 会先调用 lerna version,再确定是否要发布到npm

lerna publish from-git

from-git 基于当前git提交的软件包做发布,一般都是通过 lerna version 提交的版本

lerna publish from-package

from-package 在注册表中不存在该版本的最新提交中发布程序包 (这个我没用过)

lerna 不会发布标记为私有的软件包(package.json"private": true

changelog

根据 conventional commit 提交规范,即可通过工具为每个 package 生成 changelog 文件。

conventional commit 支持

conventional commit规范使用也可以看这个:Commit message 和 Change log 编写指南

安装如下依赖:

yarn add -W -D commitizen cz-conventional-changelog @commitlint/cli @commitlint/config-conventional husky conventional-changelog-cli

commitizen:

一个撰写合格 Commit message 的工具

cz-conventional-changelog:

用于使 commitizen 支持Angular的Commit message格式

配置 package.json 添加如下配置

{
    "config": {
        "commitizen": {
            "path": "./node_modules/cz-conventional-changelog"
        }
    }
}

至此就可以通过 git cz 命令替换 git commit 生成符合格式的Commit message。

git cz 命令出现如下选项

image

@commitlint/cli:
commitlint 用于检查您的提交消息是否符合提交格式,类似 eslint 校验js语法

@commitlint/config-conventional:
commitlint 校验规则,类似 eslint-config-standard

添加并配置 .commitlintrc.js 文件

module.exports = {
    extends: ['@commitlint/config-conventional'],
    rules: {
        ...otherRules // 可以继续配置你的规则
    }
};

husky:
husky是 Git hooks 工具,这里用于在 commit 时校验message内容

配置 package.json 文件,添加如下

{
    "husky": {
        "hooks": {
            "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
        }
    }
}

至此当新提交的commit message 不符合规范便会阻止提交。

conventional-changelog-cli:
根据commit message生成 changelog.md 文件 (这里功能和 lerna version --conventional-commits 生成changelog 有部分重叠,下文会详细区分)。

如:conventional-changelog -p angular -i CHANGELOG.md -s -r 2

注意:这里生成的是整个仓库的 changelog ,而非每个 package生成 changelog

生成changelog

生成changelog 依赖如上 conventional-commit 规范message

整个仓库 changelog

生成自从上次发布以来的变动:

conventional-changelog -p angular -i CHANGELOG.md -w

如果这是您第一次使用此工具,并且想要生成所有以前的变更日志,则可以执行:

conventional-changelog -p angular -i CHANGELOG.md -s -r 0

参见:conventional-changelog-cli

每个package工作区独立 changelog

lerna version 时,自动模式 --conventional-commits 命令会同时为每个package工作区生成 changelog

lerna version --conventional-commits

注: lerna version 成功之后便会为每个 package 生成 changelog,包括 root package

npm scripts

如下:自己常配的一些script

{
    "scripts": {
        "demo:dev": "yarn workspace demo dev",
        "demo:build": "yarn workspace demo build",
        "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 2",
        "clean": "lerna clean && rm -rf node_modules",
        "packages:diff": "lerna diff",
        "packages:list": "lerna ls -l",
        "packages:changed": "lerna changed",
        "packages:build": "lerna run --stream --sort build",
        "publish": "lerna publish",
        "autoPublish": "lerna publish --conventional-commits --yes",
        "version": "lerna version --conventional-commits --yes"
    }
}
  • changelog 生成整个仓库 changelog
  • publish 手动选择版本并发包 (其实我自己平时一般用这个)
  • autoPublish 自动确定版本并发包同时生成每个package changelog
  • version 自动确定版本不发布和生成每个package changelog
参考:https://zhuanlan.zhihu.com/p/...

原文发布在:https://www.lljj.me/

阅读 3.5k

知道的越多就知道的越少

44 声望
3 粉丝
0 条评论
你知道吗?

知道的越多就知道的越少

44 声望
3 粉丝
宣传栏