IEサポートも終わるので、npmパッケージのDependabot Alertsを解消しつつアプリの動きに支障なくアップデートさせる

フロントエンド開発を長年悩ましてきたInternet Explorer 11（以下IE11）のサポートが2022年6月15日ついに終了となります。

https://www.itmedia.co.jp/pcuser/articles/2105/21/news053.html

https://blogs.windows.com/japan/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/

これを受けて、サポートを続けていた既存のWebアプリもサポートを切る流れが現在進行系で加速していることでしょう。
ソース管理にGitHubを使用している場合、Dependabot Alertsが何十件、下手したら何百件と溜まっているかもしれません。npmパッケージをアップデートしてくれというメッセージを添えて。

npmパッケージは数年経つとバージョンが大きく上がるケースは多いです。規模の大きいパッケージになっていくと、いわゆるbreaking change（破壊的変更）が複数回含まれることも少なくありません。

この点を踏まえて、何も考えずアップデートしてDependabot Alertsをすべて解消したらアプリがビルドすら出来ずに動かなくなりました！一般にも公開するのにどうしましょう！な展開を避けるためにはどう対処すれば良いのでしょうか？今回は私自身の経験も踏まえてまとめていきます[^1]。

[^1]: あなたはどんな開発してきたの？って聞かれそうなので回答ですが、一般の人も使うとあるWebアプリのVue開発を担当しています。

:::note warn
本記事で紹介する手順はパッケージ管理がyarn(1.x系)であることを前提としています。npmなど別のパッケージ管理ツールを使用している場合は、都度コマンドを置き換えていただければと思います。またnpmに関して、パッケージ管理ツールとコマンドの意味を区別するため、後者を表す場合は`npm`と記載しています。
:::

# GitHubのDependabot Alertsとは？ 

GitHub上で運用しているリポジトリの設定がOn（デフォルトもOn）になっていると、リポジトリページに表示される警告です。
アプリにインストールされている依存パッケージの脆弱性を自動で検知・警告＆場合によってはPRを自動で生成してくれる便利機能です。ここで言う依存パッケージは`package.json`に明記されているパッケージだけでなく、`package.lock.json`/`yarn.lock`といったlockファイルにしか記載されていないパッケージも対象となります。

詳しく知りたい方は以下のページを読んでみてください。

https://docs.github.com/ja/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-dependabot-security-updates

https://zenn.dev/yuuhu04/articles/about-github-alert

# `npm audit fix`を使ってアップデートし、Dependabot Alertsを解消する

解消するためにターミナルで叩くコマンドは以下のとおりです。

```bash
$ yarn audit
$ npm i --package-lock-only
$ npm audit fix --force
$ rm yarn.lock
$ yarn import
$ rm package-lock.json
$ rm -rf node_modules
$ yarn # yarn install でも可能
```

何をしているのか、順を追って説明します。

## Dependabot Alertsの一覧を確認

```bash
$ yarn audit
```

https://classic.yarnpkg.com/lang/en/docs/cli/audit/

これはDependabot Alertsの一覧にターミナル上で吐き出してくれるコマンドです。`--level [info|low|moderate|high|critical]`フラグをつけると指定した警告度のものだけ表示されます。アップデートする度にalerts数の確認のためにこまめに叩いておきましょう。

## `npm audit fix`で実際にパッケージのアップデートを行う

```bash
$ npm i --package-lock-only
$ npm audit fix --force
$ rm yarn.lock
$ yarn import
$ rm package-lock.json
```

https://docs.npmjs.com/cli/v6/configuring-npm/package-locks#resolving-lockfile-conflicts

https://docs.npmjs.com/cli/v8/commands/npm-audit#examples

https://classic.yarnpkg.com/en/docs/cli/import

`npm audit fix`コマンドは`package.json`に明記されているパッケージの子パッケージのalerts解消も考慮した状態までアップデートしてくれるコマンドです。
ただし、`npm audit fix`コマンドに該当するコマンドが`yarn`にはないため、`npm i --package-lock-only`でまず`package.json`の内容を基に`package-lock.json`を生成します。
そして`npm audit fix --force`でパッケージのアップデートを行います。この際、`package-lock.json`の内容も書き換わります。

