Node.jsでCLIアプリケーションを構築する方法

CLI(コマンドラインインターフェース)アプリケーションは、特定のタスクを完了するためにターミナルで実行される、単純なテキストベースのアプリケーションです。CLIアプリケーションは、ほとんどすべての開発者とIT専門家のワークフローにおいて重要な役割を果たしています。

CLIアプリケーションは、主にオペレーティングシステムまたはローカルにインストールされているか、インターネット経由で利用可能なアプリケーションと対話し、ユーザーの入力と指示に従ってタスクを実行するユーティリティツールです。

CLIアプリケーションの理解

コマンドラインインターフェースを使用すると、テキスト行を入力することでプログラムと対話できます。多くのCLIプログラムは、起動に使用したコマンドによって動作が異なります。

たとえば、lsプログラムはファイル情報とディレクトリの内容を表示します。次のように実行できます。

ls -l /home

このコマンドには以下が含まれます。

  • プログラムの名前:ls
  • オプション(またはフラグ)。この場合、-lは「long」の略で、より詳細な情報を生成するオプションです。
  • 引数、/home。ここでは、引数は情報を表示するディレクトリへのパスを指定します。

各プログラムは独自のコマンドラインインターフェースを定義できますが、共通の要素があり、広く使用されています。コマンドラインインターフェースに慣れている人がプログラムを簡単に使用できるように、これらの標準に従う必要があります。

Commander.jsとは

Commander.jsは、Node.jsでCLIアプリケーションを構築できるパッケージです。標準的なCLIアプリケーションを構築するための豊富なライブラリ機能があり、多くの面倒な作業を行います。CLIアプリケーションのコマンド、オプション、機能を定義するだけで済みます。

スタイル設定用のChalk.jsなどの他のパッケージと組み合わせると、Node.jsで完全に機能するCLIアプリケーションをすばやく作成できます。

Commander.jsを使用したNode.jsでのCLIアプリケーションの構築

CLIアプリケーションの例として、urbanary-cliを考えてみましょう。これは、Urban Dictionaryから単語やソーシャルメディアの略語の意味を調べます。CLIを作成し、npmパッケージレジストリに公開して、他の人がインストールできるようにする方法を学びます。

次のコマンドで新しいフォルダーを作成し、新しいNode.jsプロジェクトを初期化します。

mkdir urbanary-cli
cd urbanary-cli
npm init -y

このCLIはAxiosを使用して、HTTPリクエストをUrban Dictionary APIに送信します。Rapid APIを使用して、エンドポイントを確認したり、資格情報を確認したりできます。

サブコマンドとヘルプを備えたシンプルなCLI

CLIの構築を開始するには、次のコマンドでCommanderとAxiosをインストールします。

npm install commander axios

プロジェクトディレクトリにbinという新しいフォルダーと、新しい空のファイルindex.jsを作成します。

mkdir bin
cd bin
touch index.js

bin(バイナリの略)フォルダーは、CLIを実行するとNodeが呼び出すエントリポイントファイルがあるため重要です。index.jsファイルはこのエントリポイントファイルです。次に、index.jsファイルを編集して、Commander.js APIでCLIの構築を開始します。

まず、Commanderからprogramオブジェクトをインポートします。

const { program } = require('commander');

programオブジェクトを使用して、サブコマンド、オプション、引数を含むプログラムのインターフェースを定義します。このオブジェクトには、それぞれに対応するメソッドがあります。たとえば、サブコマンドを定義するには、commandメソッドを使用します。

CLIがUrban Dictionaryから単語を検索するためのfindサブコマンドを定義し、次のコードを使用して説明を追加します。

// index.js
program
.command('find <word>')
.description('find meaning of a word or abbreviation or slang')

これにより、単語を必要とするfindコマンドと、その説明が登録されます。山カッコを使用すると、単語が必要な引数であることが示されます。代わりに角カッコ([])を使用すると、オプションになります。

Commander.jsがヘルプテキストを生成するために使用する説明を追加する必要があります。helpコマンドでアプリケーションを実行すると、標準の使用ガイドが表示されます。

これをテストするには、以下を追加します。

program.parse()

次に、プログラムを実行してhelpコマンドを渡すと、以下の出力が得られます。

標準的なCLIアプリケーションはすべて、ユーザーにヘルプを表示します。Commanderを使用すると、自分で作成する必要はありません。-hオプションと--helpオプションは、コマンドの使用ガイドを確認するのに役立ちます。

オプションの定義と最終的なプログラムの準備

コマンド定義にoptionメソッドをチェーンすることで、オプションを定義することもできます。

単語の定義に例を含めるためのオプションを定義する方法は次のとおりです。

program.option('-e, --example', "Display examples")

そして、返す定義の数を指定するオプションを定義する方法は次のとおりです。

program.option(
'-c, --count [amount]',
'amount of definitions to display (max is 10)'
)

