はじめに
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!')
})
結果こちら。
うーん、、、殺風景。
せっかく綺麗に出してくれるyarnの出力が真っ白になっておる
色・絵文字を再現するには
オプションに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
の結果そのまんまですね!美しい!
余計な空行も消えてます。
もう少し詳しく
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)
参考サイト
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で子プロセスの標準入出力を処理する
右から左へ受け流す
日本語の情報がなかなか少なかったです。
今後は、僕のこの記事でサクッと解決ですねっ