lernaはnpmベースのJavascriptプロジェクトでモノリシックなレポジトリを構築するツールです。
一括ビルド・一括テストなどの共通ワークフローやdevDependenciesに入るビルドツール群の共通化が可能になります。
インストール
パッケージはnpm install lerna
でインストールします。管理に用いるlerna
コマンドが入るため、必要に応じて-g
オプションを付けます。
空のディレクトリでlerna init
すると初期ファイルを作成します。
lernaはバージョン管理にgitを利用しており、lerna init実行によりプロジェクトディレクトリはgitリポジトリになります。
空のpackages/ディレクトリに個別のパッケージディレクトリを作成していきます。
lernaは後述のとおり、サブディレクトリ以下のpackage.jsonを参照して動作します。
npmパッケージのdependencies管理
lernaの運用では、プロジェクトトップとpackages以下の個別パッケージごとにpackage.jsonを持つ2層構造になります。
個別のパッケージには従来どおり、必要なnpmライブラリをdependenciesに指定する必要があります。
プロジェクトトップでは、webpackやeslint、puppeteerといったdevDependencies関連ツールを指定すると役割が明確になります。
package.jsonを更新したらnpm install
の代わりにlerna bootstrap
を実行することでプロジェクト全体のパッケージインストールが実行されます。
また、package.jsonの直接編集以外に、npm install --save
に相当するコマンドとしてlerna add
コマンドを利用すればパッケージ横断の一括インストールも可能です。
--dev
オプションはnpm iの--save-dev
オプションと同等です。また、一部のパッケージにのみ追加したい場合には、--scope
オプションにターゲットを指定します(ターゲットが複数ある場合は–scopeオプションを羅列)。
パッケージ間参照の初期設定
lerna bootstrap
は、package.jsonのname
とversion
(トップレベル設定項目)を参照してローカルレポジトリの依存性を解決します。
例として、利用する側で以下のような指定のケースを考えます。
"dependencies": {
"@some-local-repos/common-lib": "^0.0.1",
}
この場合、package.jsonで以下のように宣言しているパッケージをインポートする挙動になります。
{
"name": "@some-local-repos/common-lib",
"version": "0.0.1",
}
手動で名前とバージョンを合わせれば、lerna publish
未実行の時点でも依性解決が可能です。
lerna bootstrap
で呼び出し側のnode_moules/にsymlinkが作成され、以下のようにコードから呼び出せます(ES Modulesの例)。
import {SomeClass} from '@some-local-repos/common-lib/some-class.js'
パッケージ間の依存解決については、 How to connect sibling packages? #200に議論があります。
packages以下の個別npmスクリプトを実行
lerna run
はnpm run
の巡回コマンドです。
プロジェクトトップでlerna run ARG
を実行するとpackages/以下の個別パッケージのpackage.jsonを探索し、ARGにマッチしたnpmスクリプトを実行します。
”build”, “install”といった共通ラベルを持つnpmスクリプトを各パッケージで定義しておけば、lerna run
で一括ビルドなどが可能になります。
lerna publishとプライベート管理
パッケージのバージョン管理は、lerna publish
で実行します。
この過程でgitのリモートリポジトリへのpushとnpm publish
が実行され、npmパッケージとして公開する挙動となります。
pakege.jsonのprivate設定や、プライベートレジストリがセットアップされていれば個別の設定が優先されるようです。
また、lerna publishには、--skip-git
と--skip-npm
オプションがあり、各プロセスを回避することも可能です。
プライベートレジストリについては、 Is there a way to use lerna packages without publishing it to npm ? #536に議論があり、参考になります。
まとめ
lernaのセットアップによりmonorepoを構築できます。
セットアップには相応の手間がかかりますが、WebComponentsなどの細かい部品を開発するようなプロジェクトでは、断片化を避け、管理コストを下げられるケースがあります。
公式PRサイトに掲載されているとおり、babelほか実績は多く、大規模オープンソースプロジェクトの実例も参考になります。
Chuma Takahiro