Masayan tech blog.

  1. ブログ記事一覧>
  2. npmのpeerDependenciesの挙動について

npmのpeerDependenciesの挙動について

公開日
最終更新日

要約

npm installで「ERESOLVE unable to resolve dependency tree」エラーに遭遇したことはないだろうか。本記事では、npm peerDependenciesの仕組みとエラーの原因、そして実践的な解決方法を完全解説する。

この記事で分かること

  • peerDependencies とは何か(基本概念)
  • npm 6 → 7 で何が変わったのか(破壊的変更の詳細)
  • ERESOLVE エラーの原因と5つの解決方法
  • --legacy-peer-deps の正しい使い方
  • package.json の設定例とベストプラクティス

対象読者: npm初心者〜中級者、フロントエンド開発者

検証環境: Windows 11 / macOS / Linux、npm 8.x〜10.x (2024年11月時点)

peerDependencies とは?基礎知識

peerDependencies(ピア依存関係)は、npmパッケージが「このパッケージと一緒に使ってほしい」と推奨する依存関係を示すフィールドである。

peerDependencies の役割

通常の dependencies と異なり、peerDependencies はライブラリの利用者(開発者)がインストールすべきパッケージを指定する。

具体例: React用のライブラリの場合

あるReact用のUIライブラリは、React本体を peerDependencies に指定する。これにより、「このライブラリはReact 17.x または 18.x と一緒に使ってください」という要件を明示できる。

dependencies との違い

項目

dependencies

peerDependencies

目的

パッケージが動作するために必要

利用者側で用意すべきパッケージを指定

インストール

自動的にインストールされる

npm 7以降は自動、npm 6以前は手動

用途

内部実装で使用するライブラリ

プラグイン、拡張機能などで使用

バージョン重複

複数バージョンが共存可能

1つのバージョンのみ

package.json での記述例

{
  "name": "my-react-library",
  "version": "1.0.0",
  "peerDependencies": {
    "react": "^17.0.0 || ^18.0.0",
    "react-dom": "^17.0.0 || ^18.0.0"
  },
  "devDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

この例では、利用者は React 17.x または 18.x をインストールする必要がある。

npm 7 以降の破壊的な挙動変更

npm のバージョン 6 から 7 へのアップデートで、peerDependencies の扱いが大きく変わった。この変更がエラーの主な原因である。

npm 6 以前の挙動(〜2020年10月)

npm 6 以前では、peerDependencies は警告のみで、実際のインストール処理には影響しなかった。

特徴:

  • peerDependencies は単なる「推奨事項」
  • 依存関係の解決やインストールは自動で行われない
  • 不一致があっても警告が表示されるだけで、インストールは成功する
  • 開発者が手動で必要なパッケージをインストールする必要があった

実行例(npm 6):

npm install some-package
# Warning: some-package requires peer dependency "react@^17.0.0" but none is installed.
# インストール自体は成功する

npm 7 以降の挙動(2020年10月〜)

npm 7 から、peerDependencies が必須要件として扱われるようになった。

変更点:

  • peerDependencies に指定されたパッケージを自動でインストール
  • バージョンの不一致があるとエラーで失敗する
  • 依存関係の厳密なチェックが実施される

実行例(npm 7以降):

npm install some-package
# npm ERR! code ERESOLVE
# npm ERR! ERESOLVE unable to resolve dependency tree
# インストールが失敗する

なぜこの変更が行われたのか

理由1: バージョン重複の防止

複数のパッケージが異なるバージョンのReactを要求する場合、node_modules内に複数のReactがインストールされてしまう問題があった。

理由2: エラーの早期発見

実行時エラーよりもインストール時エラーの方が、問題の発見と修正が容易である。

理由3: ディスク容量の節約

同じパッケージの複数バージョンがインストールされることを防ぎ、ディスク使用量を削減できる。

ERESOLVE エラーの原因

ERESOLVE unable to resolve dependency tree エラーが発生する主な原因は以下の通りである。

原因1: peerDependencies のバージョン不一致

最も多いパターンである。

エラーメッセージ例:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: my-app@1.0.0
npm ERR! Found: react@17.0.2
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^18.0.0" from some-library@2.0.0

このエラーは、プロジェクトに React 17.0.2 がインストールされているが、追加しようとしているライブラリが React 18.x を要求している場合に発生する。

原因2: peerDependencies が未インストール

peerDependencies に指定されているパッケージがまったくインストールされていない場合も、npm 7 以降ではエラーになる。

原因3: 複数パッケージ間の依存関係の競合

A というパッケージが React 17.x を要求し、B というパッケージが React 18.x を要求する場合、両方を同時に満たすことができずエラーになる。

競合例:

// package-a の peerDependencies
"peerDependencies": {
  "react": "^17.0.0"
}

// package-b の peerDependencies
"peerDependencies": {
  "react": "^18.0.0"
}

原因4: パッケージのバージョンが古い

長期間メンテナンスされていないパッケージは、最新の peerDependencies に対応していない可能性がある。

エラーの解決方法(5つの対処法)

ERESOLVE エラーを解決する方法を優先度順に解説する。

解決方法1: peerDependencies を package.json に追加する【推奨】

最も正しい解決方法である。エラーメッセージで要求されているパッケージを package.json に追加してインストールする。

手順:

  1. エラーメッセージから必要なパッケージとバージョンを確認
  2. package.json に依存関係を追加
  3. npm install を再実行

実装例:

{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "some-library": "^2.0.0"
  }
}
npm install

