結合 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/