LoginSignup
6

More than 5 years have passed since last update.

Node.jsで外部コマンドを実行中に、ログを色付きで標準(エラー)出力

Last updated at Posted at 2018-05-23

はじめに

Node.jsのCLIツールを作っております。
そのツール内で外部コマンドとしてyarn installを叩くんですが、
実行中のログに色とか絵文字がつかず、プレーンテキストで出て来ちゃったので、
綺麗に出力する方法を調べたのでメモです。

教科書通りにやると殺風景に

Nodeから外部コマンド実行は初めてだったので、
こちらのchild_processのドキュメントと睨めっこしながら色々調べました。
https://nodejs.org/api/child_process.html

child_process.exec()だと「実行が終わってから何かする」って感じだったので、インストール状況を逐次出力は無理だなーと思い、
child_process.spawn()を使ってこうしてみました。

const path = require('path')
const { spawn } = require('child_process')

const dirPath = path.resolve('project-dir')
const yarnInstall = spawn('yarn', ['install'], { cwd: dirPath })

// 実行中に標準エラー出力・標準出力を随時画面に出していく
yarnInstall.stderr.on('data', data => {
  console.error(data.toString())
})
yarnInstall.stdout.on('data', data => {
  console.log(data.toString())
})

// 終了時の処理
yarnInstall.on('close', code => {
  if (code !== 0) {
    console.error(`yarn process exited with code ${code}`)
  }
  console.log('`yarn install`:  done!')
})

結果こちら。
スクリーンショット 2018-05-23 23.35.43.png
うーん、、、殺風景。
せっかく綺麗に出してくれるyarnの出力が真っ白になっておる :cry:

色・絵文字を再現するには

オプションにstdio: 'inherit'を加えてやって、
自前のログ出力処理を外しちゃえばOK!

const path = require('path')
const { spawn } = require('child_process')

const dirPath = path.resolve('project-dir')
// 標準入出力はすべて右から左へ受け流す
const yarnInstall = spawn('yarn', ['install'], { cwd: dirPath, stdio: 'inherit' })

// 終了時の処理
yarnInstall.on('close', code => {
  if (code !== 0) {
    console.error(`yarn process exited with code ${code}`)
  }
  console.log('`yarn install`:  done!')
})

結果はコチラ。yarn installの結果そのまんまですね!美しい!
余計な空行も消えてます。

スクリーンショット 2018-05-23 23.35.59.png

もう少し詳しく

options.stdioの公式docはコチラ。
https://nodejs.org/api/child_process.html#child_process_options_stdio

stdio: 'inherit'が「色・絵文字を再現」という表現は正確ではなくて、
「標準入出力をspawnではハンドリングせず、そのまんまスルーしてターミナルに出す」
って感じのようです。

その証拠に、stdio: 'inherit'を付けて実行中はstderrなどがnullになっちゃうので、
stderr.on()とか書くとエラーになるのですねぇ。
エラー出てるのに標準出力はちゃんとされるので、最初意味わからずハマりましたw

const yarnInstall = spawn('yarn', ['install'], { cwd: dirPath, stdio: 'inherit' })
yarnInstall.stderr.on('data', data => {
  console.error(data.toString())
})
yarnInstall.stderr.on('data', data => {
                   ^

TypeError: Cannot read property 'on' of null
    at Object.<anonymous> (/hoge/fuga/exec-yarn-install.js:6:20)
    at Module._compile (internal/modules/cjs/loader.js:678:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
    at Module.load (internal/modules/cjs/loader.js:589:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
    at Function.Module._load (internal/modules/cjs/loader.js:520:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
    at startup (internal/bootstrap/node.js:228:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)

スクリーンショット 2018-05-23 23.53.09.png

参考サイト

child_process and color : node - Reddit
node.js - preserve color when executing child_process.spawn - Stack Overflow
javascript - Retaining output colors when shelling out to node - Stack Overflow
Node.jsで子プロセスを起動し、非同期的に実行する
Node.jsで子プロセスの標準入出力を処理する
右から左へ受け流す

日本語の情報がなかなか少なかったです。
今後は、僕のこの記事でサクッと解決ですねっ:mag: :truck: :link: :page_with_curl: :sparkles:

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6