メリット:

  • 依存関係が明示的になり、管理しやすい
  • チーム開発で一貫性が保たれる
  • 将来的な問題を防げる

デメリット:

  • 手動で依存関係を追加する手間がかかる

解決方法2: --legacy-peer-deps オプションを使用する

npm 6 の挙動に戻すオプションである。一時的な回避策として有効だが、根本的な解決にはならない。

使い方:

npm install some-package --legacy-peer-deps

すべてのインストールに適用する場合:

npm config set legacy-peer-deps true

または .npmrc ファイルに記述:

legacy-peer-deps=true

いつ使うべきか:

  • ライブラリの更新を待つ間の一時的な対処
  • レガシープロジェクトでの互換性維持
  • 複雑な依存関係の調査中

注意点:

  • 依存関係の不整合が隠蔽され、実行時エラーの原因になる可能性がある
  • チーム全体で設定を共有する必要がある

解決方法3: --force オプションを使用する

依存関係の競合を強制的に無視する。最終手段として使用する。

使い方:

npm install some-package --force

リスク:

  • パッケージの動作が保証されない
  • 予期しないバグの原因になる可能性が高い
  • プロダクション環境での使用は非推奨

解決方法4: パッケージのバージョンを調整する

競合しているパッケージのバージョンを変更して、peerDependencies の要件を満たす。

手順例:

React 17.x を要求するライブラリを使っている場合、React を 17.x にダウングレードする:

npm install react@17 react-dom@17

判断基準:

  • プロジェクト全体への影響を慎重に評価する
  • 最新バージョンの機能が必要ない場合は有効な選択肢

解決方法5: パッケージの代替を探す

古くてメンテナンスされていないパッケージは、より新しい代替パッケージに置き換えることを検討する。

調査方法:

  • npm trends で人気度や更新頻度を確認
  • GitHub のスター数、最終更新日、Issue数を確認
  • Stack Overflow や Reddit で評判を調査

peerDependencies の確認方法

インストール前にパッケージの peerDependencies を確認する方法を紹介する。

npm info コマンドで確認

最も簡単な方法である。

基本構文:

npm info <package-name> peerDependencies

実行例:

npm info @typescript-eslint/eslint-plugin peerDependencies

出力例:

