一、項目中遇到的問題
最近在開發小程序的UI庫,組件拆分力度比較細,都是一個個的單獨的package包, 模塊的復用性和靈活性達到最大化,實操的過程中,會遇到以下問題:
1、維護成本較高,任何的基層 repo 版本變更,將會引發一系列上層封裝版本變動
2、版本發布npm包,代碼不夠規范,很多都不是發布master
3、一個包一個repo,每次需要找到對應的倉庫
4、changelog 梳理異常折騰,有些基本上都沒有changelog
基於上面的問題,有沒有一種能解決我們問題的技術呢?
二、Monorepo 項目管理
Monorepo 的全稱是 monolithic repository,即單體式倉庫,與之對應的是 Multirepo(multiple repository),這里的“單”和“多”是指每個倉庫中所管理的模塊數量。
Multirepo 是比較傳統的做法,即每一個 package 都單獨用一個倉庫來進行管理。例如:Rollup, ...,上面遇到問題的也是采用的這種方式。
Monorep 是把所有相關的 package 都放在一個倉庫里進行管理,每個 package 獨立發布。例如:React, Angular, Babel, Jest, Umijs, Vue ...
Multirepo和Monorep優劣勢對比如下:
三、Monorepo 管理工具Lerna
Lerna 是一個管理多個 npm 模塊的工具,是 Babel 自己用來維護自己的 Monorepo 並開源出的一個項目。優化維護多包的工作流,解決多個包互相依賴,且發布需要手動維護多個包的問題。
Lerna 現在已經被很多著名的項目組織使用,如:Babel, React, Vue, Angular, Ember, Meteor, Jest 。
1、lerna模式
在初始化一個項目之前我們必須要清楚,lerna 對管理 monoRepo 有兩種模式
- Fixed/Locked mode (default)
- Independent mode
Fixed/Locked 模式
: 官方默認推薦模式,當前 babel 的項目管理模式,在該模式下所有的 packages 都會遵循一個版本號,該版本號維護在 lerna.json
的 version 字段中,當需要版本發布時 lerna publish
時,如果一個模塊和上一次 release 相比有過變更的話,會自動發布一個新版本。
這種模式的問題在於:當有一個 major 變更的時候,所有 packages 都會都會有一個新的 major 版本。
維護團隊認為:版本是一種非常 cheap 的東西,所以不必糾結。
Independent 模式
: 在該模式下所有 packages 新版本的生成將會由開發者決定,lerna.json
的 version 字段也會隨之失效。這種模式的弊端非常明顯,開發者必須要非常清晰該發什么版本,事實上在多人協作項目上很難做到這一點。
2、如何使用lerna
a、全局安裝lerna
npm i -g lerna
b、初始化項目
mkdir lerna-repo && cd $_
npx lerna init
初始目錄如下,接着進行開發
c、建立 packages 的依賴關系
lerna bootstrap
這個命令會安裝好所有 packages 的依賴,以及建立好 packages 相互依賴的軟連接
正式流程為:
- 安裝所有 package 的外部依賴.
- 對存在相互依賴的 package 創建軟連接.
- 在所有已經 bootstrapped 的 package 中執行 npm run prepublish.
- 在所有已經 bootstrapped 的 package 中執行 npm run prepare.
當然我們使用 --hoist 來把每個 package 下的依賴包都提升到工程根目錄,來降低安裝以及管理的成本。
lerna bootstrap --hoist
如果以前安裝了依賴,發生改動,可以先清理一下安裝的依賴即可:
lerna clean
d、發布版本
lerna publish
正式流程為:
- 執行 lerna updated 來確定哪些包需要被發布.
- 如有必要會升級 lerna.json 的 version 字段。
- 對所有需要 update 的 package 進行版本的更新,並寫入他們的 package.json.
- 對所有需要 update 的 package 進行依賴申明 specified with a
caret (^)
. - 創建一個 git commit 和 tag
- 把包發布至 npm
四、生成changelog
由於本項目后期需要對外,使用基於PR來生成changelog的lerna-changelog,項目建議使用cz-lerna-changelog 。
1、安裝lerna-changelog
npm install lerna-changelog --save-dev
2、修改 lerna.josn
需要新增相關 lerna-changelog 所需要的配置,此處參考babel配置
"changelog": { "repo": "binglingwy/lerna-test-new", "cacheDir": ".changelog", "labels": { "PR: Breaking Change :boom:": ":boom: Breaking Change", "PR: New Feature :rocket:": ":rocket: New Feature", "PR: Bug Fix :bug:": ":bug: Bug Fix", "PR: Docs :memo:": ":memo: Documentation", "PR: Internal :house:": ":house: Internal", "PR: Performance :running_woman:": ":running_woman: Performance" } },
注意:labels 的 key 必須在 github 的倉庫內定義好
3、設置令牌
export GITHUB_AUTH="..."
GITHUB_AUTH 的 token 字段可以在github 申請 token 獲得。
4、創建個PR
a、拉一個新的分支
b、修改代碼並提交,提交記錄記得關聯issues,例如:
git commit -a -m "module-base: bug fixed, Close #1"
c、推送代碼,並在github上創建PR
注意:在創建 pr 時一定要選擇對應的 label ,label需提前在github建好,跟lerna.josn一致
d、合並pr到主干,切換到本地master,生成changelog
node_modules/.bin/lerna-changelog
e、一旦 publish 后我們便可以創建 release note,效果如下
當然也可以在生成文件CHANGELOG.md,在lerna.json中添加conventionalCommits配置:
"command": { "publish": { "allowBranch": "master", "conventionalCommits": true } }
配置后,當我們執行lerna publish
后會在項目根目錄以及每個packages
包下,生成CHANGELOG.md
。
注意: 只有符合約定的commit
提交才能正確生成CHANGELOG.md
文件。
參考文章
Lerna 官網:https://github.com/lerna/lerna/blob/master/README.md
lerna-changelog:https://github.com/lerna/lerna-changelog
手摸手教你玩轉 Lerna: http://www.uedlinker.com/2018/08/17/lerna-trainning/