Node.jsを使用してコマンドラインアプリケーションを構築する方法
開発者として、あなたはほとんどの時間をターミナルで過ごし、いくつかのタスクを回避するのに役立つコマンドを入力する可能性があります。
これらのコマンドの一部はオペレーティングシステムに組み込まれていますが、npmやbrewなどのサードパーティのヘルパーを介してインストールしたり、バイナリをダウンロードして追加したりすることもできます。 $PATH
.
一般的に使用されるアプリケーションの良い例には、npm、eslint、typescript、および Angle CLI 、 Vue CLI 、 Create ReactAppなどのプロジェクトジェネレーターが含まれます。
このチュートリアルでは、Node.jsで2つの小さなCLIアプリケーションを構築します。
- https://quotes.rest/qodからその日の見積もりを取得するQuoteOfTheDayツール。
- JSONを使用してデータを保存するTo-Doリストアプリ。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsのローカル開発環境。 Node.jsをインストールしてローカル開発環境を作成する方法に従ってください
ステップ1-シェバンを理解する
スクリプトファイルを見ると、ファイルの先頭に次のような文字が表示されます。
file.sh#!/usr/bin/env sh
またはこれ:
file.py#!/usr/bin/env python -c
これらは、オペレーティングシステムのプログラムローダーが実行可能ファイルの正しいインタープリターを見つけて使用するための方法として機能します。 ただし、これはUnixシステムでのみ機能します。
ウィキペディアから:
コンピューティングでは、シバンは、スクリプトの先頭にある文字の番号記号と感嘆符(#!)で構成される文字シーケンスです。
NodeJSには、サポートされている独自のシバン文字があります。
エディターでという新しいファイルを作成します logger.js
:
- nano logger.js
次のコードを追加します。
#!/usr/bin/env node
console.log("I am a logger")
最初の行は、NodeJSでこのファイルを解析するようにプログラムローダーに指示しています。 2行目は、画面にテキストを印刷します。
ターミナルにこれを入力すると、ファイルを実行してみることができます。 実行が拒否された権限を取得します。
- ./logger
Outputzsh: permission denied: ./logger
ファイルの実行権限を付与する必要があります。 あなたはそれをすることができます。
- chmod +x logger
- ./logger
今回は出力が表示されます。
OutputI am a logger
あなたはこのプログラムをで実行することができたでしょう node logger
、ただし、シバンを追加してプログラムを実行可能にする独自のコマンドを使用すると、入力を回避できます node
それを実行します。
今日の見積もりアプリを作成する
ディレクトリを作成して呼び出しましょう qod
. そして内部で、NodeJsアプリをインスタンス化します。
- mkdir qod
- cd qod
- npm init -y
次に、quotesサーバーにリクエストを送信する必要があることがわかっているので、既存のライブラリを使用してこれを行うことができます。 axiosを使用します
npm install --save axios
また、ターミナルで色を印刷するのに役立つライブラリであるチョークを追加します。
npm install --save chalk
次に、これらの引用符を取得するために必要なロジックを記述します。
と呼ばれる新しいファイルを作成します qod
:
- nano qod
次のコードをに追加します qod
シバンを指定し、ライブラリをロードし、APIURLを保存するファイル:
#!/usr/bin/env node
const axios = require('axios');
const chalk = require('chalk');
const url = "https://quotes.rest/qod";
次に、このコードを追加して、 GET
APIへのリクエスト:
[label qod]// make a get request to the url
axios({
method: 'get',
url: url,
headers: { 'Accept': 'application/json' }, // this api needs this header set for the request
}).then(res => {
const quote = res.data.contents.quotes[0].quote
const author = res.data.contents.quotes[0].author
const log = chalk.green(`${quote} - ${author}`) // we use chalk to set the color green on successful response
console.log(log)
}).catch(err => {
const log = chalk.red(err) // we set the color red here for errors.
console.log(log)
})
ファイルを保存します。
ファイルが実行可能になるようにファイルのアクセス許可を変更します。
- chmod +x qod
次に、アプリケーションを実行します。
./qod
見積もりが表示されます:
OutputThe best way to not feel hopeless is to get up and do something. Don’t wait for good things to happen to you. If you go out and make some good things happen, you will fill the world with hope, you will fill yourself with hope. - Barack Obama
この例は、CLIアプリケーションで外部ライブラリを使用できることを示しています。
次に、データを保存するCLIプログラムを作成しましょう。
ToDoリストの作成
これは、データの保存と取得を伴うため、もう少し複雑になります。 これが私たちが達成しようとしていることです。
- 次のコマンドが必要です
todo
- コマンドは4つの引数を取ります。
new
,get
,complete
、 とhelp
.
したがって、使用可能なコマンドは次のようになります
./todo new // create a new todo
./todo get // get a list of all your todos
./todo complete // complete a todo item.
./todo help // print the help text
と呼ばれるディレクトリを作成します todo
、Node.jsアプリをインスタンス化します。
- mkdir todo
- cd todo
- npm install -y
次に、 chalk を再度インストールして、色でログに記録できるようにします。
npm install --save chalk
最初に行うことは、これらのコマンドが使用可能であることを確認することです。 コマンドを機能させるために、NodeJの process / argv を使用します。これは、コマンドライン引数の文字列配列を返します。 process.argv
プロパティは、Node.jsプロセスの起動時に渡されたコマンドライン引数を含む配列を返します。
ファイルを作成する todo
:
- nano todo
これをtodoファイルに追加します。
#!/usr/bin/env node
console.log(process.argv)
ファイルに実行可能ファイルのアクセス許可を与えてから、新しいコマンドで実行します。
- chmod +x ./todo
- ./todo new
次の出力が得られます。
Output[ '/Users/sammy/.nvm/versions/node/v8.11.2/bin/node',
'/Users/sammy/Dev/scotch/todo/todo',
'new' ]
配列の最初の2つの文字列は、プログラムへのインタープリターとファイルのフルパスであることに注意してください。 配列の残りの部分には、渡された引数が含まれています。 この場合は new
.
安全のために、これらを制限して、正しい数の引数(1つ)のみを受け入れることができるようにします。 new
, get
と complete
.
を変更します todo
ファイルなので、次のようになります。
#!/usr/bin/env node
const chalk = require('chalk')
const args = process.argv
// usage represents the help guide
const usage = function() {
const usageText = `
todo helps you manage you todo tasks.
usage:
todo <command>
commands can be:
new: used to create a new todo
get: used to retrieve your todos
complete: used to mark a todo as complete
help: used to print the usage guide
`
console.log(usageText)
}
// used to log errors to the console in red color
function errorLog(error) {
const eLog = chalk.red(error)
console.log(eLog)
}
// we make sure the length of the arguments is exactly three
if (args.length > 3) {
errorLog(`only one argument can be accepted`)
usage()
}
最初にコマンドライン引数を変数に割り当ててから、下部で長さが3以下であることを確認します。
また、 usage
文字列。コマンドラインアプリが期待するものを出力します。 以下のような間違ったパラメータでアプリを実行します。
- ./todo new app
Outputonly one argument can be accepted
todo helps you manage you todo tasks.
usage:
todo <command>
commands can be:
new: used to create a new todo
get: used to retrieve your todos
complete: used to mark a todo as complete
help: used to print the usage guide
1つのパラメーターを指定して実行すると、何も出力されません。つまり、コードはパスします。
次に、4つのコマンドのみが予期されていることを確認する必要があり、それ以外はすべて無効として出力されます。
ファイルの先頭にコマンドのリストを追加します。
const commands = ['new', 'get', 'complete', 'help']
そして、長さを確認した後、渡されたコマンドで確認します。
...
if (commands.indexOf(args[2]) == -1) {
errorLog('invalid command passed')
usage()
}
ここで、無効なコマンドを使用してアプリを実行すると、これが発生します。
- ./todo ne
Outputinvalid command passed
todo helps you manage you todo tasks.
usage:
todo <command>
commands can be:
new: used to create a new todo
get: used to retrieve your todos
complete: used to mark a todo as complete
help: used to print the usage guide
それでは、 help
を呼び出すことによるコマンド usage
関数。 これをtodoファイルに追加しましょう:
//...
switch(args[2]) {
case 'help':
usage()
break
case 'new':
break
case 'get':
break
case 'complete':
break
default:
errorLog('invalid command passed')
usage()
}
//...
私たちは switch
呼び出されたコマンドに基づいて関数を呼び出すステートメント。 よく見ると、 help
caseはusage関数を呼び出すだけです。
The new
コマンドは新しいtodoアイテムを作成し、それをjsonファイルに保存します。 使用するライブラリはlowdbです。 必要に応じて、jsonファイルの読み取りと書き込みを行う関数を簡単に作成できます。
lowdbをインストールします
- npm install --save lowdb
追加しましょう [readline](https://nodejs.org/api/readline.html)
と lowdb
依存関係、データの保存に役立ちます。 lowdbコードは、githubページの標準です。
//...
const rl = require('readline');
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync('db.json')
const db = low(adapter)
// Set some defaults (required if your JSON file is empty)
db.defaults({ todos: []}).write()
//...
次に、ユーザーにデータの入力を求める関数を追加します。
//...
function prompt(question) {
const r = rl.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
return new Promise((resolve, error) => {
r.question(question, answer => {
r.close()
resolve(answer)
});
})
}
//...
ここでは、readlineライブラリを使用して、ユーザーにプロンプトを表示して出力を読み取るのに役立つインターフェイスを作成しています。
次に、ユーザーが入力したときに呼び出される関数を追加する必要があります。 new
指図:
//...
function newTodo() {
const q = chalk.blue('Type in your todo\n')
prompt(q).then(todo => {
console.log(todo)
})
}
//...
プロンプトの青色を取得するためにチョークを使用しています。 そして、結果をログに記録します。
最後に、で関数を呼び出します new
場合。
// ...
switch(args[2]) {
//...
case 'new':
newTodo()
break
// ...
}
// ...
新しいコマンドを使用してアプリを実行すると、todoを追加するように求められます。 入力してEnterキーを押します。
- ./todo new
OutputType in your todo
This my todo aaaaaaw yeah
This my todo aaaaaaw yeah
これに似たものが表示されるはずです。
また、 db.json
ファイルはファイルシステムで作成されており、todosプロパティがあります。
次に、todoを追加するためのロジックを追加しましょう。 newTodo関数を変更します。
//...
function newTodo() {
const q = chalk.blue('Type in your todo\n')
prompt(q).then(todo => {
// add todo
db.get('todos')
.push({
title: todo,
complete: false
})
.write()
})
}
//...
コードを再度実行します。
- ./todo new
OutputType in your todo
Take a Scotch course
あなたがあなたを見れば db.json
、todoが追加されているのがわかります。 次のgetコマンドで取得できるように、さらに2つ追加します。 これが db.json
ファイルはより多くのレコードがあるように見えます:
{
"todos": [
{
"title": "Take a Scotch course",
"complete": false
},
{
"title": "Travel the world",
"complete": false
},
{
"title": "Rewatch Avengers",
"complete": false
}
]
}
作成後 new
コマンド、あなたはすでに実装する方法のアイデアを持っている必要があります get
指図。
ToDoを取得する関数を作成します。
//...
function getTodos() {
const todos = db.get('todos').value()
let index = 1;
todos.forEach(todo => {
const todoText = `${index++}. ${todo.title}`
console.log(todoText)
})
}
//...
// switch statements
switch(args[2]) {
//...
case 'get':
getTodos()
break
//...
}
//....
コマンドを再度実行します。
- ./todo get
今すぐアプリを実行すると、次の出力が得られます。
Output1. Take a Scotch course
2. Travel the world
3. Rewatch Avengers
を使用して緑色にすることができます chalk.green
.
次に、 complete
コマンド、これは少し複雑です。
あなたは2つの方法でそれを行うことができます。
- ユーザーが入力するときはいつでも
./todo complete
、すべてのToDoを一覧表示し、Todoが完了としてマークするための番号/キーを入力するように依頼することができます。 - ユーザーが入力できるように、別のパラメーターを追加できます
./todo get
、次に、次のようなパラメータで完了としてマークするタスクを選択します。./todo complete 1
.
あなたが実装したときに最初の方法を行う方法を学んだので new
コマンド、オプション2を見ていきます。
このオプションを使用すると、コマンド ./todo complete 1
、指定されたコマンド数の有効性チェックに失敗します。 したがって、最初にこれを処理する必要があります。 引数の長さをチェックする関数を次のように変更します。
//...
// we make sure the length of the arguments is exactly three
if (args.length > 3 && args[2] != 'complete') {
errorLog('only one argument can be accepted')
usage()
return
}
///...
このアプローチでは、真理値表を使用します。 TRUE && FALSE
等しくなります FALSE
、およびコードは次の場合にスキップされます complete
合格。
次に、新しい引数の値を取得し、todoの値を完了したものにします。
//...
function completeTodo() {
// check that length
if (args.length != 4) {
errorLog("invalid number of arguments passed for complete command")
return
}
let n = Number(args[3])
// check if the value is a number
if (isNaN(n)) {
errorLog("please provide a valid number for complete command")
return
}
// check if correct length of values has been passed
let todosLength = db.get('todos').value().length
if (n > todosLength) {
errorLog("invalid number passed for complete command.")
return
}
// update the todo item marked as complete
db.set(`todos[${n-1}].complete`, true).write()
}
//...
また、更新します switch
含めるステートメント complete
指図:
//...
case 'complete':
completeTodo()
break
//...
これを実行すると ./todo complete 2
、あなたはあなたに気付くでしょう db.json
これに変更され、2番目のタスクが完了としてマークされます。
{
"todos": [
{
"title": "Take a Scotch course",
"complete": false
},
{
"title": "Travel the world",
"complete": true
},
{
"title": "Rewatch Avengers",
"complete": false
}
]
}
私たちがする必要がある最後のことは変化です ./todo get
実行されたタスクのみを表示します。 これには絵文字を使用します。 変更 getTodos
このコードで:
//...
function getTodos() {
const todos = db.get('todos').value()
let index = 1;
todos.forEach(todo => {
let todoText = `${index++}. ${todo.title}`
if (todo.complete) {
todoText += ' ✔ ️' // add a check mark
}
console.log(chalk.strikethrough(todoText))
})
return
}
//...
ここで入力すると ./todo get
あなたはこれを見るでしょう。
Output1. Take a Scotch course
2. Travel the world ✔ ️
3. Rewatch Avengers
結論
Node.jsで2つのCLIアプリケーションを作成しました。
アプリが機能したら、ファイルを bin
フォルダ。 このように、npmは、実行可能ファイルを配布するときに実行可能ファイルを操作する方法を知っています。 また、実行可能ファイルを配置する場所に関係なく、更新する必要があります package.json
binプロパティ。
この記事の焦点は、CLIアプリケーションがvanilla nodejsを使用してどのように構築されるかを調べることでしたが、現実の世界で作業する場合は、ライブラリを使用する方が生産的です。
npmに公開できる素晴らしいCLIアプリケーションを作成するのに役立つライブラリのリストを次に示します。
- vopral-フル機能のインタラクティブCLIフレームワーク
- meow-CLIヘルパーライブラリ
- commanderjs-CLIライブラリ
- minimist-引数の解析用
- yargs-引数の解析
そして、色を手伝ってくれたチョークのようなライブラリは言うまでもありません。
追加の演習として、 Delete
CLIへのコマンド。