初めてnpmのCLIパッケージを作成してみました。
コマンドライン引数の受け取りやプロンプトの表示など、難しそうなイメージだった部分も、ライブラリを使うことで手軽に実装できたので、それらを紹介したいと思います。
作成したパッケージ
利用しなくなったプロジェクトの node_modules
や dist
フォルダを探して削除するための clean-node-projects
というパッケージを作成しました。
npx clean-node-projects
とすることで、そのパスの配下のフォルダが検索され、どれを削除するか選ぶことができます。
CLIパッケージの基本
コマンドラインから呼び出すアプリを作るためには、
まず package.json
の bin
という項目に、 { コマンド名: 実行ファイルパス }
を記載します。
...
"bin": {
"test-cli": "./bin/test-cli"
},
実行ファイルは、ファイル名を指定するだけで実行できるように、nodeのシェバンを書きます。
#!/usr/bin/env node
console.log('Hello world');
このパッケージをnpmに公開すれば、 test-cli
を実行することで Hello world
と表示されるアプリができます。
便利なライブラリ
yargs
yargsは、受け取ったコマンドライン引数を使いやすい形に整えたり、かっこいいヘルプメッセージを生成してくれるライブラリです。
#!/usr/bin/env node
const yargs = require('yargs');
const slicedArgs = process.argv.slice(2); // 最初の2つは受け取った引数ではないので除外
const argv = yargs(slicedArgs)
.option('option-a', {
alias: 'a',
description: 'オプションA',
type: 'number'
})
.option('option-b', {
alias: 'b',
description: 'オプションB',
type: 'array',
default: ['foo', 'bar']
})
.help().argv;
console.log(argv.a);
console.log(argv.b);
上記のファイルを test-cli --help
のように実行すると以下のようなメッセージが表示されます。
オプション:
--version バージョンを表示 [真偽]
-a, --option-a オプションA [数値]
-b, --option-b オプションB [配列] [デフォルト: ["foo","bar"]]
--help ヘルプを表示 [真偽]
test-cli -a 100
のように実行すると、指定した型で値を取得できることがわかります。
console.log(argv.a); // => 100
console.log(argv.b); // => [ 'foo', 'bar' ] (デフォルト値)
inquirer
inquirerは、対話型のインターフェースを簡単に実装できるライブラリです。
チェックボックス選択式の例
#!/usr/bin/env node
const inquirer = require('inquirer');
const prompt = async () => {
const result = await inquirer.prompt({
type: 'checkbox',
name: 'folders',
message: 'Select folders to remove',
choices: ['aaa/bbb/ccc', 'aaa/bbb/ddd', 'aaa/bbb/eee', 'fff/ggg/hhh']
});
console.log(result.folders);
};
prompt();
上記を実行すると、以下のようにスペースで選択したり a
で全選択したりできる入力受付状態になります。
console.log(result.folders); // => [ 'aaa/bbb/ccc', 'aaa/bbb/ddd' ]
columnify
columnifyは、データを列を揃えて見やすく表示するためのライブラリです。
#!/usr/bin/env node
const columnify = require('columnify');
const result = columnify([
{ path: '/aaa/bbb/ccc', 'last access': '2022/01/01', size: '20MB'},
{ path: '/aaa/bbb/ddd', 'last access': '2022/01/03', size: '40MB'},
{ path: '/aaa/bbb/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'last access': '2022/01/07', size: '90MB'}
], { maxWidth: 40 });
console.log(result);
実行結果
PATH LAST ACCESS SIZE
/aaa/bbb/ccc 2022/01/01 20MB
/aaa/bbb/ddd 2022/01/03 40MB
/aaa/bbb/eeeeeeeeeeeeeeeeeeeeeeeeeeeeee… 2022/01/07 90MB
eeeee
結果は文字列で得られるので、inquirerと組み合わせて綺麗に表示する際は色々工夫が必要でした。
感想
素晴らしいライブラリの製作者の方々に感謝です。
もしよければ clean-node-projects も使ってみていただけると嬉しいです。
今後モチベーションが続けば、ちゃんとテストを書いて、ファイル読み込みを並列に実行するなど、改善できたら良いなと思っています。
参考