◆ 複数のパッケージをまとめて管理できる
◆ workspace のルートに node_modules と yarn.lock ができて全部そこにインストールされる

monorepo

JavaScript 関係ツールのドキュメントを眺めてると monorepo の対応についてのページがあったりします
自分には関係ないやつってことでスキップしてましたが ふと monorepo って自分に役立つことあるのかなと思いました

monorepo というと複数パッケージをそれぞれ別のリポジトリに分けるのではなく 1 つのリポジトリにまとめてるやつです
大きめなプロジェクトの Github のページを見ると 1 つのリポジトリで packages フォルダがあってそこにそれぞれのパッケージが入っていることが多いです

作る側的にはパッケージごとにリポジトリを作るより楽になります
ひとつひとつは小さいプラグイン系をそれぞれ別のリポジトリにすると考えると 管理が面倒になるのは簡単に想像できます
バグ報告や質問する側にしても 細かくリポジトリが分かれてるとどこに書けばいいのか判断に困るということがあるので 一つのほうが助かります
ただ エラーが出たり求めてる機能がなかったりして issue を探そうって人にとっては逆に扱いづらかったりします
明らかにこのパッケージについてのことなのに 関係ないものも全部まとまってるので探すのが大変です
なので検索することのほうが多い自分的には Github で monorepo になってるのはあまり好きじゃないです

単純に 1 つのリポジトリに複数のパッケージを含めるだけなら 特別なことでもなくわざわざ名前をつけるほどのものでもないです
見る側としては monorepo が好きじゃないと書きましたが 自分でリポジトリを作るときは基本まとめてます
ウェブページを表示するものだと クライアントとサーバは別アプリに分けられるので それぞれ package.json は別にしてます
client と server というフォルダがリポジトリルートにあって それぞれに package.json がある感じです
なので monorepo というものは使ったことがあると言えます
実際はこういう package.json がリポジトリ内に複数あるかではなく monorepo 管理用のツールを導入してるかが monorepo かどうかになると思います

yarn で使ってみる

有名なツールだと lerna があります
Github ではよく見かけます
lerna.json がトップにあるのでわかりやすいです
他には Microsoft の Rush だったり 他マイナー系の新しめなツールは色々あるようですが あまり聞きません
比較的最近 monorepo 化した lit も lerna でしたし

とりあえず試すなら lerna かなと思ったのですが yarn 自体にそういう機能があるようでした
わざわざ追加でツールを入れたくないので yarn でできるなら yarn にします

yarn の機能は workspaces と呼ばれるものです
そういえば名前は聞いたことがあります

まずはルートのフォルダを作って package.json を作ります
そこに workspaces キーで workspace へ追加するフォルダを登録します

  "workspaces": [
"pkg*"
],
"private": true,

ワイルドカードが使えるので pkg から始まるフォルダを workspace に含めるようにしました
あと workspaces 機能を使うには private を true に設定する必要がありました
ないとエラーになります↓

error Workspaces can only be enabled in private projects.

pkg1 と pkg2 フォルダを作ってそれぞれに package.json を作ります
普段はいきなり yarn add でパッケージを追加しようとすると自動で作られますが この場合は親フォルダに package.json があるので手動や yarn init で作らないといけないです

作ったら pkg1 と pkg2 のそれぞれに追加したいパッケージを yarn add で追加します
通常なら pkg1/yarn.lock や pkg1/node_modules が作られますが workspaces 機能が有効になっていると workspace のルートフォルダに node_modules や yarn.lock が作られます

.
|-- node_modules
| |-- package0
| |-- ...
| `-- packageN
|-- package.json
|-- pkg1
| `-- package.json
|-- pkg2
| `-- package.json
`-- yarn.lock

似た系統のパッケージなら同じパッケージが依存関係に重複してあることがよくあるので 容量が節約できます
物によっては node_modules が数百 MB とかありますからね
client/server でのパッケージ分けだと重複はあまりなさそうですが 内部で依存関係として入るパッケージには意外と重複があったりします

自分で yarn add で追加するパッケージを複数のパッケージで使う場合 全部で yarn add しなくても workspace のルートに追加できます
このとき単純に yarn add だとエラーになります↓

error Running this command will add the dependency to the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).

意図せずルートに追加してしまわないようにの警告です
ルートに追加したいのなら -W オプションをつければ追加できます

また workspace に設定した各パッケージも node_modules に含まれます
シンボリックリンクになってます

[root@aee6904f505c repo]# ll node_modules/
(略)
lrwxrwxrwx 1 root root 7 Mar 18 14:12 pkg1 -> ../pkg1
lrwxrwxrwx 1 root root 7 Mar 18 14:12 pkg2 -> ../pkg2
(略)

別パッケージのモジュールをインポートしたいときの問題を解決してくれています

色々便利そうですが node_modules が一箇所にまとまるのは問題もある気がします
片方だけのバージョンを更新したいときに package.json で指定したバージョンの範囲であれば別のパッケージの依存パッケージも更新されます
また node_modules が多くなってくると yarn の処理が遅くなります
個々のパッケージごとに node_modules が分かれていればそれぞれが扱うパッケージ数が少ないので高速でしたが 1 つの node_modules に全部となるととても遅くなりそうです

client/server でパッケージを分ける場合 client の方は事前ビルドするのでビルド後には node_modules は不要です
それに対して server の方は実行時にも参照するので node_modules が必要です
開発用の環境から実際に動かす環境に移す時は node_modules は server の分だけでいいのに client の分まで含まれてしまいます
サイズが小さいならいいですが client 側のほうがサイズが大きくなりがちで 数百 MB もあるとコピーにかかる時間も長くなるので分けたいなという気持ちになります

普段のフォルダ構成的には ほぼ workspaces キーを追加するだけで使えるお手軽機能でしたが メリットもデメリットもあるので使うかどうかは難しいところです