inquirer.jsを使用してCLIアプリケーションに対話型インターフェースを導入する
UI開発者 永田この記事はミツエーリンクス Advent Calendar 2019 - Qiitaの7日目の記事です。
昨今のWebフロントエンド業界では、HTML、CSS、JSの開発を行う際にwebpack、Gulpといった技術の活用や、Vue.js、Reactなどのフレームワークの使用が当たり前となってきています。
それらの開発環境を導入するためには、ターミナルからnpm経由でパッケージをインストールすることになりますが、最近ではターミナルからCLIアプリケーションを操作しながら開発を行う場面も増えてきました。
技術の移り変わりが激しい業界であるゆえにかと思いますが、それはつまり、フロントエンドエンジニアも黒い画面(ターミナル)と向き合い、CLIの操作に慣れておく必要があるということです。
本稿ではNode.jsでCLIアプリケーションを作成する時に役立つnpmパッケージ「inquirer.js」の使い方を紹介しつつ、対話形式の楽しいインターフェースをターミナル上で動作させていきます。
実際にCLIアプリケーションを作成してガッツリとコマンドの設定を書いていくわけではありませんが、CLIを操作したことがない方でも楽しく黒い画面を操作することができる内容となっておりますので、CLIアプリケーションを作ってみたい、黒い画面と仲良くなりたいと思っている方の学習の足がかりになれば幸いです。
inquirer.js
CLIアプリケーションに対話型のインターフェースを組み込むことができるパッケージです。
導入することで、簡単かつ少ないコードでインタラクティブなCLIアプリケーションを作成できます。
オプションも豊富で、text input、list(番号付きも可)、checkbox、passwordなど、さまざまな対話形式に対応しています。
インストール
まずはプロジェクトの初期化と実行用のJSファイルを作成します。
npm init -y
Linux
touch index.js
Windows(PowerShell)
ni index.js
プロジェクトを実行しやすいように、package.jsonのscriptsにstart
コマンドを追加しておきましょう。
"scripts": {
"start": "node index.js"
},
最後に、さきほど作成したindex.js
でモジュールを読み込みます。
const inquirer = require('inquirer');
以上でinquirer.js
を実行する準備が整いました。
基本的な使い方
inquirer.prompt(questions)
メソッドを使用して対話を設定します。
引数questions
はArray型ですので、オプションを設定したオブジェクトを配列に追加し、引数に設定します。
今回は以下のオプションを使用します。
- type: (String) - 対話形式の選択 [ input (default)、 number、 confirm、 list、 rawlist、 expand、 checkbox、 password、 editor ]
- name: (String) - promptの識別名
- message: (String | Function) - ターミナルに出力する質問テキスト
- default: (String | Number | Boolean | Array | Function) - 未入力時に表示するデフォルト値
- mask: (String) - パスワード入力中のマスク表示で使用する文字列
- choices: (Array | Function) - 回答項目リスト。
new inquirer.Separator()
を配列に追加することでセパレータを表示する - validate: (Function) - バリデーションを実行する関数。値が有効な場合はtrueを返却する
実行準備
以下のコードをindex.jsに追加します。
type
オプションが設定されていない場合、inputの対話形式として設定されます。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
}
]);
promptメソッドの戻り地はPromiseオブジェクトですので、then()でつなげていきます。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
}
])
.then(answers => {
console.info('USERNAME:', answers.username);
});
これで対話型インターフェースの導入が完了しました!
実行
npm start
で実行します。
npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. (mlc-user)
さきほど設定した質問文が表示されました!
続けて回答を入力します。
npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
Username is mlc-nagata
入力した内容が出力されました。簡単です!
さまざまな質問形式
前述したように、inquire.jsはさまざまな対話形式に対応しているので、いろいろ試してみます。
引数の配列に新規オブジェクトを追加するだけで対話を連結させることができます。
質問の回答はanswers
にすべて格納される仕組みです。
type
オプションに任意の対話形式を設定します。
Password
ユーザーの入力が表示されます。
mask
オプションを設定しない場合は入力中のマスク文字は表示されず、ユーザーの入力はすべて非表示になります。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
},
{
type: 'password',
name: 'password',
message: 'Enter your password.',
mask: '*'
}
])
.then(answers => {
console.info('USERNAME:', answers.username);
console.info('PASSWORD:', answers.password);
});
実行します。
$ npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
? Enter your password. ***************
入力中の文字列がマスクされていることが確認できます。
List
任意の選択肢を定義して、リスト形式で提示することができます。
choices
に選択肢の配列を設定します。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
},
{
type: 'password',
name: 'password',
message: 'Enter your password.',
mask: '*'
},
{
type: 'list',
name: 'region',
message: 'Choose A Region.',
choices: ['Americas', 'Europe', 'Asia Pacific']
}
])
.then(answers => {
console.info('USERNAME:', answers.username);
console.info('PASSWORD:', answers.password);
console.info('REGION:', answers.region);
});
実行します。
$ npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
? Enter your password. ***************
? Choose A Region. (Use arrow keys)
> Americas
Europe
Asia Pacific
選択式リストが表示されました。
checkbox
選択肢の複数選択が可能になります。
Listと同じように、choices
を設定します。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
},
{
type: 'password',
name: 'password',
message: 'Enter your password.',
mask: '*'
},
{
type: 'list',
name: 'region',
message: 'Choose A Region.',
choices: ['Americas', 'Europe', 'Asia Pacific'],
},
{
type: 'checkbox',
name: 'favoriteFrameworks',
message: 'Choose your favorite JS frameworks.',
choices: ['Vue', 'React', 'Angular', 'jQuery', 'Others']
}
])
.then(answers => {
console.info('USERNAME:', answers.username);
console.info('PASSWORD:', answers.password);
console.info('REGION:', answers.region);
console.info('FAVORITE FRAMEWORKS:', answers.favorites);
});
実行します。
$ npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
? Enter your password. ***************
? Choose A Region. Americas
? Choose your favorite JS frameworks. (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) Vue
( ) React
( ) Angular
( ) jQuery
( ) Others
チェックボックスと操作説明のテキストが表示されました。
Validate
ユーザーの入力を受け取り、バリデーションをかけることができます。
const inquirer = require('inquirer');
inquirer
.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
},
{
type: 'password',
name: 'password',
message: 'Enter your password.',
mask: '*'
},
{
type: 'list',
name: 'region',
message: 'Choose A Region.',
choices: ['Americas', 'Europe', 'Asia Pacific'],
},
{
type: 'checkbox',
name: 'favoriteFrameworks',
message: 'Choose your favorite JS frameworks.',
choices: ['Vue', 'React', 'Angular', 'jQuery', 'Others']
},
{
type: 'input',
name: 'favoriteNumber',
message: 'Enter any number from 2 to 3 digits.',
validate: (input) => {
if (Number.isFinite(Number.parseInt(input)) && input.match(/^[0-9]{2,3}$/)) {
return true;
} else {
return 'invalid value'
}
}
}
])
.then(answers => {
console.info('USERNAME:', answers.username);
console.info('PASSWORD:', answers.password);
console.info('REGION:', answers.region);
console.info('FAVORITE FRAMEWORKS:', answers.favorites);
console.info('FAVORITE NUMBER:', answers.favorites);
});
2~3桁までの好きな数字を入力し、値に対してバリデーションを実行させます。
$ npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
? Enter your password. ***************
? Choose A Region. Americas
? Choose your favorite JS frameworks. Vue, jQuery, Others
? Enter any number from 2 to 3 digits. test
>> invalid value
試しにtest
と入力してみた結果、バリデーターから返却されたメッセージが出力されました。
実行結果
$ npm start
> node-cli@1.0.0 start D:\works\node-cli
> node index.js
? Enter your username. mlc-nagata
? Enter your password. ***************
? Choose A Region. Americas
? Choose your favorite JS frameworks. Vue, jQuery, Others
? Enter any number from 2 to 3 digits. 328
USERNAME: mlc-nagata
PASSWORD: sample-password
REGION: Americas
FAVORITE FRAMEWORKS: [ 'Vue', 'jQuery', 'Others' ]
FAVORITE NUMBER: 328
すべての対話が完了した後に回答が出力されています。
モジュール化
実際に使用する際にはモジュールとして再利用しやすい状態であってほしいので、これまでに作成したコードをモジュール化しておきます。
以下の手順で新規JSファイルを作成します。
Linux
mkdir ./lib/; touch ./lib/questions.js
Windows (PowerShell)
ni ./lib/ -ItemType Directory; ni ./lib/questions.js
作成した./lib/questions.js
に以下の内容を記述します。
const inquirer = require('inquirer');
module.exports = {
userInfo: () => {
return inquirer.prompt([
{
name: 'username',
message: 'Enter your username.',
default: 'mlc-user'
},
{
type: 'password',
name: 'password',
message: 'Enter your password.',
mask: '*'
},
{
type: 'list',
name: 'region',
message: 'Choose A Region.',
choices: ['Americas', 'Europe', 'Asia Pacific'],
},
{
type: 'checkbox',
name: 'favoriteFrameworks',
message: 'Choose your favorite JS frameworks.',
choices: ['Vue', 'React', 'Angular', 'jQuery', 'Others']
},
{
type: 'input',
name: 'favoriteNumber',
message: 'Enter any number from 2 to 3 digits.',
validate: (input) => {
if (Number.isFinite(Number.parseInt(input)) && input.match(/^[0-9]{2,3}$/)) {
return true;
} else {
return 'invalid valuel';
}
}
}
]);
}
};
次に、例としてindex.jsを以下のように修正します。
const questions = require('./lib/questions');
const execUserInfoSurvey = async () => {
return await questions.userInfo();
};
const execute = () => {
execUserInfoSurvey().then((userInfo) => {
console.info(userInfo);
});
};
execute();
async
、 await
と組み合わせるとより使いやすくなるかと思います。
おわりに
inquirer.jsは、少ないコードでリッチな表現を追加することができる素晴らしいライブラリです。
本稿で紹介していないオプションやメソッドを備えていますので、ぜひ試してみてください。
今回の記事はNode.jsの勉強としてCLIアプリケーションを作成した際の備忘録も兼ねているのですが、機会があればCLIアプリケーション自体の作り方についても書くことができればと思います。