lerna とは?
lerna/lerna: A tool for managing JavaScript projects with multiple packages.
が何ものかというと、単一のリポジトリで複数の npm module 開発を可能にするツールです。
たとえば、
- babel/babel: ?? Babel is a compiler for writing next generation JavaScript.
- facebook/create-react-app: Set up a modern web app by running one command.
- nuxt/nuxt.js: The Vue.js Developers Framework
このあたりの有名なリポジトリが lerna を採用していて、もう面影がないですが、
react も同じディレクトリ構成をしています。(脱 lerna でもしたのでしょうか)
monorepo の長所と短所
babel/monorepo.md at master ・ babel/babel
からの引用ですが、
Why is Babel a monorepo?
Pros:
* Single lint, build, test and release process.
* Easy to coordinate changes across modules.
* Single place to report issues.
* Easier to setup a development environment.
* Tests across modules are run together which finds bugs that touch multiple modules easier.
Cons:
* Codebase looks more intimidating.
* Repo is bigger in size.
* Can't npm install modules directly from GitHub
* ???
このあたりはひじょうに痛感していて、依存し合う2つの npm module が別々のリポジトリだとテストをどっちに書こうかなどいろいろと悩みがあります。
そういった部分をマージしましょうというお話ですね。ただし、 Cons もそこそこあると。
lerna のベースとなる環境を作る
lerna/commands/init at master ・ lerna/lerna
$ lerna init
これで以下のように必須のファイル・ディレクトリたちが作られる。
これは npm init
や yarn init
の lerna 版 だと思います。
lerna-repo/
packages/
package.json
lerna.json
publish したい npm module の雛形を create する
$ lerna create lemon-sour
$ lerna create cli
上記のように実行すると、 packages の下にこのようにディレクトリが配置される。
packages
├─cli
│ │ package.json
│ │ README.md
│ │
│ ├─lib
│ │ cli.js
│ │
│ └─__tests__
│ cli.test.js
│
└─lemon-sour
│ package.json
│ README.md
│
├─lib
│ lemon-sour.js
│
└─__tests__
lemon-sour.test.js
ローカルパッケージ cli を lemon-sour から参照するよう追加する。
$ lerna add cli --scope lemon-sour
lerna add
は yarn add と同じコマンドだが、 --scope
を指定いないとすべての packages に追加されてしまう。
なので、たてば lemon-sour だけに lodash を入れたい場合は、
$ lerna add lodash --scope lemon-sour
となる、このあたりは慣れるしかないんでしょうね。
また、 run test
を実行すると、すべての package で script:test を実行してくれる。
$ lerna run test
さらに lerna コマンドは、どの階層にいても実行できるので、 create は ROOT に行ってから実行しないと、みたいなものがない。
lerna と yarn を一緒に使う場合
そもそも lerna を使うと npm install
や yarn add
のようなものを直接使うことはできない。
なので、 yarn を使うには、 lerna.json を編集する必要がる。
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
],
"version": "0.0.0"
}
ROOT の package.json に workspaces の key を追加する。
{
"name": "root",
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^3.8.5"
}
}
これで yarn workspaces が使える状態が整いました。
では試しに packages 全体に typescript を入れて、 lerna で build してみましょう。
$ lerna add typescript --dev
これで packages 個別に typescript がインストールされましたが、面白いことに packages のほうの node_modules のほうには typescript の link しかありません。
これは、同じバージョンの typescript 2つの npm module にインストールされましたが、それは2つ別々に配置するのが無駄なので、 ROOT のほうの node_modules に引き上げられます。
add した module を remove する方法
どうやら、これがまだないらしく、つまり yarn remove
相当のものはありません。
npm uninstall throws 404 for unpublished siblings ・ Issue #1229 ・ lerna/lerna
今後追加されていくようです。
なので、 editor で package.json を修正して、以下のコマンドを実行する必要があります。
$ lerna clean // node_modules たちを消す
$ lerna bootstrap // yarn 相当
publish する
$ lerna publish
これで、 lerna.json に書かれてるバージョンが上がって各 npm module たちが push されていきます。
今回のサンプルコード
読んだ記事
Lerna を使って、 Babel や React が採用している monorepo を試してみる - Qiita
Lernaを使ってFirebase環境のためのモノレポ環境一式をカッコよく構築する - Qiita
lernaを使ってnpmプロジェクトをモノレポ化する - つくりおき
単一リポジトリで複数package|projectを管理することをmonorepoというそう - なっく日報
Support Yarn workspaces to replace bootstrap command by bestander ・ Pull Request #899 ・ lerna/lerna