2020-04-14

【Node.js】CLIでロード中にクルクル回るアレ(スピナー)を作る

CLIでインストールするようなプログラムで良く採用されているロード中にクルクル回ってるアレを作る方法。

Article Image

サンプル

こんなものを作る

spinner

ことの発端

socket.ioを使っているとデータを「受信している or 止まっている」が目視で分かりにくい。

データが入ってくる度にconsole.logをしているとデータ数によっては画面が勢いよく流れてしまうのでこういった場合はロード中によく見るようなスピナーがあれば良いと考えた。

今回のサンプルはGatsbyjsをビルドする時に画面に表示される物をイメージしている(同じようなものが出る)

コード

import rl from 'readline'

const spin_char = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]

let spin_count = 0;
function spin(message) {
    process.stdout.write('\x1B[?25l') //カーソルを消す
    rl.clearLine(process.stdout, 0) //行をすべて削除
    rl.moveCursor(process.stdout, -9999, 0) //一番左側に戻る
    process.stdout.write(`${spin_char[spin_count]} ${message}`) //spin_charの配列で描画
    spin_count++ //要素番号計算
    spin_count >= spin_char.length ? spin_count = 0 : null //要素番号のリセット
}

//process.stderr.write('\x1B[?25h') //カーソルを戻すコードはこれ

setInterval(() => {
    spin("Loading");
}, 200);

インストールするライブラリ無しでコピペして実行すればスピナーが回るのがメリットである。

ちょっと解説

まず console.log は改行が強制的に入るので使えない。改行せずに画面に文字を描画するコードはprocess.stdout.write() である。

process.stdout.write('\x1B[?25l') このコードがないとカーソルが残る。カーソルが残ると画面がちらつくため非常に見栄えが悪くなる。このあとカーソルを再び表示する場合は process.stderr.write('\x1B[?25h') を使おう。

またES6以降のコードではあるが(拡張子をmjsにする必要がある)Node.jsのコードとして${文字列}は**テンプレートリテラル(またはテンプレート文字列)という文法の中のプレースホルダー**と呼ぶ。テンプレートリテラルとはバックティック(` `)で文字列を表現すること。これにより文字列中に幾つも変数を挿入できるので便利だ。

clearLineだけで行の文字が消えるのでは?と思ったが行は削除されるがカーソルの位置が前の文字列の最後で止まったままなので、ずれた位置からスピナーが開始されてしまう。その対応として moveCursorで先頭に戻している。

moveCursorの第2引数は9999文字左に移動という意味だがあまりスマートには見えない。もっと良いコードがあるかもしれない。

参考サイト

主に参考にしたサイト[英語]: Build Command-Line Spinners in Node.js

カーソルを消すコードはこちらを参考にした[英語]: https://github.com/visionmedia/node-progress/issues/88

所感

このコードだけだと永遠に回り続けるので、別途ロード等に合わせるコードを用意する必要がある。

さらに拡張してバーでのローディング表示なども試してみたい。



この記事のタグ

この記事をシェア


謎の技術研究部 (謎技研)