Node.jsを使ったアプリケーションのサンプル集にlernaを使うと便利だった
先日参加した技術書典でFitbitのClock Faceの作り方に関する本を出しました。サンプルコードを添えたのですが、そこで使ったlernaが今回のようなケースと相性が良いと感じたので紹介します。
今回のケース
1つのリポジトリに複数のNode.jsのアプリケーションを配置しました。そしてそれらは同じ devDependencies
を持っています。
複数のアプリケーションが存在していて
. ├── LICENSE ├── README.md └── packages ├── package1 │ └── package.json ├── package2 │ └── package.json ├── package3 │ └── package.json └── package4 └── package.json
それぞれのpackage.jsonに次のような記述がある
{ "name": "package1", ... "devDependencies": { "@hoge": "1.0.0", "@fuga": "~1.0.0", "@piyo": "^1.0.0" }, ... }
問題と思っていたこと
このようなサンプル集のリポジトリで各サンプルを動かしたい場合は、クローンしてきたあとにそれぞれのpackageのなかで npm install
を実行する必要があります。
単純に数が増えてくると手間だというのと、同じ依存関係を持つ .node_module/
が各package配下に重複してできてしまい、ディスク容量を圧迫してしまいます。
簡単にサンプルを実行可能な状態にして、重複する依存関係はよしなに参照するとかしてほしい。
lerna
lernaはmonorepo管理用のツールです。npmに公開するところまでサポートしてます。
今回はlernaの機能の一部を使って問題を解決します。
使い方
新規の場合
$ lerna init
で必要なものを作成できます。
. ├── lerna.json ├── package.json └── packages
packages
の中に各プロジェクトを配置します。
モジュールの追加
モジュールのインストールは各package直下だけではなく、プロジェクトルートで lerna
を使って行えます。
$ lerna add ${モジュール名} --dev
これで packages
配下のすべての package.json
に ${モジュール名}
が追加されます。各package直下で npm install ${モジュール名} --save-dev
したことと大体同じになります。
cloneしてきてから初期化
プロジェクトルートで次のように実行すればすべてのpackageを初期化できます。
$ lerna bootstrap
重複をまとめる
まず既存の node_modules/
を削除します。cloneしてきた直後だと不要です。
$ lerna clean
先程のbootstrapにオプションを付けて実行します。
$ lerna bootstrap --hoist
--hoist
オプションをつけることで、package共通で使うモジュールは プロジェクトルートの node_modules/
にインストールされます。各package配下では、 共通利用しているモジュールのみ node_modules/.bin/
にシンボリックリンクが生成され て利用可能になります。
プロジェクトルートの node_modules/
は lerna clean
では消去できないので注意してください。
今回のサンプルコードだと --hoist
オプションを使うことでディスク容量を半分以下に抑えられました。モジュールの種類や依存状況にもよりますが、 同じようなものを共通して利用するサンプル集のような場合だと、サンプル数が多ければ多いほど効果が出てきます。
- hoistなし
$ du -sch * 4.0K LICENSE 4.0K README.md 4.0K lerna.json 4.0K package.json 518M packages 518M total
- hoistあり
$ du -sch * 4.0K LICENSE 4.0K README.md 4.0K lerna.json 152M node_modules 316K package-lock.json 4.0K package.json 99M packages 252M total
--hoist
オプションを使うとファイル容量を節約できますが、前述の通りpackageから見たら通常 インストールされているモジュールの位置が異なるので lerna
で管理可能なもの以外で パスを参照している場合注意が必要です。
まとめ
lerna
はmonorepoの管理だけでなく、次の場合にも便利です。
- Node.jsのサンプル集を扱うとき
- サンプルの一括セットアップをしたいとき
- ディスク容量の節約がしたいとき
- まとめた場合共通モジュールの参照先が変わるので注意
参考
lerna/lerna: A tool for managing JavaScript projects with multiple packages. / GitHub