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 系のパッケージが肥大化してしまっているプロジェクトではかなりオススメだ。