ここで`--force`フラグの有無の違いについて質問が飛んできそうなので、説明します。正直npmのドキュメント読んでも分かりづらいため、ここは説明が難しいところですが、私はこんな風に解釈しています。
- `--force`フラグなし: `package.json`に明記されているパッケージに限り、パッケージそのものにalertsが出ていれば、修正したバージョンへアップデートを行う。 
- `--force`フラグあり: `package.json`に明記されているパッケージの依存パッケージでalertsが出ている→`package.json`に明記されているパッケージについて、その依存パッケージがalertsの出ないバージョンへ修正された状態のバージョンへアップデートを行う。

`--force`フラグありの意味が自分で書いておいてよくわからなくなっていますが、要は`package.json`に明記されているパッケージの子パッケージのalerts解消も考慮した状態までアップデートしてくれるよ、の意味で取っていただければと思います。

`package-lock.json`の内容を`yarn.lock`に反映させたいので、一旦既存のものを削除し`yarn import`で再度生成します。

## アップデート後、ビルド出来るかなどを確認

```bash
$ rm -rf node_modules
$ yarn # yarn install でも可能
```

`node_modules`にはまだアップデート前の情報が残ったままなので一旦消して、再度生成しましょう。
終わったら、ビルドしてみたりアプリ起動したりして、正常に既存アプリが動作するかを確認しましょう。`yarn audit`での確認も忘れずに。またLinter/Formatter/テストコードが入っている場合はこちらも合わせて確認しておきましょう。

流れとしては以上です。コマンドの説明を終えたので、ここから具体的な対処方法の解説をしていきます。

# 依存パッケージ数別アップデート手順

`package.json`にいるパッケージ数の規模によってアップデート手順が少し違ってくるので分けて説明します。
※パッケージ数はあくまで私の経験則による目安です。パッケージが大きいものばかりという可能性もあるので、目安はケースバイケースで変更してください。

## パッケージ数が小規模（<=15くらい）

