Source: jsilvax. A Beginner's Guide to Lerna with Yarn Workspaces. Oct/6/2018node
當結合在一塊兒時,Lerna和Yarn Workspaces能夠簡化和優化對多包倉庫的管理。 Lerna 經過提供有用的實用命令來處理跨多個包的任務執行,使版本管理和將包發佈到NPM Org中成爲一種輕鬆的體驗。 Yarn Workspaces 管理咱們的依賴關係。它不須要多個node_modules目錄,而是智能地優化了依賴關係,將他們一併安裝,並容許在一個monorepo中交叉連接依賴關係。Yarn Workspaces提供了像Lerna這樣的工具來管理多包倉庫。git
爲了開始,讓咱們啓用Yarn Workspaces吧github
yarn config set workspaces-experimental true
複製代碼
如今咱們能夠經過建立一個模擬項目來講明這些概念了npm
mkdir my-design-system && cd my-design-system
複製代碼
而後,咱們初始化項目json
yarn init
複製代碼
並將Lerna添加爲開發依賴。bootstrap
yarn add lerna --dev
複製代碼
而後你會想要初始化Lerna,這將建立一個lerna.json和一個包目錄緩存
lerna init
複製代碼
爲了設置Lerna開啓Yarn工做空間,咱們須要配置lerna.json。 讓咱們添加yarn做爲咱們的npm客戶端,並指定咱們使用yarn工做空間。在本教程中,咱們將獨立地版本化咱們的包。markdown
// lerna.json
{
"packages": ["packages/*"],
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true
}
複製代碼
此時咱們應該只有一個根 package.json。在這個根 package.json中,咱們須要添加workspaces和private爲true。將private設置爲true將阻止根項目被髮布到NPM。併發
// package.json
{
"name": "my-design-system",
"private": true,
"workspaces": [
"packages/*"
]
}
複製代碼
須要在包目錄下建立新的包。讓咱們建立一個模擬表單包app
cd packages
複製代碼
一旦咱們進入了正確的目錄,咱們就能夠建立並cd到咱們的新包中了
mkdir my-design-system-form && cd my-design-system-form
複製代碼
而後咱們經過運行 yarn init 來建立一個新的package.json
yarn init
複製代碼
新包的名稱應該遵循咱們的NPM Org scope命名方式,例如:@my-scope-name。 一樣重要的是,新的包要從0.0.0這樣的版本開始,由於一旦咱們使用Lerna進行第一次發佈,它就會發布成0.1.0或1.0.0。
// package.json
{
"name": "@my-scope-name/my-design-system-form",
"version" : "0.0.0",
"main" : "index.js"
}
複製代碼
若是您有一個支持私有包的NPM Org帳戶,您能夠在您的模塊的獨立包.json中添加如下內容。
"publishConfig": {
"access": "restricted"
}
複製代碼
如今咱們知道了建立新包的流程,假設說咱們最後的結構是這樣的。
my-design-system/
packages/
my-design-system-core/
my-design-system-form/
my-design-system-button/
複製代碼
若是咱們想把my-design-system-button做爲依賴關係添加到my-design-system-form中,並讓Lerna將它們進行符號連接,咱們能夠經過cd到該包中來實現。
cd my-design-system-form
複製代碼
而後運行如下內容。
lerna add @my-scope-name/design-system-button --scope=@my-scope-name/my-design-system-form
複製代碼
這將更新@my-scope-name/my-design-system-form的package.json。 咱們的package.json應該是這樣的。
// package.json
{
"name": "@my-scope-name/my-design-system-form",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@my-scope-name/my-design-system-button": "^1.0.0"
}
}
複製代碼
如今,你能夠在index.js中引用這個本地依賴關係,如
import Button from '@my-scope-name/my-design-system-button';
複製代碼
作法和前面的命令相似。不過這是針對/packages/* 的。無論你要加的依賴是本地的同級依賴仍是來自NPM的依賴,都不要緊。
lerna add the-dep-name
複製代碼
若是你有常見的開發依賴,最好在 workspace 的 root package.json中指定。例如,能夠是Jest、Husky、Storybook、Eslint、Prettier等依賴項
yarn add husky --dev -W
複製代碼
*添加-W標誌,就能夠明確表示咱們要把依賴關係添加到工做區根目錄。
若是有一個全部包都使用的依賴,但你想刪除,Lerna有exec命令,能夠在每一個包中運行一個任意命令。有了這些知識,咱們就可使用exec來刪除全部包的依賴關係。
lerna exec -- yarn remove dep-name
複製代碼
Lerna提供了run命令,它將在每一個包含了npm腳本的包中運行該腳本。 例如,假設咱們全部的包都遵循my-design-system-form的結構。
my-design-system-form/
__tests__/
Form.test.js
複製代碼
在每一個package.json中,咱們都有測試的npm腳本。
"name": "@my-scope-name/my-design-system-form",
"scripts": {
"test": "jest"
}
複製代碼
而後Lerna能夠經過運行每一個測試腳原本執行。
lerna run test --stream
複製代碼
*-stream 這個flag提供子進程的輸出。
首先,你須要確保你已經登陸了。你能夠經過如下操做來驗證你是否已經登陸。
npm whoami // myusername
複製代碼
若是你沒有登陸,請運行如下內容並按照提示操做。
npm login
複製代碼
登陸後,您能夠經過運行Lerna發佈。
lerna publish
複製代碼
Lerna會提示你更新版本號。
Lerna支持使用Conventional Commits Standard在CI環境中自動進行語義版本管理。 這使開發人員可以像下面這樣提交
git commit -m "fix: JIRA-1234 Fixed minor bug in foo"
複製代碼
而後在CI環境中,包的版本能夠根據上面的提交更新併發布到NPM。這能夠經過配置你的CI環境來完成。
lerna publish --conventional-commits --yes
複製代碼
若是你不想傳遞flag,能夠在你的lerna.json文件中添加如下內容。
"command": {
"publish": {
"conventionalCommits": true,
"yes": true
}
}
複製代碼
若是你想強制執行 Conventional Commits 標準,我建議在項目的ROOT中加入Commitlint。
yarn add @commitlint/cli @commitlint/config-conventional husky cross-env --dev
複製代碼
而後在根package.json中建立一個發佈腳本
"scripts": {
"release": "cross-env HUSKY_BYPASS=true lerna publish"
}
複製代碼
這個發佈腳本將在CI環境中運行。請注意,咱們在 lerna.json 文件中配置了傳統的提交和 "yes "標誌。因爲這個CI環境將會把版本的變動提交,咱們不但願觸發提交消息的inting。咱們經過添加一個名爲HUSKY_BYPASS的環境變量來實現,咱們將使用cross-env將其設置爲true。 咱們還須要在root package.json中添加進一步的配置。
"husky": {
"hooks": {
"commit-msg": "[[ -n $HUSKY_BYPASS ]] || commitlint -E HUSKY_GIT_PARAMS"
}
},
"commitlint": {
"extends": ["@commitlint/config-conventional"]
}
複製代碼
對於husky,咱們添加了一個commitlint/config-conventional的commit-msg鉤子,它將檢查咱們在上面添加的HUSKY_BYPASS環境變量,若是這個變量是假的,那麼咱們經過@commitlint/config-conventional來精簡提交消息。
若是出於任何緣由,你想徹底掌控版本控制,Lerna有能力將版本控制和發佈分紅兩個命令。 你能夠手動運行。
lerna version
複製代碼
而後按照提示更新各個版本號。 而後你就能夠有一個步驟,讀取最新的標籤(是手動更新的)發佈到NPM。
lerna publish from-git --yes
複製代碼
每當有新的貢獻者對你的項目進行git克隆,或者你須要拉取你團隊的最新變化時,你必須運行yarn命令。
yarn
複製代碼
在大多數的Lerna教程中,提倡使用lerna bootstrap命令,然而當啓用yarn工做空間時,這是沒必要要的,也是多餘的
lerna bootstrap when you're using Yarn workspaces is literally redundant? All lerna bootstrap --npm-client yarn --use-workspaces (CLI equivalent of your lerna.json config) does is call yarn install in the root. — Issue 1308
複製代碼
在咱們的例子中,咱們正在構建一個多包設計系統。若是開發人員想在設計系統中建立一個新的組件,但在發佈以前也要在本地客戶端應用程序中進行測試,他們能夠經過使用yarn的連接命令來實現。
假設咱們想在my-client-app中使用咱們本地的my-design-system-core。 咱們先cd到咱們要在另外一個項目中用到的軟件包。
cd ~/path/to/my-design-system/my-design-system-core
複製代碼
而後咱們建立一個symlink
yarn link
複製代碼
你應該看到這樣的輸出
success Registered "@my-scope-name/my-design-system-core".
info You can now run `yarn link "@my-scope/my-design-system-core"` in the projects where you want to use this module and it will be used instead.
複製代碼
如今咱們的包已經有了符號連接,咱們能夠進入my-client-app中使用。
cd ~/path/to/my-client-app
yarn link @my-scope-name/my-design-system-core
複製代碼
在 /packages/my-design-system-core 中的任何變化都會反映在my-client-app中。如今,開發人員能夠很容易地在兩個項目上進行本地開發,並看到它的反映。
當開發者完成後,再也不想使用本地的包時,咱們須要解除連接。 cd到入咱們要解除連接的包中
cd ~/path/to/my-design-system/my-design-system-core
複製代碼
運行unlink刪除本地symlink
yarn unlink
複製代碼
你會看到這樣的輸出
success Unregistered "@my-scope-name/my-design-system-core".
info You can now run `yarn unlink "@my-scope-name/my-design-system-core"` in the projects where you no longer want to use this module.
複製代碼
如今,咱們能夠cd到my-client-app中解除連接。
cd ~/path/to/my-client-app
yarn unlink @my-scope-name/my-design-system-core
複製代碼
Lerna與Yarn Workspaces是一個很好的組合。Lerna 在 Yarn Workspaces 的基礎上增長了實用功能,用於處理多個包。紗線工做空間使得全部的依賴關係能夠一塊兒安裝,使得緩存和安裝速度更快。它讓咱們能夠經過一個命令輕鬆地在NPM上發佈依賴關係,當依賴關係的版本發生變化時,自動更新兄弟依賴關係的package.json,通常來講,安裝、版本管理和發佈都是一種無痛的體驗。