lerna入門指南


一.定位
前端

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

相關文章
相關標籤/搜索