Handpick で lintDependencies や testDependencies を管理しよう!
React + TypeScript 構成などで巨大な Node.js プロジェクトを構築していると面倒になってくるのが、devDependencies
に積まれた開発用 npm パッケージの量。
大量の ESLint Config や Prettier 関連のツールが並び、テストのために Jest や Playwright などがインストールされている。
これらは Lint のため、Unit Test や E2E テストのために必要なツールであり、package.json
で管理したいのは山々なのだが、いかんせん物量が多いと npm install
に時間がかかるようになる。
また、CI サーバを導入していて、feature ブランチであっても Lint やテストは Git Push に応じて CI サーバで回してしまう場合もあるだろう。そうすると、開発者のローカルマシンに大量の Linter や Testing ツールを導入する必要は、必ずしも必要でなかったりもする。
そんなワケで、devDependencies
内にある Lint 用のパッケージ、テスト用のパッケージなどを切り出して、devDependencies
を軽くしたい、という要件が挙がった。
そこで調べたところ、Handpick という npm パッケージでコレを実現できそうなのでやってみることにした。
検証プロジェクト
Handpick の挙動を確認するためのサンプルプロジェクトを以下に用意した。
Vite で react-ts プロジェクトを立ち上げ、Linter として ESLint 系のパッケージを用意した。最初は --save-dev
で devDependencies
に追加して動作確認したが、一通り確認が終わったら、次のように package.json
に lintDependencies
という項目を増やしてそちらにパッケージ群を記載するようにした。
package.json
{
// …中略…
"dependencies": {
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@types/react": "18.3.11",
"@types/react-dom": "18.3.0",
"@vitejs/plugin-react": "4.3.2",
"typescript": "5.6.3",
"vite": "5.4.8"
},
"lintDependencies": {
"@eslint/js": "9.12.0",
"eslint": "9.12.0",
"eslint-plugin-react": "7.37.1",
"eslint-plugin-react-hooks": "5.1.0-rc-fb9a90fa48-20240614",
"eslint-plugin-react-refresh": "0.4.12",
"globals": "15.11.0",
"typescript-eslint": "8.8.1"
}
}
名称は lintDependencies
としたが、この名前は任意に決められる。ユニットテスト系の依存パッケージを増やしたければ testDependencies
、E2E テストを別けて書きたければ e2eDependencies
などと名前を付けてやると、依存パッケージの宣言だと分かりやすいであろう。
パッケージ数が少ないものの、こうして別けてみると見通しが良くて分かりやすくなった。
devDependencies
は開発用サーバを立てたりビルドしたり、コーディング時に使用する型定義類のパッケージlintDependencies
は色々入っているが、とにかく ESLint を回す時に必要になるパッケージ
というのが一目瞭然である。
Handpick で個別にインストールしてみる
さて、Handpick というツールは、一時的に package.json
の dependencies
部分を書き換えることで動作する仕組みになっている。npm
の他に yarn
や pnpm
にも対応しており、内部的にはこれらのインストールコマンドを直接実行する形になっている。
まずは Handpick をグローバルインストールしよう。
$ npm install --global handpick
そして $ handpick
とオプションなしで実行すると、dependencies
と devDependencies
がインストールされる挙動になっている。
それでは lintDependencies
をインストールする場合はどうするかというと、次のように --target
オプションを指定する。
$ handpick --target=lintDependencies
すると、コマンド実行中だけ、package.json
の dependencies
の内容が lintDependencies
のモノになり、前述の検証プロジェクトでいうと ESLint 類だけインストールされる形となる。なお、この時 dependencies
と devDependencies
のパッケージはインストールされない。本当に lintDependencies
に書かれたモノだけがインストールされる動きとなる。
使用するツールによっては dependencies
・devDependencies
と、それにプラスして lintDependencies
もインストールしたい、という場合が多いと思うので、そういう時は以下のように3つとも --target
オプションに指定してやることで対応できる。
$ handpick --target=dependencies --target=devDependencies --target=lintDependencies
コレは素晴らしい~
そんなワケで、Handpick というツールを使うと、devDependencies
にひとまとまりになってしまう Linter や Testing ツール類を、lintDependencies
や testDependencies
として切り出して管理ができる。
コレにより npm install
の所要時間を削減でき、開発者は今までどおり npm install
で開発に必要なツールだけインストールできる。
そして CI サーバなどでは handpick
コマンドを用いることで lintDependencies
などを追加でインストールしてやることで、CI サーバ上では Lint や Test が行えるようになる。もちろん、ローカルで開発者が handpick
コマンドを使えば同じことができる。
これらを同じ単一の package.json
で管理できるので、とても分かりやすく見通しが良い。
ESLint 系のパッケージが肥大化してしまっているプロジェクトではかなりオススメだ。