optionメソッドは2つの文字列パラメータを受け取り、1つはオプションの名前(短縮形と長形の両方)用、もう1つは説明用です。countオプションの追加の[amount]引数は、表示する定義の数の値です。

最後に追加するメソッドはactionメソッドです。このメソッド内でfindコマンドの機能を実装します。チェーンに追加して、コードが次のようになるようにします。

program
.command('find <word>')
.description('find meaning of a word or abbreviation or slang')
.option('-e, --example', "Display examples")
.option(
'-c, --count [amount]',
'amount of definitions to display (max is 10)'
)
.action(async (word, options) => {});

この設定では、lolの定義を3つ取得し、例を示すコマンドは次のようになります。

urbanary-cli find lol -e -c 3

​または、各オプションの長い形式を使用します。

urbanary-cli find lol --example --count 3

Commanderのnpmページで詳細を確認し、さまざまなユースケースに合わせて機能を調整する方法を学びましょう。

プログラムの機能を実装する

まず、index.jsファイルにAxiosを次のようにインポートします。

const axios = require('axios');

次に、actionのパラメータの関数本体で、Urban Dictionaryにリクエストを行い、オプションに従って結果を表示するロジックを実装できます。

リクエストを定義することから始めます。

let requestOptions = {
method: 'GET',
URL: "https://mashape-community-urban-dictionary.p.rapidapi.com/define",
params: { term: word },
headers: {
'X-RapidAPI-Key': YOUR_RAPID_API_KEY,
'X-RapidAPI-Host': 'mashape-community-urban-dictionary.p.rapidapi.com'
}
}

次に、次のコードを使用してAxiosを使用してAPIにリクエストを行います。

try {let resp = await axios.request(requestOptions);console.log(Definitions for ${word} fetched);wordData = resp.data.list;} catch (err) {console.error(err.message)}

レスポンスデータから必要なプロパティは、定義と例を保持するlistプロパティのみです。

tryブロックのまま、このロジックを追加してオプションを処理し、次のように結果を表示します。

if (options.example && options.count) {let cnt = 1;let definitions = wordData.slice(0, options.count);definitions.forEach((elem) => {console.log(Definition ${cnt++}: ${elem.definition});console.log(Example:\n${elem.example}\n);});} else if (options.count && !options.example) {let cnt = 1;let definitions = wordData.slice(0, options.count);definitions.forEach((elem) => {console.log(Definition ${cnt++}: ${elem.definition});});} else if (options.example) {console.log(Definition: ${wordData[0].definition});console.log(Example:\n${wordData[0].example});} else {console.log(Definition: ${wordData[0].definition});}

このコードは、if-elseステートメントを使用してコマンド引数を評価し、出力を表示する方法を決定します。exampleオプションとcountオプションが渡された場合、wordDataを反復処理し、指定された数の定義と例をそれらとともに印刷します。

countのみを渡した場合、例なしでその量の定義が表示されます。exampleのみを渡した場合、1つの定義と例文が表示されます。elseステートメントは、オプションを渡さなかった場合に定義のみを印刷するデフォルトの動作です。

アプリケーションの準備が整ったので、次のステップは実行可能にすることです。まず、bin/index.jsファイルの先頭にshebang行を追加して、スタンドアロンスクリプトとして実行できるようにします。

#!/usr/bin/env node

次に、package.jsonファイルを開き、mainプロパティの値を編集し、その後にbinプロパティを次のように追加します。

"main": "./bin/index.js",
"bin": {
"urbanary-cli": "./bin/index.js"
},

binの下のキーurbanary-cliは、ターミナルでアプリケーションを実行するために使用するコマンドです。そのため、コマンドラインアプリケーションを作成するときは、適切な名前を使用してください。

npm install -gを実行してアプリケーションをグローバルにインストールすると、ターミナルからコマンドとしてアプリケーションを実行できるようになります。

以下の画像は、インストールプロセスとlmkの意味を見つけるためのテストコマンドを示しています。

また、プロジェクトディレクトリ内のターミナルでnpm publishを実行することで、npmパッケージレジストリに公開することもできます。これにより、誰でもどこからでもnpm installを使用してインストールできるようになります。

RustなどのテクノロジーでCLIを構築する場合と比較して、Node.jsでアプリケーションを構築して公開する方が簡単です。

Node.jsで機能的なCLIアプリケーションを構築する

npmパッケージに取り組んでいて、それを補完するCLIユーティリティが必要な場合でも、開発者としてワークフローを改善するためのツールを構築したい場合でも。Node.js Commanderパッケージがあれば、アイデアを実現するために必要なものがすべて揃っています。 他のライブラリを使用してアプリケーションのCLIエクスペリエンスを改善することもできます。Node.jsは十分に堅牢なので、手間をかけずに目的に合った機能を提供します。