まだ数が少ないので、[こちらの節](#npm-audit-fixを使ってアップデートしdependabot-alertsを解消する)で解説した方法のみで問題ありません。時間もかからない＆万が一何か合った場合に原因の特定が難しくないからです。


## パッケージ数が中〜大規模（>15くらい）

規模が大きくなるので、一辺にアップデートしてしまうと万が一何か合った場合の原因特定/原因となったライブラリの切り分けが難しくなっていきます。ですので私の経験上、以下の方法をオススメします。

1. 基本的に前述のアップデートコマンドを叩いて、`npm audit fix --force`ではなく、`npm audit fix`で叩く
2. ビルドエラー等出ないか確認 
3. 前述のアップデートコマンドそのまま叩く
4. 再度ビルドエラー等出ないか確認 

# こんなときどうすればいいの？集

`npm audit fix`の方法だけですんなり上手くいけばいいのですが、やはり上手くいかない場合も多々あります。私の経験で実際に対処したケースをここにまとめておきます。

## `npm audit fix`でアップデートしたのにDependabot Alertsが解消されない

このケースは残念ながら度々発生します。この場合、alertsが出ているパッケージは`package.json`に明記されているパッケージから更に枝分かれ形式で依存しているものであるケースがほとんどです。

この場合、yarnの`resolutions`機能を使ってalertsが出ているパッケージを指定する方法で対処する方法があります。

まず`yarn audit`などでalerts一覧を確認し、そこでpatched versionに書かれたバージョンを`package.json`の`resolutions`欄に追記しましょう。

コード例では以下のことを行っています（パッケージ名はあくまで例です）。
- hogehogeというパッケージのバージョンが`2.1.3`で固定されてインストールされる
- fugaというパッケージのバージョンが`1.1.5` < `2.0.0`の間でインストールされる

```diff_json: package.json
{
   "devDependencies": {
    ...
   },
+  "resolutions": {
+    "hogehoge": "2.1.3"
+    "fuga": "^1.1.5"
+  }
}
```

これで再度`yarn`もしくは`yarn install`コマンドでパッケージをインストールし、yarn auditすると`resolutions`したパッケージのalertsが消えます。

`resolutions`機能をもう少し詳しく知りたい方は以下のページを参考にしてみてください。

https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/

https://numb86-tech.hatenablog.com/entry/2020/05/26/170627

https://zenn.dev/azu/articles/d56615b2e11ad1#yarn%E3%81%A7%E3%81%AEresolutions%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E5%9B%BA%E5%AE%9A%E6%96%B9%E6%B3%95

※`npm`を使用している場合、version8.3以降限定ですが、`overrides`機能で代用可能なようです。

## ESLintとPrettierが喧嘩する

ESLintとPrettierはモダンフロント開発におけるLinter/Formatterのデファクトスタンダードです。

そんなESLintとPrettierですが、アップデートを行うと、ESLint的にはOKだが、PrettierとしてはNGとなる現象も多々発生します（私は遭遇したことないですが、逆のケースも勿論存在すると思います）。この場合、vscodeなどで出るエラー解消ボタンを押してコードを修正しても今度はESLintとしてNGになってしまいます。なぜこんなことが起こるようになってしまったのでしょうか？

Prettierはversion 2.x系以降において末尾カンマの有無などデフォルト設定が大きく変更されました。詳しい変更点の内容は以下の記事を参考にしてもらえばと思います。

https://prettier.io/blog/2020/03/21/2.0.0.html

https://qiita.com/sosukesuzuki/items/50a5ed5e7079eb9da0fe

Prettier側の設定で上記変更点を一部offにすることは可能なのですが、残念ながらPrettier側から変更出来る設定は少なく全部の競合の制御は不可能な仕様となっています。ですので、ESLint側の方を上手く制御してあげる必要があります。

https://prettier.io/docs/en/options.html

Prettier側としては、[eslint-config-prettier](https://github.com/prettier/eslint-config-prettier)というPrettier側のルールと競合しうるESLintルールをoffしてくれるライブラリを使って競合を避けることが推奨されています[^2]。もしこのeslint-config-prettierが入っていても、競合が発生するのであればpluginも含めたESLint関連のパッケージのバージョン指定を一度見直しましょう。

https://prettier.io/docs/en/integrating-with-linters.html

[^2]: [ここ](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md#version-700-2020-12-05)に書かれている通り、version 7.x以降はESLintのversion7.x以降のインストールが必須とされているため、ご注意ください。

## Node.jsのバージョンが指定されているため、パッケージのバージョンを上げたくても上げられない

プロジェクトによっては、使用するNode.jsのバージョンが指定されている場合があります。この場合、パッケージによってはアップデート出来ないケースがあり得ます。

私が出会ったパッケージでは[node-sass](https://github.com/sass/node-sass)がこれに該当します。README見てもらえばわかると思いますが、Node.jsのバージョンによってインストールするバージョンが指定されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/c0f2941d-04e5-9369-431d-9c5e46e878d6.png)
（引用：[node-sassのREADME](https://github.com/sass/node-sass#node-version-support-policy)より）

もう非推奨なんだし、さっさと[dart-sass](https://github.com/sass/dart-sass)に乗り換えればいいのにの声が聞こえてきそうですが、現実はそんなわけにはいきません。以下のページを見てもらえばと思いますが、`@import`から`@use`への変更を筆頭に文法が一部変更されています。

https://buildersbox.corp-sansan.com/entry/2021/03/10/110000

https://haniwaman.com/dart-sass/

アプリの規模が大きい場合、既存の大量のsass/scssファイルの精査/書き換え作業が必要になります。もはやこのレベルならアップデート作業が完了した後に、別タスクとしてやるかnode-sassのままにしておくべきでしょう（正直dart-sassへの移行は、E2E Test環境やVisual Regression Testing環境が完備されているとかでもない限り、山積みの手動テストが必要になるのでかなり難しい）。

そんなわけでalertsを消すだけなら、前述のyarnの`resolutions`機能を活用しましょう。（もしalertsを全て消してくれという要求がされているのであれば、今回はNode.jsのバージョンの影響で解消出来なかったです、Node.jsのバージョン云々は今後相談させてくださいみたいな話をマネジメント層を通してきちんと相談しましょう。）

# まとめ
今回は私の経験則を基にnpmパッケージのアップデート対応方法をまとめてみました。alertsを一掃するだけならそんなに難しくないのですが、アプリを動かすまでのパッケージバージョンの指定/設定の追記修正がなかなか難しいです。

また対処集もいくつか載せてみましたが、こんなケースもあった、もっとこうすれば楽に進められるなどのご意見があればコメントいただけると非常に嬉しいです。ではIEに苦しめられない良いフロント開発ライフを願って！

# 参考ページ

https://stackoverflow.com/questions/51732435/is-there-a-yarn-alternative-for-npm-audit

https://stackoverflow.com/questions/22343224/whats-the-difference-between-tilde-and-caret-in-package-json