9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

npm v7以降のpeerDependencies採用方針

Last updated at Posted at 2023-08-15

先に結論だけ

このような依存関係のパッケージがあるとします。

パッケージA
    ┗ パッケージB
        ┗ パッケージC

npm v7以降のpackage.jsonではpeerDependenciesを以下の方針で採用しましょう。

  • パッケージBとCで、違うバージョンのパッケージAを使う場合dependenciesを使う
  • パッケージBとCで、同じバージョンのパッケージAが必要な場合はpeerDependenciesを使う

パッケージBでpeerDependenciesを使う場合は

  • パッケージBでは、パッケージAをdependenciesdevDependenciesには入れない
  • パッケージCでも、パッケージAをdependenciesdevDependenciesには入れない

はじめに

この記事は、npm v7以降のpackage.jsonでpeerDependenciesがどのように振る舞うかの実験と、その結果から依存パッケージをどのフィールドにインストールすべきかの方針を記録、共有するためのものです。

想定する環境

% node --version
v18.15.0
% npm --version
9.5.0

対象となるバージョンが変わると、記事の内容がそのまま適用できないかもしれません。記事を読む前に、お手元の環境をご確認ください。

想定する読者

  • npmモジュールの開発者
  • 開発しているモジュールが、他のモジュールに依存している

npm v7での破壊的変更

npm V7でpeerDependenciesフィールドの挙動に破壊的変更が加えられました。大きな変更点は以下の2点です。

peerDependenciesのバージョン評価が厳密になった

従来のpeerDependenciesでは、矛盾するバージョンのパッケージがインストールされても警告が表示されるだけでした。npm v7以降では、peerDependenciesの設定と矛盾するバージョンがインストールされるとエラーが発生し、インストールが中断されます。

peerDependenciesがインストールされるようになった

npm v7以降では、peerDependenciesで指定したパッケージが自動的にインストールされるようになりました。以前のようにdependenciesやdevDependenciesに追加する必要はありません。

peerDependenciesを指定した場合のバージョン解決

それぞれのパッケージで、peerDependenciesとdependenciesを指定した場合どのようにバージョンが解決されるかを実験してみます。

パッケージBの場合

まずは、直接peerDependenciesを指定したパッケージの振る舞いを確認します。

peerDependenviesのみを指定する

▼package-b/package.json

  "peerDependencies": {
    "package-a": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0"
  }

この場合、指定範囲内のもっとも高いバージョン4.0.0がインストールされます。

peerDependenciesとdependenciesを併記する

▼package-b/package.json

  "peerDependencies": {
    "package-a": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0"
  },
  "dependencies": {
    "package-a": "^3.0.0"
  },

この場合、両方の指定範囲内のもっとも高いバージョン3.0.0がインストールされます。

peerDependenciesとdependenciesを併記し、矛盾させる

▼package-b/package.json

  "peerDependencies": {
    "package-a": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0"
  },
  "dependencies": {
    "package-a": "^0.1.0"
  },

この場合、dependenciesが優先され0.1.0がインストールされます。インストール時にエラーは発生しません。peerDependenciesが強制力を発揮するのは、このパッケージを参照する先であり、自分自身には強制しません。

パッケージCの場合

パッケージBに依存するパッケージCで、依存パッケージがどのようにバージョン解決されるかを実験します。

パッケージBでpeerDependenciesのみを指定する

▼package-b/package.json

  "version": "1.0.0",
  "peerDependencies": {
    "package-a": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0"
  }

▼package-c/package.json

  "dependencies": {
    "package-b": "^1.0.0"
  }

この場合、パッケージCではパッケージAの4.0.0がインストールされます。

パッケージBでpeerDependenciesを指定し、パッケージCで矛盾したバージョンを指定する

▼package-b/package.json

  "version": "1.0.0",
  "peerDependencies": {
    "package-a": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0"
  }

▼package-c/package.json

  "dependencies": {
    "package-b": "^1.0.0",
    "package-a": "^0.1.0"
  }
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree

バージョンの解決に失敗し、エラーが発生します。インストールは中断されます。

パッケージBとCでdependenciesを指定する

▼package-b/package.json

  "dependencies": {
    "package-a": "^2.0.0"
  }

▼package-c/package.json

  "dependencies": {
    "package-b": "^1.0.0",
    "package-a": "^4.0.0"
  }

この場合、以下の2つがインストールされます。

  • package-c/node_modules : package-a 4.0.0
  • package-c/node_modules/package-b/node_modules : package-a 2.0.0

dependenciesとpeerDependenciesの採用方針

実験結果から、それぞれのパッケージでdependenciesとpeerDependenciesのどちらを採用すべきか方針を割り出します。

パッケージAの複数バージョンが併存するか否か

パッケージBでdependenciesとpeerDependenciesのどちらを利用するかは、パッケージAの複数のバージョンが併存するか否かで決定します。

パッケージBとCがそれぞれパッケージAに依存するが、パッケージAのグローバル変数を利用しない場合、dependenciesを利用します。それぞれがパッケージAのインスタンスを作成し、使い終われば破棄する場合はこの条件に該当します。

パッケージAのグローバル変数を利用し、その変数がパッケージBとCで共有されなければいけない場合、peerDependenciesを利用します。プラグインモジュールを作成する場合はこの条件に該当します。

たとえばパッケージAがシングルトンを作り状態を保存する場合、バージョンが共通していないと動作しません。

peerDependenciesとdependencies / devDependenciesの併用

パッケージBでpeerDependenciesを採用したなら、パッケージAはdependencies / devDependenciesに追記してはいけません。npm v7以降では、peerDependenciesは自動的にインストールされます。

過去のバージョンの動作確認をする時のみdevDependenciesを利用し、公開時には削除しましょう。

GitHub ActionsのDependabotを使う場合のみ併用する

あなたがGitHub ActionsのDependabotなど、依存関係を自動更新するCI環境を持っている場合は、peerDependenciesとdevDependenciesの併用を検討してください。

DependabotはpeerDependenciesのバージョンを確認しません。devDependenciesに同じ依存先を指定しておけば、Dependabotはバージョンの確認と更新PRを発行します。

peerDepencenciesのバージョン指定

peerDependenciesを使う場合、動作確認ができる範囲で広いバージョンを指定しましょう。

peerDependenciesはインストール中にエラーを発生させます。下位互換を削除する場合はセマンティックバージョニングにしたがってメジャーバージョンを変更しましょう。


以上、ありがとうございました。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?