npm installがERESOLVEで止まったら、最初に「どのpackageが、どのpeer バージョンを要求し、実際には何が選ばれたか」を読みます。--forceや--legacy-peer-depsを足して終了コードだけを変える前に、互換性の衝突なのか、npmの解決条件や版の差なのかを分けます。
この記事はnpmのpeer dependency解決を対象にします。npm ciのmanifestとlockfile不一致、registry認証、通信障害とは別です。以下のpackage名とバージョンは架空例で、実packageの互換性を示しません。依存のinstallや動作試験も行っていません。
目次
エラーの要求元とバージョン範囲を表にする
ログのFound、Could not resolve dependency、peerなどに相当する箇所を読み、要求元packageと対象hostを抜き出します。表示形式はnpm版で異なるため、文字列の位置だけを固定した読み方にしません。
表は横にスクロールできます
| 架空の構成要素 | バージョン・要求 | 確認する意味 |
|---|---|---|
| root app | host-lib 3.2.0を使用 | appが選んだhost |
| plugin-a 1.0.0 | peer host-lib ^2.0.0 | pluginが宣言した対応範囲 |
| plugin-b 2.0.0 | peer host-lib ^3.0.0 | 別pluginの対応範囲 |
この架空例では、host-lib 3.2.0はplugin-aの^2.0.0を満たしません。単にrootのhostを2系へ下げればplugin-bとの関係が変わります。衝突行だけを消すのではなく、同時に使うpluginとhostの組合せを一覧にします。
peerDependenciesは、pluginなどがhost tool/libraryとの互換性を表すための宣言です。npmのpackage.json資料(新しいタブで開く)で意味を確認し、通常のdependenciesと同じように「別の場所に二個入れば必ず解決する」と考えないようにします。
manifest・lock・実ツリーを区別する
package.jsonは宣言、package-lock.jsonは解決状態、node_modulesは実際に展開された状態です。installが途中で失敗した作業場所では、node_modulesが今回意図した完成形とは限りません。実行ディレクトリとworkspace、Node.js/npmの版、直前の変更も記録します。
読取中心の確認では、対象packageを指定したnpm lsで現在の依存関係を見て、npm explainでなぜ取り込まれたかをたどる方法があります。まだinstallされていないpackageは、これらの実ツリー表示だけでは判断できません。エラーログ、manifest、lock側の情報と合わせます。
表は横にスクロールできます
| 確認資料 | 分かること | 分からないこと |
|---|---|---|
| package.json | 宣言range・workspace・overrides | 実行時互換性の保証 |
| package-lock.json | 記録された解決状態 | 現在のnode_modulesが同じか |
| npm ls | 現在の依存関係・問題表示 | 未install構成の完成形 |
| npm explain | 依存として入った経路 | upstreamが保証する対応範囲 |
private registryや内部package名を含むログは、公開issueへ丸ごと貼らず、再現に必要な範囲を伏せた最小例へ切り出します。.npmrcのregistry tokenも共有しません。
互換な組合せと解決器の問題を分ける
packageの公式release noteやpeer宣言を確認し、hostに対応するplugin版へ更新する、互換なhostへ合わせる、使わなくなったpluginを外す、といった候補を比較します。すべてを最新版へ上げることが、既存appにとって最小変更とは限りません。
一方、range上は成立するはずなのに失敗する場合、npm版、workspace、overrides、optional peer、解決器の既知問題も調査対象です。ERESOLVEという名前だけで必ずpackageの宣言が間違っていると断定しません。最小再現と利用版を揃え、該当する公式issueやrelease情報を確認します。
表は横にスクロールできます
| 状態 | 次の確認 | 修正後に必要な検証 |
|---|---|---|
| peer rangeが明確に衝突 | 対応するhost/plugin版 | 関連機能の動作 |
| 別環境だけ成功 | npm版・設定・lock生成条件 | 同じ条件で再現するか |
| 複雑なworkspaceでのみ失敗 | rootと対象workspaceの依存 | 対象範囲とlock差分 |
| 条件上成立するが失敗 | 最小再現・npm既知問題 | 修正候補版での再確認 |
回避flagが変える意味を理解する
npm config(新しいタブで開く)によれば、legacy-peer-depsは依存ツリー構築時にpeerDependenciesを無視します。--omit=peerはdiskへ展開しない扱いで、同じ意味ではありません。peer contractを無視してinstallできても、その組合せの実行時互換性が確認されたことにはなりません。
strict-peer-depsの設定も確認します。公式資料は、これを有効にすると、通常なら警告付きで解決できる深い依存のpeer競合も失敗とする場合を説明しています。個人環境の設定だけで通る状態を、チーム共通の解決と扱わないようにします。
回避策を一時採用する場合は、対象、必要な理由、未確認の互換性、外す条件を記録します。グローバル設定で全projectへ広げず、projectの管理方針に従います。lockfileやnode_modulesを削除して最初からやり直す操作を、ログ確認の前提にはしません。
install成功の後に機能を検証する
修正候補は隔離した検証環境で適用し、manifestとlockの差分を対にして確認します。解決されたhostとplugin版が意図したものか、関連するテストや実行経路が動くかを確かめます。CIとのnpm版・設定差も確認します。
完了記録には、衝突していたpeerの要求元、採用した組合せ、変更した依存、lock差分の範囲、動作確認と未確認事項を残します。installが終了した事実だけを「依存の互換性が直った」と言い換えないことが、再発時の切り分けに役立ちます。
