開発者ドキュメント

Node.jsを使用してコマンドラインアプリケーションを構築する方法

開発者として、あなたはほとんどの時間をターミナルで過ごし、いくつかのタスクを回避するのに役立つコマンドを入力する可能性があります。

これらのコマンドの一部はオペレーティングシステムに組み込まれていますが、npmやbrewなどのサードパーティのヘルパーを介してインストールしたり、バイナリをダウンロードして追加したりすることもできます。 $PATH.

一般的に使用されるアプリケーションの良い例には、npm、eslint、typescript、および Angle CLI Vue CLI Create ReactAppなどのプロジェクトジェネレーターが含まれます。

このチュートリアルでは、Node.jsで2つの小さなCLIアプリケーションを構築します。

  1. https://quotes.rest/qodからその日の見積もりを取得するQuoteOfTheDayツール。
  2. JSONを使用してデータを保存するTo-Doリストアプリ。

前提条件

このチュートリアルを完了するには、次のものが必要です。

ステップ1-シェバンを理解する

スクリプトファイルを見ると、ファイルの先頭に次のような文字が表示されます。

file.sh
#!/usr/bin/env sh

またはこれ:

file.py
#!/usr/bin/env python -c

これらは、オペレーティングシステムのプログラムローダーが実行可能ファイルの正しいインタープリターを見つけて使用するための方法として機能します。 ただし、これはUnixシステムでのみ機能します。

ウィキペディアから:

コンピューティングでは、シバンは、スクリプトの先頭にある文字の番号記号と感嘆符(#!)で構成される文字シーケンスです。

NodeJSには、サポートされている独自のシバン文字があります。

エディターでという新しいファイルを作成します logger.js:

  1. nano logger.js

次のコードを追加します。

#!/usr/bin/env node

console.log("I am a logger")

最初の行は、NodeJSでこのファイルを解析するようにプログラムローダーに指示しています。 2行目は、画面にテキストを印刷します。

ターミナルにこれを入力すると、ファイルを実行してみることができます。 実行が拒否された権限を取得します。

  1. ./logger
Output
zsh: permission denied: ./logger

ファイルの実行権限を付与する必要があります。 あなたはそれをすることができます。

  1. chmod +x logger
  2. ./logger

今回は出力が表示されます。

Output
I am a logger

あなたはこのプログラムをで実行することができたでしょう node logger、ただし、シバンを追加してプログラムを実行可能にする独自のコマンドを使用すると、入力を回避できます node それを実行します。

今日の見積もりアプリを作成する

ディレクトリを作成して呼び出しましょう qod. そして内部で、NodeJsアプリをインスタンス化します。

  1. mkdir qod
  2. cd qod
  3. npm init -y

次に、quotesサーバーにリクエストを送信する必要があることがわかっているので、既存のライブラリを使用してこれを行うことができます。 axiosを使用します

npm install --save axios

また、ターミナルで色を印刷するのに役立つライブラリであるチョークを追加します。

npm install --save chalk

次に、これらの引用符を取得するために必要なロジックを記述します。

と呼ばれる新しいファイルを作成します qod:

  1. nano qod

次のコードをに追加します qod シバンを指定し、ライブラリをロードし、APIURLを保存するファイル:

qod
#!/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)
})

ファイルを保存します。

ファイルが実行可能になるようにファイルのアクセス許可を変更します。

  1. chmod +x qod

次に、アプリケーションを実行します。

./qod

見積もりが表示されます:

Output
The 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リストの作成

これは、データの保存と取得を伴うため、もう少し複雑になります。 これが私たちが達成しようとしていることです。

  1. 次のコマンドが必要です todo
  2. コマンドは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アプリをインスタンス化します。

  1. mkdir todo
  2. cd todo
  3. npm install -y

次に、 chalk を再度インストールして、色でログに記録できるようにします。

npm install --save chalk

最初に行うことは、これらのコマンドが使用可能であることを確認することです。 コマンドを機能させるために、NodeJの process / argv を使用します。これは、コマンドライン引数の文字列配列を返します。 process.argv プロパティは、Node.jsプロセスの起動時に渡されたコマンドライン引数を含む配列を返します。

ファイルを作成する todo:

  1. nano todo

これをtodoファイルに追加します。

やること
#!/usr/bin/env node

console.log(process.argv)

ファイルに実行可能ファイルのアクセス許可を与えてから、新しいコマンドで実行します。

  1. chmod +x ./todo
  2. ./todo new

次の出力が得られます。

Output
[ '/Users/sammy/.nvm/versions/node/v8.11.2/bin/node', '/Users/sammy/Dev/scotch/todo/todo', 'new' ]

配列の最初の2つの文字列は、プログラムへのインタープリターとファイルのフルパスであることに注意してください。 配列の残りの部分には、渡された引数が含まれています。 この場合は new.

安全のために、これらを制限して、正しい数の引数(1つ)のみを受け入れることができるようにします。 new, getcomplete.

を変更します 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 文字列。コマンドラインアプリが期待するものを出力します。 以下のような間違ったパラメータでアプリを実行します。

  1. ./todo new app
Output
only 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()
}

ここで、無効なコマンドを使用してアプリを実行すると、これが発生します。

  1. ./todo ne
Output
invalid 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をインストールします

  1. 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キーを押します。

  1. ./todo new
Output
Type 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()
  })
}
//...

コードを再度実行します。

  1. ./todo new
Output
Type in your todo Take a Scotch course

あなたがあなたを見れば db.json、todoが追加されているのがわかります。 次のgetコマンドで取得できるように、さらに2つ追加します。 これが db.json ファイルはより多くのレコードがあるように見えます:

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
	//...
}
//....

コマンドを再度実行します。

  1. ./todo get

今すぐアプリを実行すると、次の出力が得られます。

Output
1. Take a Scotch course 2. Travel the world 3. Rewatch Avengers

を使用して緑色にすることができます chalk.green.

次に、 complete コマンド、これは少し複雑です。

あなたは2つの方法でそれを行うことができます。

  1. ユーザーが入力するときはいつでも ./todo complete、すべてのToDoを一覧表示し、Todoが完了としてマークするための番号/キーを入力するように依頼することができます。
  2. ユーザーが入力できるように、別のパラメーターを追加できます ./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番目のタスクが完了としてマークされます。

db.json

{
  "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 あなたはこれを見るでしょう。

Output
1. 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アプリケーションを作成するのに役立つライブラリのリストを次に示します。

  1. vopral-フル機能のインタラクティブCLIフレームワーク
  2. meow-CLIヘルパーライブラリ
  3. commanderjs-CLIライブラリ
  4. minimist-引数の解析用
  5. yargs-引数の解析

そして、色を手伝ってくれたチョークのようなライブラリは言うまでもありません。

追加の演習として、 Delete CLIへのコマンド。

モバイルバージョンを終了