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

名词解释

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

背景

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

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

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

详细的可参考 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即为每一个独立的工做区。webpack

如:packages/demo,使用 vue-cliios

cd packages && vue create demo

demo/package.json 配置:git

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

    "publishConfig": {
       "access": "publish" // 若是该模块须要发布,对于scope模块,须要设置为publish,不然须要权限验证
    }
}

yarn workspace

yarn install

安装全部依赖,包含子package依赖,若是子package之间存在相互依赖会经过建立软链的方式引用,而非npm下载,这里可能会影响webpack配置中使用 node_modules 作路径判断的地方。github

yarn install

依赖树关系

yarn workspaces info

安装/删除依赖模块

单个package工做区web

# packageA 安装 axios
yarn workspace packageA add axios

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

root packagevue-cli

# 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的状况下已经能够知足基本须要了。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/