TL;DR
npmやyarnの標準機能のみを使って、「ローカルで、コマンド一発で複数ディレクトリのパッケージインストール」を実現する。また、CIを実行しやすいように、それぞれのディレクトリにlockファイルができるようにする。
はじめに
monorepoは複数のプロジェクトを一つのリポジトリで管理する手法です。例えば、Web開発ではフロントエンドとバックエンドを以下のように、同じリポジトリ内で管理することがあります。
web/
server/
monorepoのメリットとしては、
- フロントとバックエンドでコードを共有しやすい(とくにTypeScriptの型定義)
- issueやPull requestがひとつのリポジトリに集まるため管理しやすい
などがあります。
やりたいこと
- コマンド一発で、
web/
とserver/
のyarn install
(もしくはnpm install
ornpm ci
)を完了させたい。あわよくば、コマンド一発でフロントとバックエンドを両方起動したい。 -
web/
とserver/
それぞれでlockファイルを持ちたい(「CIでweb側だけpackageをインストールをしてテストを走らせる」といったことがやりたいため)
解決方法
1. Docker Composeの利用
複数のコンテナを良い感じに扱える技術。環境による差異もなくせて便利です。ただし、Docker環境で開発するのは普通のローカル環境よりも実行速度が遅い(特にMacで顕著)のが難点です。チームメンバー全員がWindows or LinuxならばDockerでも良いのですが、Macで開発している人が多い場合は、「DBはDockerで、アプリケーションはローカルの環境で」という構成にしたいです。
2. Workspace機能を使う
npm v7やyarnのworkspaceを使うことで、ルートディレクトリでインストールコマンドを走らせるだけで良くなります。
"workspaces": [
"web",
"server"
]
しかし、ルートディレクトリに1つのlockファイルがまとまってできてしまう問題が発生します。
webディレクトリでyarn install
をすると、ルートのlockファイルは無視されてしまいます。かといってルートディレクトリでインストールすると、「フロント側のテストを走らせたいだけなのに、バックエンドのpackageもインストールされてしまう」という事態を招きます。
3. ルートディレクトリのnpm scriptsで解決(結論)
yarn --cwd <ディレクトリ> <コマンド>
とすることで指定したディレクトリでコマンドを実行することができます(参考)。
例えば、yarn --cwd web install
とすると、webディレクトリでyarn install
が実行されます。
npmの場合はnpm --prefix <ディレクトリ> <コマンド>
です。
この機能を使って、以下のようにルートディレクトリのpackage.jsonを設定します。
"scripts": {
"all:install": "yarn install && yarn --cwd web install && yarn --cwd server install",
"all:dev": "run-p dev:*",
"dev:web": "yarn --cwd dev",
"dev:server": "yarn --cwd server"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
run-p
はコマンドを並列実行します。
これにより、yarn all:install
をするだけで、ルート・フロント・バックのパッケージインストールが終わります。また、yarn all:dev
とすると、フロントとバック両方のdevサーバーが起動します。
最後に
他に良い方法がございましたらご教授いただけますと幸いです。