{
  "@typescript-eslint/parser": "^5.0.0",
  "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}

この出力から、以下が分かる:

  • @typescript-eslint/parser バージョン 5.x 系が必要
  • eslint はバージョン 6.x、7.x、8.x のいずれかが必要

package.json を直接確認

GitHub や npm のWebサイトでパッケージの package.json を確認する方法もある。

npm Webサイトでの確認:

  1. https://www.npmjs.com/package/ にアクセス
  2. 右側の「Version」から確認したいバージョンを選択
  3. 「Dependencies」タブで peerDependencies を確認

npm list コマンドで現在の状態を確認

インストール済みのパッケージとその依存関係を確認できる。

npm list --depth=0

peerDependencies の警告も表示される:

npm list

実践的なトラブルシューティング

実際の開発現場で遭遇しやすいケースと解決策を紹介する。

ケース1: React プロジェクトで UI ライブラリをインストール

シナリオ:

npm install @mui/material
npm ERR! ERESOLVE unable to resolve dependency tree

原因: Material-UI が要求する React バージョンと、プロジェクトの React バージョンが一致しない。

解決手順:

  1. Material-UI の peerDependencies を確認:
npm info @mui/material peerDependencies
  1. 出力結果:
{
  "react": "^17.0.0 || ^18.0.0",
  "react-dom": "^17.0.0 || ^18.0.0"
}
  1. React を適切なバージョンにアップグレード:
npm install react@18 react-dom@18
  1. 再度 Material-UI をインストール:
npm install @mui/material

ケース2: TypeScript プロジェクトで ESLint を設定

シナリオ:

npm install @typescript-eslint/eslint-plugin
npm ERR! ERESOLVE unable to resolve dependency tree

原因: TypeScript ESLint プラグインが要求する eslint や @typescript-eslint/parser がインストールされていない。

解決手順:

  1. 必要な peerDependencies を確認:
npm info @typescript-eslint/eslint-plugin peerDependencies
  1. 必要なパッケージを一括インストール:
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

ケース3: 複数ライブラリの競合

シナリオ:

library-a は React 17.x を要求し、library-b は React 18.x を要求する。

解決手順:

  1. 各ライブラリの peerDependencies を確認
  2. React 18 が両方に対応しているか確認(^17.0.0 || ^18.0.0 のような記述)
  3. 対応していない場合は以下のいずれかを選択:
    • library-a を最新版にアップグレード(React 18 対応版があるか確認)
    • library-a の代替ライブラリを探す
    • 一時的に --legacy-peer-deps で回避

ケース4: Monorepo での依存関係エラー

シナリオ:

Monorepo(複数パッケージを1つのリポジトリで管理)で、各パッケージの peerDependencies が競合する。

解決策:

Workspace のルートで共通の peerDependencies を管理:

{
  "workspaces": [
    "packages/*"
  ],
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

よくある質問(FAQ)

Q1: peerDependencies と dependencies の使い分けは?

A: ライブラリ開発者の視点で判断する。

  • dependencies: ライブラリ内部で使用し、利用者は意識しなくてよいパッケージ
  • peerDependencies: 利用者側でも使用する、または利用者がバージョンを選択すべきパッケージ

例えば、React用のコンポーネントライブラリなら、React本体は peerDependencies に指定し、内部で使うユーティリティは dependencies に指定する。

Q2: --legacy-peer-deps を使い続けても問題ない?

A: 短期的には問題ないが、長期的には推奨しない。

リスク:

  • 依存関係の不整合による実行時エラー
  • セキュリティアップデートが適用されない可能性
  • 新しいパッケージとの互換性問題

推奨アプローチ:

  1. 一時的な回避策として使用
  2. 根本的な解決(依存関係の更新)を並行して進める
  3. 解決したら --legacy-peer-deps を削除

Q3: peerDependencies のバージョン範囲の読み方は?

A: semver(セマンティックバージョニング)記法で指定される。

記法

意味

^1.2.3

マイナーバージョンまで許容

1.2.3〜1.x.x

~1.2.3

パッチバージョンのみ許容

1.2.3〜1.2.x

>=1.0.0 <2.0.0

範囲指定

1.0.0以上2.0.0未満

||

OR条件

^17.0.0 || ^18.0.0 は17.x または18.x

Q4: npm install が遅い原因が peerDependencies?

A: 可能性がある。npm 7 以降は peerDependencies の解決に時間がかかる場合がある。

高速化の方法:

  1. node_modules を削除して再インストール
  2. npm のキャッシュをクリア: npm cache clean --force
  3. package-lock.json を削除して再生成

Q5: エラーメッセージが長すぎて読めない

A: --verbose フラグを外すか、エラーログファイルを確認する。

簡潔な出力:

npm install 2>&1 | head -n 30

ログファイルの確認:

npm install
# エラーメッセージの最後に表示されるログファイルのパスを確認
cat /path/to/npm-debug.log

Q6: 特定のパッケージだけ --legacy-peer-deps を適用できる?

A: 個別のインストールコマンドにのみオプションを付ける。

npm install package-a --legacy-peer-deps
npm install package-b  # 通常の挙動

または .npmrc で一時的に設定:

echo "legacy-peer-deps=true" > .npmrc
npm install problem-package
rm .npmrc

Q7: peerDependenciesMeta とは?

A: npm 7 で追加された、peerDependencies をオプション扱いにするフィールドである。

使用例:

{
  "peerDependencies": {
    "react": "^18.0.0",
    "sass": "^1.50.0"
  },
  "peerDependenciesMeta": {
    "sass": {
      "optional": true
    }
  }
}

この設定により、sass がインストールされていなくてもエラーにならない。

まとめ

本記事では、npm peerDependencies の仕組みとエラー解決方法を解説した。

重要ポイント:

  1. peerDependencies とは: 利用者側でインストールすべきパッケージを指定する依存関係
  2. npm 7 の変更: 警告のみ → エラーで失敗する挙動に変更された
  3. 推奨解決方法: エラーメッセージを読み、必要なパッケージを package.json に追加
  4. --legacy-peer-deps: 一時的な回避策として有効だが、根本解決を目指すべき
  5. 事前確認: npm info コマンドで peerDependencies を確認する習慣をつける

次のステップ:

  • プロジェクトの package.json を見直し、peerDependencies が正しく管理されているか確認
  • npm を最新版にアップデート: npm install -g npm@latest
  • package-lock.json を定期的に更新し、依存関係を最新に保つ

適切な依存関係管理により、開発環境の安定性とチーム開発の効率が向上する。peerDependencies を正しく理解し、エラーに遭遇した際は本記事の解決方法を参考にしてほしい。