メモ2ブログ

メモtoウェブログ。旧ブログはこちら。 http://sakebook.blogspot.jp/

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

単一リポジトリで複数package|projectを管理することをmonorepoというそう / なっく速報

lernaでmonorepo管理 / ユニコーンリサーチ