このブログははてなブログからの移行記事です。
npm run hogeでエラーを出したくない
eslintでのチェックやトランスパイルの実行は下のような感じでpackage.jsonに書いてnpm run lint等で実行するようにしてる。
{ "scripts": [ "lint": "eslint src/", "build": "babel src --out-dir dest" } }
その際、eslint実行等の場合はコマンドの実行自体がコケるだけでnpmが鬱陶しいエラーを出してくる。

欲しいのはnpm scriptの結果で、下のはnpm初心者には無益で紛らわしいログでしかない
これをどうにかしたい
解決策を調べる
どうにかできないか調べてみた。
解決策その1:--silentオプションをつける
npmにはloglevelという概念があり、これにオプションを指定するとログの出力形式を変更できる。
その中の1つに--silentがあるのでnpm scriptを実行する際にこのオプションをつける。
省略形で-sでもよい。

これで鬱陶しさはなくなったが
- 毎回オプションをつけなければいけない
- npm-debug.logを吐き出さないので本当にnpm由来のエラーが発生したらオプション外してもう一回実行しなきゃいけない
というデメリットがある
解決策その2:.npmrcを設定する
最近こんな記事を読んだ。
今まで知らなかったのが本当にもったいないくらい最高の話で、ローカルにnpmコマンドの設定を保持できる。
なので.npmrcを作成し、以下の用なオプションを指定すると常時、loglevelがsilentになる
loglevel=silent
これで毎回オプションを足す手間は省ける。
ただし、これにもデメリットがあって
- CI等でこうするとエラーが発生したときにログが読めない
npm-debug.logが吐き出されない
という問題が依然として残る
解決策その3:aliasでごまかす
後にも言うけどこの問題に根本的解決策は現状ないです。
なので上記デメリットを吸収できる方法は思いつく限りだとshellのaliadを指定する方法です。
要は単純で、alias名は何でもいいんだけど例えば下記のようなものを各々のdotfilesに追記する。
alias npm-run='npm run --silent $*'
これでnpm scriptsを実行したいときはnpm-run lintとかで実行する。
ログが欲しい時やCIではnpm run lintを使う。
解決策番外編:pipeで無理やり成功させる
これは全然解決策じゃなくて、絶対にやめたほうがよいのであえて書いた。
何かというと、npmのissueやstackoverflowを眺めてると「npm scriptに|| true足せばいいよ」ってのがあって
npm scriptの実行結果を無理やりtrueに持っていけばエラーじゃないからログも出ないぜという話。
{ "scripts" [ "lint": "eslint src/ || true" ] }
ただ、確かにログは吐かなくなるんだけどnpm scriptの実行が失敗してもコマンドがこけないので
CI等で実行してる場合は例えばeslintが失敗してもそれを補足できなくなる。
絶対にやめような^^
結論
現状、「標準出力にいらんエラーを吐かせず、npm-debug.logはちゃんと残してくれるnpm scriptの書き方」はない。
ので以下の2策に逃げるしか無い気がする。
- npm script実行時は
-sオプションをつける .npmrcでloglevel=silentを指定する
ただし、前者は複数人開発だと周知が面倒だし後者はいざというときにログが無くて死ぬ可能性がある。
npmのissueにもこの話題はあがっていて、dev環境用のnpm scriptsを用意しようとかいろいろ提案されているみたい。
run-scripts are too noisy while used in development · Issue #8821 · npm/npm · GitHub
個人的にはnpm慣れてるので、個人ではshellのaliasで逃げつつチームの時はこのブログ記事ぶん投げようかなという感じ。
追記
匿名の方より以下のコメントをいただきました。

これであれば「標準出力にいらんエラーを吐かせず、npm-debug.logはちゃんと残してくれるnpm scriptの書き方」を実現できそうです。
具体的にはこんな感じのshellを書いて使う。
#!/bin/zsh
###
# npm run with slim
###
DOTFILES_NPM_ERROR_LOG="$HOME/.dotfiles/dist/npm_error.log"
function npmrun() {
npm run $1 2>$DOTFILES_NPM_ERROR_LOG
if [ ! $? -eq 0 ]; then
echo "npm error log recorded at $DOTFILES_NPM_ERROR_LOG"
return 1
fi
}
もしかしたらもっと良い書き方があるかもだが、これでひとまず解決した。最高!
COMMENT: コマンドラインだと、「npm run test 2>error.log」と手も。