shokaimonorepoという1つのリポジトリに複数プロジェクトを入れる開発手法がある。なっく日報そういえばRocketIOやnode-lindaを作っていた時は自作のライブラリ/パッケージが3,4層に積み上がっていて、単一パッケージ内で生じるバグはテストを書けば潰せるけどパッケージ間で起こるバグは非常に解決が難しかった。イベント発火のタイミングによるものとか。パッケージをまたがったテストをどこに書くのかという問題がある。複数パッケージで起こったバグはどっちのissueに書けばいいのかわからないし、両方でブランチ切って同時に修正してリリースしたりとか超面倒だった。バージョン毎の依存関係も、serverの1.3に対応してるのはclientの1.5で・・とか依存関係を書くのがややこしい。テスト・ビルド用ツールも、それぞれのnpmに.babelrcとか.eslintrcとか置いて微妙に内容が違ったりすると混乱するし、統一したい。思う所があったのだが、1つのgitリポジトリに複数npmをまとめて入れて管理すればこの辺の悩みは解決しそうなのでmonorepoを試してみる事にした。6系になってからbabel-cliとかbabel-polyfillとかbabel-preset-es2015とかめちゃくちゃパッケージが分かれてて、でもバージョン番号は合っているのでこれどうやって管理してるんだ?と思ったらlernaというNode.jsでmonorepoするためのツールを使っていた。コマンドはbootstrap、updated、publishの3つだけ。publishしてくれたりする。ドキュメントが無いのでソース読んで理解した。v1.1.0時点についてのメモ。bootstraplib/commands/bootstrap.jsbootstrapすると必要なファイルが作られる。packagesディレクトリが作られるので、その下に複数のnpmを置ける。publishできるようにpackage.jsonや.npmignoreなどを置く(自分で)rootディレクトリには開発用のpackage.jsonが作られ、devDependenceisにlernaがインストールされる。rootにあるVERSIONというファイルにバージョン番号が書いてある。これはpublishに使われる。installが行われ(4並列でchild_process.execしている)、monorepo内で依存関係があればnpmjs.comからインストールせずにリンクが作られる。require("/Users/sho/src/nodejs/weather-yahoo-jp/packages/weather-yahoo-jp");1行だけ書いてあるindex.jsが生成されて、リポジトリ内のローカルリンクになる。ように^で始まるバージョン番号で指定していないとリンクを作ってくれない。ようなバージョン指定ではnpmjs.comからインストールしてしまうという罠がある。installするのにも使う。bootstrapしろ」とREADMEに書いておくべき。publishlib/commands/publish.jsupdatedなnpmを全てpublishする。VERSIONファイルのパッチレベルが0.2.3→0.2.4のように1つ上がる。publishは対話式なので自分で番号入力したり、major,minor,patchでインクリメントもできる。packagesの下の依存しあっているnpmのdependenciesで指定しているバージョン番号をVERSIONに置換してくれる。これもbootstrapでのリンクと同じように、”^0.1.2′′みたいな^が頭につく形式で書いてないと置換してくれない。publishすればcommitに含めてくれる。publishとcommitしてくれる。実際やってみるweather-yahoo-jpという天気を取得するNodeライブラリと、CLIで天気を表示するツールを1つのリポジトリにまとめてmonorepo化してみた。test_helper.es6rootのpackage.jsonのdependenciesにビルド/テスト関係のnpmを全部入れて、各packages内はdevDependencies不要という構成にしたらすっきりした。testコードは各packagesの下に置く。npmごとにbabelやeslint入れて微妙にバージョンずれて変な感じになったりしない。js:babel-registertest/lint関係のnpmはrootのpackage.jsonにインストールするようにした。installは自動的にやってくれる。bootstrapする。runで呼び出せばlernaをグローバルインストールしなくていい。CircleCIではrootのnode_modulesしかcacheしないので、cache_directoriesにpackages/*/node_modulesを追加した。各packages内でそれぞれコマンドを実行するrun-each-packagesというコマンドを作った。全packageでbabelをwatch–parallelつけると並列実行する。babelはrootディレクトリから実行すると書き出し先をpackages下のそれぞれに指定できなかったので、run-each-packagesが必要になった。installの経過を表示してくれなくて不安なので使ったりもする。installはdependenciesが多すぎるとたまにエラー吐いて死ぬので経過を表示したい。ディレクトリ構成も実装も処理内容もシンプルで理解しやすい。シンプルなのでかゆいところは自分で掻ける。形式で頭に^つけて書かなければローカルリンクしてくれない事以外はだいたい直感通りに動くので混乱なかった。