npm で依存関係のあるライブラリのバージョンアップの仕方

# 前提
他のライブラリとの依存関係が問題にならない場合、 `npm install <package-name>@latest` でライブラリのバージョンを最新に上げることができるため難しいことはありません。  

問題は多くのライブラリと依存関係にあるライブラリ（例：`react` ）のバージョンを上げる場合です。  

単に `npm install react@latest` としても依存関係の問題でコマンドが失敗してしまいます。

依存関係を無視して無理やりバージョンを上げる方法もありますが、その場合は他のライブラリとの依存関係の解決に失敗した状態になります。  

こうなるとそれ以降 `npm install` が全て失敗するようになり、非常に困ります。

以下の方針にしたがって順番にライブラリのバージョンをあげていくことで依存関係を解決できる状態を維持してライブラリをバージョンアップできます。

# 使用するコマンド
以下のコマンドを使用します。

- `npm install <package-name>`
- `npm install <package-name>@latest`
- `npm list <package-name>`
- `npm outdated`

## `npm install`

`npm install <package-name>` と `npm install <package-name>@latest` の二つのコマンドを使用します。  
これらは微妙に挙動が異なるので違いを押さえておきましょう。

### `npm install <package-name>`
このコマンドは、package.json に記載されているバージョン範囲に基づいて、指定したパッケージをインストールします。  
もし package.json にバージョン範囲が指定されていない場合は、最新の互換バージョンがインストールされます。

### `npm install <package-name>@latest`
このコマンドは、指定したパッケージの最新バージョンをインストールします。package.json に記載されたバージョン範囲に関係なく、常に最新のバージョンがインストールされます。

### 主な違い

|  | バージョンの選定 | 互換性 |
| --- | --- | --- |
|`npm install <package-name>` | package.json に基づいたバージョン範囲内でインストール | プロジェクトの依存関係に基づいて互換性を保つ |
|`npm install <package-name>@latest` | 常に最新バージョンをインストール | 最新機能や修正を取り入れるが、互換性の問題が発生する可能性がある |

## `npm list <package-name>`

`npm list <package-name>` コマンドは、指定したパッケージの依存関係を表示するために使用されます。  
このコマンドを使うと、特定のパッケージがどのような依存関係を持っているかを確認できます。

出力例

このコマンドを実行すると、以下のような出力が得られます：

```
project-name@1.0.0 /path/to/project
└─┬ express@4.17.1
  ├── accepts@1.3.7
  ├── array-flatten@1.1.1
  ├── body-parser@1.19.0
  └── ...
```

主なポイント

- ツリー形式で依存関係が表示され、どのパッケージがどのバージョンに依存しているかがわかります。  
- 特定のパッケージの依存関係を詳細に確認するのに便利です。  
- このコマンドを使うことで、プロジェクト内の依存関係を把握しやすくなり、トラブルシューティングやメンテナンスが容易になります。  


## `npm outdated`

npm で管理しているライブラリのうち更新可能なものの一覧を表示します。

実行例

```
npm outdated
Package         Current  Wanted  Latest  Location
express         4.17.1   4.18.0  4.18.1  my-project/node_modules/express
lodash          4.17.20  4.17.21 4.17.21 my-project/node_modules/lodash
moment          2.29.1   2.29.4  2.29.4  my-project/node_modules/moment
```

主なポイント

- Package: パッケージ名。
- Current: 現在インストールされているバージョン。
- Wanted: package.json に記載されているバージョン範囲内での最新バージョン。
- Latest: npmリポジトリで利用可能な最新バージョン。
- Location: パッケージのインストール場所。


# 手順

以下の手順で進めましょう。

1. 目的のライブラリを `npm instlal <package-name>` で更新してみます。
    * ここで目的のバージョンに上がれば完了です！
    * 上がらなかった場合は以降の手順に進みましょう。
2. 目的のライブラリを `npm install <package-name>@latest` で更新してみます。
    * ここで目的のバージョンに上がれば完了です！
    * ここでライブラリに依存関係がある場合コマンドが失敗し、以下のようなエラーメッセージが出ます。以降の手順に進みましょう。
  
    <details><summary>エラーメッセージの例</summary>
    
    ```
    npm install react@latest
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^18.3.0" from react-dom@18.3.0
    npm warn node_modules/react-dom
    npm warn   react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" from @storybook/addon-docs@8.6.12
    npm warn   node_modules/@storybook/addon-docs
    npm warn   9 more (@storybook/blocks, @storybook/icons, @storybook/react, ...)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^16.8.0 || ^17 || ^18" from react-hook-form@7.48.2
    npm warn node_modules/react-hook-form
    npm warn   peer react-hook-form@"^7.0.0" from @hookform/resolvers@3.3.2
    npm warn   node_modules/@hookform/resolvers
    npm warn   1 more (the root project)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^16.8.0 || ^17 || ^18" from react-hook-form@7.48.2
    npm warn node_modules/react-hook-form
    npm warn   peer react-hook-form@"^7.0.0" from @hookform/resolvers@3.3.2
    npm warn   node_modules/@hookform/resolvers
    npm warn   1 more (the root project)
    npm warn ERESOLVE overriding peer dependency
    npm warn While resolving: react@0.0.0
    npm warn Found: react@18.3.0
    npm warn node_modules/react
    npm warn   peer react@">=16" from @mdx-js/react@3.1.0
    npm warn   node_modules/@mdx-js/react
    npm warn     @mdx-js/react@"^3.0.0" from @storybook/addon-docs@8.6.12
    npm warn     node_modules/@storybook/addon-docs
    npm warn   19 more (@storybook/addon-docs, @storybook/addon-links, ...)
    npm warn
    npm warn Could not resolve dependency:
    npm warn peer react@"^16.0.0 || ^17.0.0 || ^18.0.0" from react-simple-keyboard@3.7.66
    npm warn node_modules/react-simple-keyboard
    npm warn   react-simple-keyboard@"^3.7.66" from the root project
    npm error code ERESOLVE
    npm error ERESOLVE unable to resolve dependency tree
    npm error
    npm error While resolving: react@0.0.0
    npm error Found: react@19.1.0
    npm error node_modules/react
    npm error   react@"19.1.0" from the root project
    npm error
    npm error Could not resolve dependency:
    npm error peer react@"^18.3.1" from react-dom@18.3.1
    npm error node_modules/react-dom
    npm error   react-dom@"^18.2.0" from the root project
    npm error
    npm error Fix the upstream dependency conflict, or retry
    npm error this command with --force or --legacy-peer-deps
    npm error to accept an incorrect (and potentially broken) dependency resolution.
    npm error
    npm error
    npm error For a full report see:
    ```
    </details>

3. `npm list <package-name>` で目的のライブラリの依存関係を確認します。
4. `npm outdated` の内容と比較し、依存関係のライブラリの中で更新可能なものを確認します。
5. 更新可能な各ライブラリについて、手順1. から順に実行してライブラリを更新します。

# やめたほうが良いこと

- `npm install` で `--force`, `--legacy-peer-deps` のオプションを使用して依存関係を無視してパッケージを更新する
- `package.json` にあるバージョンを直接書き換えて `npm install` でパッケージを更新する

これらを行うことで依存関係を無視してパッケージを更新できます。

しかし上記の方法で依存関係が解決できない状態になるとそれ以降 `npm install` が全て失敗するようになり、非常に困ります。

そのため上記の方法は使わないほうが良いです。