モノレポの最適解:pnpm Workspaceがもたらす「依存地獄」からの解放と開発体験の極致
多くのチームが「npm link」の悪夢に苦しんできたことだろう。シンボリックリンクの整合性が取れず、ビルドのたびに壊れるnode_modules、そしてnpm link先の環境と本番環境の微妙な差異。それらは開発者の脳のリソースを削り取るノイズでしかない。
本稿では、我々がどのようにpnpm Workspaceを駆使し、モノレポ環境で「公開不要なローカル依存関係」を完全に制御し、CIパイプラインを極限まで効率化しているかを共有する。
1. なぜ「npm link」は捨て去られるべきなのか
npmやyarnの`link`コマンドは、物理的なファイルを別のディレクトリへコピー(あるいはリンク)する。これは「依存関係のグラフ」を静的に解決するパッケージマネージャーの設計思想と真っ向から衝突する。
対してpnpm Workspaceは、Content Addressable Store(単一インスタンスストア)をベースに、`node_modules`内に高度なハードリンクとシンボリックリンクを構築する。これにより、ローカルパッケージ間での依存関係が「本番環境のインストール結果」と完全に同一の構造で再現される。これがモノレポにおける「動いたはずなのに動かない」を根絶する唯一の解だ。
2. pnpm-workspace.yaml:物理構造を論理的に分離する
モノレポを構築する際、最も重要なのは「パッケージの独立性」と「依存の可視化」だ。以下は、スケーラビリティを確保するためのベストプラクティス構成である。
pnpm-workspace.yaml
packages:
- ‘packages/’ # UIコンポーネントや共通ユーティリティ群
- ‘apps/’ # Next.jsやNode.jsサーバーなどのエンドアプリケーション
- ‘internal/’ # 外部公開しない秘匿性の高いビジネスロジック群
重要な設定:自動的な依存解決のトリガー
catalog:
# ここで共通の依存関係を管理することで、
# 全パッケージ間でのバージョン衝突(いわゆるdependency hell)を防ぐ
react: ^18.2.0
typescript: ^5.3.3
3. 現場で震えるほど役立つ「フィルタリング」戦略
CI環境において、全パッケージを再ビルドするのは時間の無駄だ。pnpmのフィルタリング機能を使えば、変更があったグラフノードだけをピンポイントで叩ける。
変更があったパッケージのみをビルドするCIコマンド
–filter … で変更対象のパッケージを指定
–changed-since=origin/main で差分のみを抽出
pnpm –filter “…[origin/main]” run build
この`…`(ドット3つ)の威力を見誤ってはいけない。これは「変更されたパッケージ」とその「依存先」すべてを対象にする指定だ。例えば、共通の`ui-kit`に変更が入った場合、それに依存している`web-app`や`admin-panel`も自動的にビルド対象となる。この連鎖解決こそが、モノレポCIの真骨頂である。
4. 開発効率を「異次元」に引き上げる設定とプラグイン
神プラグイン:`pnpm-sync-dependencies-meta`
モノレポ内でのパッケージ間依存(`workspace:`)を維持しつつ、デプロイ時に正しく書き換えるためのプラグイン。これを導入することで、ローカルではリンク、本番ではバージョン参照という切り替えを意識せずに行える。
.npmrc の最適化(絶対に入れるべき設定)
.npmrc
依存関係がworkspace内にある場合は自動的にリンクする
link-workspace-packages = true
複数のプロジェクトでnode_modulesを共有し、ディスク消費を抑える
auto-install-peers = true
依存関係のホイスティング(平坦化)を制御し、幽霊依存を防ぐ
hoist-pattern[] = @types/
5. チーム開発における「暗黙のルール」の共有
モノレポにおいて最も危険なのは「誰かが勝手に依存を追加し、依存グラフが汚染されること」だ。これを防ぐために、ルートの `package.json` に以下のスクリプトを仕込んでおけ。
{
“scripts”: {
“check:circular”: “madge –circular packages/”,
“check:unused”: “pnpm recursive exec — depcheck”
}
}
- circular: 循環依存はモノレポ崩壊の第一歩。CIで必ず検知する。
- unused: `package.json` にあるが実際には使われていない依存を排除する。
アーキテクトからの提言:ツールは「文化」である
pnpm Workspaceを導入するということは、単にパッケージマネージャーを変えることではない。「どのモジュールがどのモジュールに依存しているか」という依存グラフを、チーム全員が明示的に意識する文化を作るということだ。
npm linkの時代、我々は「隠れた依存関係」に支配されていた。しかし、pnpmのWorkspaceを適切に設定すれば、依存関係は可視化され、ビルドは論理的になり、CIは最短距離で完了するようになる。
この環境を手に入れた時、君たちのチームは「コードを書くこと」以外のコストを極限まで削ぎ落とし、プロダクトの本質的な価値創造に全脳力を注げるようになるはずだ。今すぐ `pnpm install` から、新しいモノレポの景色を見に行こう。