npm-run-all examples
実装は以下のリポジトリにおいてあります。
https://github.com/algas/npm-run-all-example
背景
node.js でカレントディレクトリだけではなくサブディレクトリでも同じコマンドを同時に実行したいことがあります。
例えば、下記のようなディレクトリ構成の時に parent
, child
, child2
で同時に npm install
や npm test
などのコマンドを実行したい場合です。
parent/
|- package.json
|- child/
|- package.json
|- child2/
|- package.json
サブディレクトリで npm コマンドを実行する
npm install --prefix (SUB_DIRECTORY)
のように --prefix
オプションでサブディレクトリを指定することで、サブディレクトリの package.json
で定義されている、またはデフォルトで使える npm コマンドを実行することができます。
サブディレクトリの数が少ない場合には上記のオプションを使えば、同時にコマンドを実行できます。
しかし、多くのサブディレクトリがある場合には、並列に実行したり実行順番や実行結果の成功を担保するようにコマンドをつないで行くのは容易ではありません。
npm コマンドを複数同時に実行する
npm-run-all
という npm パッケージを使うと、複数の npm コマンドを逐次・並列実行するのが容易になります。
https://github.com/mysticatea/npm-run-all
例えば、lint
と build
という npm コマンドが使える場合には以下のコマンドで同時に実行できるようになります。
- 逐次実行:
npm-run-all -s lint build
- 並列実行:
npm-run-all -p lint build
npm-run-all
以外にも lerna などのパッケージがありますが、「npm コマンドとして実行したい」という今回の目的にそぐわないので使わないことにしました。
サブディレクトリでも同時に npm コマンドを実行する
--prefix
オプションと npm-run-all
を組み合わせることによってサブディレクトリでも同時に npm コマンドを実行することができるようになります。
汎用的にコマンドを実行するために下記のようなラッパーコマンドを用意しました。
{
"scripts": {
"all-install": "npm-run-all -p \"prefix:* -- install\"",
"all-test": "npm-run-all -s \"prefix:* -- test\"",
"all-p": "npm-run-all -p \"run:* -- {@}\"",
"all-s": "npm-run-all -s \"run:* -- {@}\"",
"all-p-hello": "npm run all-p hello",
"all-s-hello": "npm run all-s hello",
"prefix:self": "npm --prefix ./",
"prefix:child": "npm --prefix ./child",
"prefix:child2": "npm --prefix ./child2",
"run:self": "npm --prefix ./ run",
"run:child": "npm --prefix ./child run",
"run:child2": "npm --prefix ./child2 run",
"hello": "echo \"Hello world\"",
"test": "echo \"Test\""
}
}
コマンド概要
-
npm run all-install
:npm install
をすべて(parent, child, child2)のディレクトリで実行します。 -
npm run all-test
:npm test
をすべて(parent, child, child2)のディレクトリで実行します。 -
npm run all-p
: 任意の npm コマンドをすべて(parent, child, child2)のディレクトリで並列実行します。 -
npm run all-s
: 任意の npm コマンドをすべて(parent, child, child2)のディレクトリで逐次実行します。
注意点
- 同じコマンドを同時に実行するには child, child2 以下の
package.json
にもnpm script
を定義する必要があります。 -
all-s
の実行順を厳密に定義するには、本記事の例のように*
を使わずに直接すべてのディレクトリの順番を明示すべきです。 - 「シェルスクリプトやその他の言語でスクリプトを書けばいいのに」というツッコミは受け付けておりません。