Nodeで作ったCLIツールににローディングや対話モデルを追加する
oclifでCLIツールをちょいちょい作るのですが、いろいろエフェクトや機能が欲しくなってきたので、後で見返すように覚え書き。 ローディングアニメーション的なものを入れる コマンド内でnpm installや非同期通信を […]
目次
oclifでCLIツールをちょいちょい作るのですが、いろいろエフェクトや機能が欲しくなってきたので、後で見返すように覚え書き。
ローディングアニメーション的なものを入れる
コマンド内でnpm installや非同期通信をさせてる場合、「あれ、ちゃんと動いてる?」となる時があります。ということで、待機中はローディング的なもの出しましょう。今回はcli-spinnerを使います。
$ npm i -S cli-spinner
ローディングの必要な処理を用意する
oclifだとasync / awaitで処理を書いていきます。なのでテストするときは、以下のようなsleepのプロミスを用意すると良いでしょう。
const sleep = sec => new Promise(resolve => setTimeout(resolve, sec))
処理はこんな感じで書けます。
const {Command} = require('@oclif/command')
const Spinner = require('cli-spinner').Spinner;
const sleep = sec => new Promise(resolve => setTimeout(resolve, sec))
class HelloCommand extends Command {
async run() {
const spinner = new Spinner('processing.. %s');
spinner.setSpinnerString('|/-\\');
spinner.start();
// ここに非同期処理
await sleep(1000)
spinner.stop();
// 結果を出す前に、改行を
this.log(`\n`)
this.log(`Finished`)
}
}
実行すると、こんな感じになります。
$ ./bin/run hello
processing.. \
Finished
spinner.setSpinnerString()
の引数文字列が順番に表示されます。
対話式にする
引数に必要なデータが無い場合やセットアップコマンドでは、再度コマンドを入力させるより対話式で確認した方が効率的です。ここからは、inquirerを使って実装してみます。
$ npm i -S inquirer
oclifの場合、flagにプロパティがあるかどうかを確認して、なければ選ばせるという方法を取ることができます。以下のようなヘルパーを書いておくと良いでしょう。
const inquirer = require('inquirer')
const getServiceName = async flags => {
if (flags.name) return flags.name
const responses = await inquirer.prompt([{
name: 'name',
message: 'select a service name',
type: 'list',
choices: [{name: 'AWS'}, {name: 'GCP'}, {name: 'Azure'}],
}])
return responses.name
}
あとはコマンドの処理部分に組み込みましょう。
class HelloCommand extends Command {
async run() {
const {flags} = this.parse(HelloCommand)
const name = await getServiceName(flags)
this.log(`You choose ${name}!`)
}
}
こうすることで、以下のように対話式でデータを入力させることができます。
$ ./bin/run hello
? select a service name (Use arrow keys)
❯ AWS
GCP
Azure
You choose AWS!
$ ./bin/run hello --name GCP
You choose GCP!
テキスト入力にすることや、複数項目にすることも可能です。
const responses = await inquirer.prompt([{
name: 'name',
message: 'put a service name',
type: 'input',
}, {
name: 'comment',
message: 'put a comment',
type: 'input',
}])
こんな感じですね。
$ ./bin/run hello
? put a service name Amazon Web Service
? put a comment
You choose Amazon Web Service!
OSで通知を出す
node-notifierでデスクトップ通知を出すこともできます。
$ npm i -S node-notifier
const {Command} = require('@oclif/command')
const Spinner = require('cli-spinner').Spinner;
const notifier = require('node-notifier')
const sleep = sec => new Promise(resolve => setTimeout(resolve, sec))
class HelloCommand extends Command {
async run() {
const spinner = new Spinner('processing.. %s');
spinner.setSpinnerString('|/-\\');
spinner.start();
// ここに非同期処理
await sleep(1000)
spinner.stop();
// 結果を出す前に、改行を
this.log(`\n`)
this.log(`Finished`)
notifier.notify({
title: 'My CLI Example',
message: 'Finished'
})
}
}
これで処理が完了すると通知が出るようになります。
オプションで通知音の有無やアイコンのカスタマイズもできます。
notifier.notify({
title: 'My CLI Example',
message: 'Finished',
icon: path.join(__dirname, 'hello.png'),
sound: true,
wait: true
})
Happy Node.js CLI Life !
ここにchalkを加えると、かなりいい感じのCLIツールっぽいものが作れる(はず)です。
最近作り始めたばかりですが、よくやるタスクをまとめていくと結構楽かつ楽しいので皆さんも是非。