なぜ、あなたの `package.json` は「魔窟」と化すのか?
開発の現場でよく目にする光景があります。`scripts` セクションが50行を超え、`&&` が乱立し、どのコマンドがどの順序で依存しているのか、誰にも読み解けない「スパゲッティ・スクリプト」です。
「とりあえず動けばいい」と継ぎ足されたビルドコマンドは、やがて開発者の脳を疲弊させ、CI/CDパイプラインを不可解なエラーで停止させます。
今日は、そんな泥沼から脱出し、「コマンドのオーケストラ」を指揮するための2つの武器を紹介します。それが `npm-run-all` と `npm-run-path` です。これらを使いこなすことは、単なるツール導入ではなく、開発体験(DX)を再定義する第一歩になります。
—
1. npm-run-all:スクリプトの「指揮者」
標準の `npm run script1 && npm run script2` には致命的な欠点があります。1つが失敗した瞬間に後続が止まること、そして何より「並列実行」が極めて書きにくいことです。
`npm-run-all` は、複数のスクリプトを「直列(sequential)」または「並列(parallel)」に美しく制御するための標準規格と言えるツールです。
インストールと基本概念
まずはプロジェクトに導入しましょう。
開発時のみ必要なツールとしてインストール
npm install –save-dev npm-run-all
なぜこれが「現場」で必須なのか
例えば、TypeScriptの型チェック、Lint、そしてテストを同時に走らせる場合を考えてみましょう。
{
“scripts”: {
“lint”: “eslint src/”,
“typecheck”: “tsc –noEmit”,
“test”: “jest”,
“validate”: “npm-run-all –parallel lint typecheck test”
}
}
- `–parallel`: これを使うと、複数のタスクが独立したプロセスで同時に走ります。CPUのマルチコアを活かし、ビルド時間を劇的に短縮できます。
- `–sequential` (デフォルト): 順番に実行します。ビルド完了後にデプロイするなど、依存関係がある場合に最適です。
現場の知見:
このツールの真骨頂は「ワイルドカード」にあります。`npm-run-all –parallel build:` と書けば、`build:css`, `build:js`, `build:assets` をすべて同時に起動できます。コマンドを増やすたびに親スクリプトを書き換える必要はもうありません。
—
2. npm-run-path:環境変数の「魔術師」
大規模プロジェクトでは、`node_modules/.bin` にあるバイナリを直接叩きたい場面が多々あります。しかし、OSやシェルによってパスの解決順序が異なり、CI環境でだけ「コマンドが見つかりません」という悲劇が起こります。
`npm-run-path` は、「現在のプロジェクトのローカル環境」を優先した実行パスを、プログラム的に注入するためのツールです。
なぜこれが必要か
外部ツール(例えばPythonスクリプトやシェルスクリプト)から、プロジェクト内の `eslint` や `jest` を呼び出したいとき、単純な `exec()` では環境変数が正しく引き継がれません。このツールは、その実行環境を「プロジェクトのコンテキスト」に強制的に適合させます。
動作確認:HelloWorld的アプローチ
Node.jsスクリプト内で、ローカルのツールを安全に呼び出す例です。
// run-tool.js
const { spawn } = require(‘child_process’);
const npmRunPath = require(‘npm-run-path’);
// 現在のプロジェクトの node_modules/.bin を含めたパス環境変数を生成
const env = npmRunPath.env();
// これで、どんな場所から実行してもローカルの eslint が正確に呼び出される
spawn(‘eslint’, [‘src/’], { env, stdio: ‘inherit’ });
この小さなコードが、あなたのビルドスクリプトを「OSに依存しない堅牢なもの」に変えます。
—
大規模プロジェクトを整理する「作法」
これらを使って `package.json` を再設計する際、以下のルールを適用してみてください。
1. 単一責任の原則: 1つのスクリプトは1つのタスクだけを行う。
2. 名前空間の活用: `build:css`, `build:js` のようにプレフィックスを付ける。
3. 抽象化: 複雑な処理は `scripts/` ディレクトリに `.js` や `.sh` ファイルとして逃がし、`package.json` からはそれらを呼び出すだけにする。
劇的な改善の実感
これらを導入すると、あなたの開発環境はこう変わります。
- Before: 「ビルドが終わらない…どのコマンドが止まってるんだ?」とログを彷徨う。
- After: `npm run validate` と打つだけで、Lintもテストも同時に走り、結果が色分けされて整然と出力される。
最後に
道具は使い手によって価値が決まります。`npm-run-all` と `npm-run-path` は、あなたのプロジェクトがどれだけ巨大になっても、その実行フローを「制御可能な領域」に留めてくれる頼もしいガードレールです。
さあ、今日からあなたのスクリプトに「秩序」を取り戻しましょう。この小さな一歩が、数ヶ月後のあなた自身の開発効率を、数倍に跳ね上げるはずです。何か詰まったら、いつでも戻ってきてくださいね。応援しています。