一.定位前端
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
多模塊管理工具,用來幫助維護monoreponode
P.S.Lerna是Babel本身日用並開源的工具,見Why is Babel a monorepo?react
二.monorepo
monorepo(monolithic repository),與multirepo相對,分別是單代碼倉庫與多代碼倉庫(one-repository-per-module)git
multirepo即傳統作法,按模塊分爲多個代碼庫,實踐中發現一些問題:github
issue管理混亂,常常有在core repo提module問題的,須要Close this and track thatnpm
changelog難以整合,須要人工梳理全部變更的倉庫,並作整合json
core repo版本更新麻煩,須要同步全部module更新其依賴的core repo版本bootstrap
monorepo把全部相關module都放到一個repo裏,每一個module獨立發佈,但使用與該repo統一的版本號(例如Babel和React),issue和PR都集中到該repo,changelog能夠簡單地從一份commit列表梳理出來(甚至若是按照commit規範關聯issue tag的話,可以自動生成規範的changelog)bash
monorepo也存在一些問題,但不如上面提到的痛點強烈:babel
repo體積較大,可能帶來版本控制的問題(Git不適合管理體積太大的repo)
統一構建工具,對構建工具提出了更高要求,要能構建各類相關module
從源碼管理的角度來看,multirepo與monorepo是兩種不一樣的理念,前者容許多元化發展,各個module能夠有本身的玩法(構建,依賴管理,單元測試等),後者但願集中管理,減小玩法差別帶來的溝通成本
monorepo標誌性的特徵是目錄結構,例如React:
react-16.2.0/ packages/ react/ react-art/ react-.../
每一個module都有本身的依賴項(package.json),可以做爲獨立的npm package發佈,只是源碼放在一塊兒維護
典型案例:
rollup:multirepo
babel:monorepo
P.S.以前使用rollup遇到問題都先去主repo查相關issue,再根據線索找到對應的plugin repo,再查相關issue。一直感受異常麻煩,又說不出來哪裏不對,原來是源碼組織方式帶來的困擾
三.lerna試玩
// 安裝 npm install lerna -g git init hoho-lerna && cd hoho-lerna // 初始化目錄結構 lerna init
獲得以下結構:
hoho-lerna/ packages/ lerna.json package.json
建立module:
mkdir packages/hoho-lerna-core && cd packages/hoho-lerna-core npm init
這樣最終會獲得一堆package:
packages/ hoho-lerna-core/ package.json hoho-lerna-module-a/ package.json hoho-lerna-module-b/ package.json module.../
咱們實際作的事情是按模塊拆分紅package,並(經過module級的package.json)聲明瞭各package之間的依賴關係
依賴處理
若是moduleA依賴core,經過lerna bootstrap命令處理依賴事後,會在moduleA的node_modules下建立軟連接指向core目錄,有一隻活生生的例子
注意:npm不會自動安裝peerDependencies,lerna也不提供這個服務
lerna bootstrap按照以前聲明的依賴關係,經過創建軟連接來把各package實際關聯起來
發佈package
既然都放在packages裏了,容易統一管理,因此支持一鍵發佈全部package到npm
P.S.先要有npm帳號(自行註冊),並npm adduser添加到本地配置裏
準備好以後,火燒眉毛的開始一箭n星:
lerna publish
不出意外的話,會獲得相似輸出:
lerna info version 2.7.0 lerna info current version 0.0.0 lerna info Checking for updated packages... lerna info Comparing with initial commit. lerna info Checking for prereleased packages... ? Select a new version (currently 0.0.0) Major (1.0.0) Changes: - hoho-lerna-core: 1.0.0 => 1.0.0 - hoho-lerna-module-a: 1.0.0 => 1.0.0 - hoho-lerna-module-b: 1.0.0 => 1.0.0 ? Are you sure you want to publish the above changes? Yes lerna info publish Publishing packages to npm... lerna info published hoho-lerna-module-b lerna info published hoho-lerna-core lerna info published hoho-lerna-module-a lerna info git Pushing tags... Successfully published: - hoho-lerna-core@1.0.0 - hoho-lerna-module-a@1.0.0 - hoho-lerna-module-b@1.0.0 lerna success publish finished
而後,npm registry裏就多了3個垃圾package……
publish的大體過程是:
本地打個tag(例如git tag v1.0.0)
自動更新依賴項版本號 示例
而後把各個package發佈到npm
最後把tag和相應的commit給push上去
注意:若是發佈到npm這一步失敗了的話(好比沒配置npm帳號),下一次直接lerna publish沒法直接發佈,貌似由於本地tag已是v1.0.0認爲上次發佈成功了。把這個tag手動滾掉也不行,.git裏可能記了一些發佈狀態,滾掉以後出現commit hash匹配錯誤,這裏不太友好
P.S.更多命令請查看Lerna
自動生成changelog
先安裝changelog工具:
npm install lerna-changelog -g
而後在lerna.json添加對應配置項:
"changelog": { "repo": "ayqy/hoho-lerna", "labels": { "enhancement": ":rocket: Enhancement", "bug": ":bug: Bug Fix", "doc": "Refine Doc", "feat": "New Feature" }, "cacheDir": ".changelog" }
特別注意:repo是必填的,說是能自動推斷,實際上不太靠譜,見The ‘repo’ field automatically inferred failed, but no error occurred
P.S.labels裏,key是要在Github配置的標籤,用來給Issue/PR分類,value裏的:bug:只是調皮的emoji,會做爲changelog裏該類change的標題
到這裏還不算完,還須要Github repo權限(爲了能查Issue、PR),把token以環境變量的形式暴露出來(經常使用的話,能夠添到~/.bash_profile裏):
export GITHUB_AUTH="..."
配置完畢。要達到「自動」,前提是平常開發維護遵照約定的規範,不然最後工具確定猜不出來changelog。規範是指:
(建議)commit message關聯上對應的issue
(必須)建立PR時要選擇咱們預約義的label
由於工具只整理github帶有指定label的PR,並把commit message做爲changelog項,建議commit message裏關聯上issue,生成的changelog就能關聯到對應issue:
Uses github PR/Issue names categorized by labels with configurable headings.
例如:
git cm -m "feat: changelog, Close #1"
而後提交PR並給貼上label:feat,merge以後,本地pull過來試試lerna-changelog:
## Unreleased (2018-01-13) #### New Feature * [#2](https://github.com/ayqy/hoho-lerna/pull/2) feat: changelog, Closes [#1](https://github.com/ayqy/hoho-lerna/issues/1). ([@ayqy](https://github.com/ayqy)) #### Committers: 1 - 黯羽輕揚 ([ayqy](https://github.com/ayqy)) 至關漂亮:https://github.com/ayqy/hoho-lerna/releases/tag/v1.1.0
P.S.應該在.gitignore忽略掉本地生成的changelog臨時文件,僅在發佈新版本時本地lerna-changelog,並把生成的changelog貼到release note。不自動發佈release note多是API限制或出於慎重考慮,畢竟release note仍是比較重要的
另外,以這種方式自動整理出changelog,實際上靠的是開發中約束(PR的label規範,commit message做爲changelog項的規範),與lerna沒有太大關係,只要是monorepo(Issue/PR)都放在一塊兒,就能夠按照這個思路獲取Issue/PR信息,整理出changelog
至關於把最後梳理changelog的巨大工做量分佈到平常開發維護了,change都要走PR,並且要有issue記錄,不習慣的話仍是很麻煩的(有要求commit message自帶label而不走PR的呼聲,之後應該會支持)
四.適用場景
哪些場景能夠採用monorepo(並用lerna管理?)?
不過度龐大的項目,整合到一塊兒有100G源碼的話,仍是再考慮一下吧
多模塊/插件化項目,把官方維護的插件都做爲package很是合適
另外,還須要:
基礎建設
團隊信任
基礎建設是指強大的構建工具,能知足全部模塊的build需求(純前端項目的話,build壓力不大)
monorepo環境下,能夠而且鼓勵改別人的代碼,一方面須要持續集成機制(例如React – CircleCI)確認修改帶來的影響,另外一方面還須要不一樣團隊之間互相信任,不然會常常出現一個團隊的變動影響了另外一個團隊的狀況,須要回滾掉別人的修改,反而影響效率
P.S.Lerna出來好久了(和Babel差很少年紀),不少項目都在用了
參考資料
Lerna:很簡練的官方文檔
monorepo 新浪潮 | introduce lerna:前輩的helloworld還不錯
REPO 風格之爭:MONO VS MULTI
Mono Repository Tool Comparison:monorepo工具對比
New wave modularity with Lerna, monorepos, and npm organizations