メインコンテンツへ移動

Lerna 入門ガイド

無料2018-01-13#Tool#monorepo#lerna monorepo#babel lerna#lerna tutorial#lerna-changelog

シンプルで実用的な monorepo 管理ツール、もう手動で changelog を整理する必要はありません

一.ポジショニング

Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.

マルチパッケージ管理ツールで、monorepo の維持管理を支援します

P.S.Lerna は Babel が日常使用しオープンソース化したツールです。Why is Babel a monorepo? を参照

二.monorepo

monorepo(monolithic repository) は multirepo に対比する概念で、それぞれ単一コードリポジトリと複数コードリポジトリ(one-repository-per-module)を指します

multirepo は従来の做法で、モジュールごとに複数のコードリポジトリに分割しますが、実践においていくつかの問題が発見されました:

  • issue 管理が混乱しており、よく core repo で module の問題を提起する必要があり、Close this and track that が必要

  • changelog の統合が難しく、すべての変更リポジトリを手動で整理し統合する必要がある

  • core repo のバージョン更新が面倒で、core repo に依存するすべての module のバージョンを同期して更新する必要がある

monorepo はすべての関連 module を 1 つの repo にまとめ、各 module は独立してリリースしますが、該 repo と統一されたバージョン番号を使用します(例えば BabelReact)。issue と PR はすべて該 repo に集中し、changelog は 1 つの commit リストから簡単に整理できます(さらに commit 規範で issue tag を関連付ければ、規範的な changelog を自動生成できます)

monorepo にもいくつかの問題がありますが、上記の痛点ほど強烈ではありません:

  • repo の体积が较大で、バージョン管理の問題をもたらす可能性がある(Git は体积が大きすぎる repo の管理に適さない)

  • 統一ビルドツールで、ビルドツールにより高い要求を突きつけ、さまざまな関連 module をビルドできる必要がある

ソースコード管理の観点から見ると、multirepo と monorepo は 2 つの異なる理念です。前者は多元的な発展を許可し、各 module は自分の玩法(ビルド、依存管理、ユニットテストなど)を持てます。後者は集中管理を希望し、玩法の違いによるコミュニケーションコストを削減します

monorepo の象徴的な特徴はディレクトリ構造で、例えば React:

react-16.2.0/
  packages/
    react/
    react-art/
    react-.../

各 module は自分の依存項(package.json)を持ち、独立した npm package としてリリースできます。ソースコードを一緒に維持管理するだけです

典型的なケース:

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 コマンドで依存関係を処理した後、moduleAnode_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 の大まかなプロセスは:

  1. ローカルでタグを打つ(例:git tag v1.0.0

  2. 依存項のバージョン番号を自動更新

  3. その後各 package を npm にリリース

  4. 最後にタグと対応する commit を push

注意:npm へのリリースステップで失敗した場合(例:npm アカウントを設定していない)、次回直接 lerna publish しても直接リリースできません。ローカルタグがすでに v1.0.0 なので前回リリース成功とみなされるためです。このタグを手動でロールバックしてもダメで、.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 を推測できません。規範とは:

  1. (推奨)commit message で対応する issue を関連付ける

  2. (必須)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.ローカルで生成された changelog 一時ファイルを .gitignore で無視すべきです。新バージョンリリース時のみローカルで 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)で変更による影響を確認し、他方で異なるチーム間の相互信頼が必要です。否则よく 1 つのチームの変更が別のチームに影響し、他人の変更をロールバックする必要があり、逆に効率に影響します

P.S.Lerna は很久前から出ており(Babel とほぼ同年代)、多くのプロジェクト が使用しています

参考資料

コメント

コメントはまだありません

コメントを書く