yarnでworkspaceを使用する際の挙動

332
NO IMAGE

yarnでworkspaceを使用した際のモジュールの格納位置について調べてみました。
一部のモジュールが、何故かワークスペースのルートに配置されず、それに依存しているモジュールでエラーが発生したためです。

調査方法

以下のような構成のプロジェクトを作成し、依存するバージョンを適宜変更して、ワークスペースのルートでyarn installを実行しました。

yarn-workspace-test
│  package.json
│  
├─first
│  │  package.json
│  │  
│  └─src
│          index.ts
│          
├─second
│  │  package.json
│  │  
│  └─src
│          index.ts
│          
└─third
        package.json

ワークスペースのpackage.json

{
  "name": "yarn-workspace-test",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "build": "yarn workspaces run build",
    "lint": "yarn workspaces run lint"
  },
  "workspaces": [
    "first",
    "second",
    "third"
  ]
}

個別プロジェクトのpackage.json

{
  "name": "first",
  "version": "0.0.1",
  "description": "",
  "license": "ISC",
  "author": "",
  "devDependencies": {
    "eslint": "6.7.2"
  }
}

通常時

全プロジェクトで同一バージョン

node_modulesの場所 指定バージョン 配置バージョン
first 6.7.2 ./binのみ
second 6.7.2 ./binのみ
third 6.7.2 ./binのみ
ルート - 6.7.2

モジュールはルートのみに配置されたが、各プロジェクトにも、.bin以下は作成された。

コンフリクト有

全プロジェクトで異なるバージョン

node_modulesの場所 指定バージョン 配置バージョン
first 6.7.0 ./binのみ
second 6.7.1 6.7.1
third 6.7.2 6.7.2
ルート - 6.7.0

6.7.0がルートに配置された。それに対応する、firstにはモジュールが配置されなかったが、secondとthirdにはそれぞれ指定のバージョンが配置された。

コンフリクト有(1対2)

1プロジェクトのみを異なるバージョン node_modulesの場所 指定バージョン 配置バージョン
first 6.7.0 6.7.0
second 6.7.2 ./binのみ
third 6.7.2 ./binのみ
ルート - 6.7.2

2プロジェクトで指定されているバージョンがルートに配置された。

想定

公式ドキュメントでは、衝突解決のルールが見つからなかったが、おそらく以下のようなルールになっている。

バージョンに矛盾がある場合には、その中ので最も使用されているバージョンをルートのnode_modulesに配置。それ以外は、そのバージョンが使用されているプロジェクトのnode_modulesに配置。使用回数が同じ場合には、最も小さいバージョンをルートに配置。

動作する理由

上記のルールで配置すれば、ほぼ問題は発生しない。
yarnコマンドの実行時のノードモジュールの検索は、自プロジェクトのnode_modulesを最優先に、上位ディレクトリにあるnode_modulesを順に見ていくため。