使用 Node.js 構建互動式命令列工具

2019-01-02 23:25:00

使用 Node.js 構建一個根據詢問建立檔案的命令列工具。

當用於構建命令列介面(CLI)時,Node.js 十分有用。在這篇文章中,我將會教你如何使用 Node.js 來構建一個問一些問題並基於回答建立一個檔案的命令列工具。

開始

首先,建立一個新的 npm 包(NPM 是 JavaScript 包管理器)。

mkdir my-scriptcd my-scriptnpm init

NPM 將會問一些問題。隨後,我們需要安裝一些包。

npm install --save chalk figlet inquirer shelljs

這是我們需要的包:

  • Chalk:正確設定終端的字元樣式
  • Figlet:使用普通字元製作大字母的程式(LCTT 譯註:使用標準字元,拼湊出圖片)
  • Inquirer:通用互動式命令列使用者介面的集合
  • ShellJS:Node.js 版本的可移植 Unix Shell 命令列工具

建立一個 index.js 檔案

現在我們要使用下述內容建立一個 index.js 檔案。

#!/usr/bin/env nodeconst inquirer = require("inquirer");const chalk = require("chalk");const figlet = require("figlet");const shell = require("shelljs");

規劃命令列工具

在我們寫命令列工具所需的任何程式碼之前,做計劃總是很棒的。這個命令列工具只做一件事:建立一個檔案

它將會問兩個問題:檔名是什麼以及檔案字尾名是什麼?然後建立檔案,並展示一個包含了所建立檔案路徑的成功資訊。

// index.jsconst run = async () => {  // show script introduction  // ask questions  // create the file  // show success message};run();

第一個函數只是該指令碼的介紹。讓我們使用 chalkfiglet 來把它完成。

const init = () => {  console.log(    chalk.green(      figlet.textSync("Node JS CLI", {        font: "Ghost",        horizontalLayout: "default",        verticalLayout: "default"      })    )  );}const run = async () => {  // show script introduction  init();  // ask questions  // create the file  // show success message};run();

然後,我們來寫一個函數來問問題。

const askQuestions = () => {  const questions = [    {      name: "FILENAME",      type: "input",      message: "What is the name of the file without extension?"    },    {      type: "list",      name: "EXTENSION",      message: "What is the file extension?",      choices: [".rb", ".js", ".php", ".css"],      filter: function(val) {        return val.split(".")[1];      }    }  ];  return inquirer.prompt(questions);};// ...const run = async () => {  // show script introduction  init();  // ask questions  const answers = await askQuestions();  const { FILENAME, EXTENSION } = answers;  // create the file  // show success message};

注意,常數 FILENAMEEXTENSIONS 來自 inquirer 包。

下一步將會建立檔案。

const createFile = (filename, extension) => {  const filePath = `${process.cwd()}/${filename}.${extension}`  shell.touch(filePath);  return filePath;};// ...const run = async () => {  // show script introduction  init();  // ask questions  const answers = await askQuestions();  const { FILENAME, EXTENSION } = answers;  // create the file  const filePath = createFile(FILENAME, EXTENSION);  // show success message};

最後,重要的是,我們將展示成功資訊以及檔案路徑。

const success = (filepath) => {  console.log(    chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)  );};// ...const run = async () => {  // show script introduction  init();  // ask questions  const answers = await askQuestions();  const { FILENAME, EXTENSION } = answers;  // create the file  const filePath = createFile(FILENAME, EXTENSION);  // show success message  success(filePath);};

來讓我們通過執行 node index.js 來測試這個指令碼,這是我們得到的:

完整程式碼

下述程式碼為完整程式碼:

#!/usr/bin/env nodeconst inquirer = require("inquirer");const chalk = require("chalk");const figlet = require("figlet");const shell = require("shelljs");const init = () => {  console.log(    chalk.green(      figlet.textSync("Node JS CLI", {        font: "Ghost",        horizontalLayout: "default",        verticalLayout: "default"      })    )  );};const askQuestions = () => {  const questions = [    {      name: "FILENAME",      type: "input",      message: "What is the name of the file without extension?"    },    {      type: "list",      name: "EXTENSION",      message: "What is the file extension?",      choices: [".rb", ".js", ".php", ".css"],      filter: function(val) {        return val.split(".")[1];      }    }  ];  return inquirer.prompt(questions);};const createFile = (filename, extension) => {  const filePath = `${process.cwd()}/${filename}.${extension}`  shell.touch(filePath);  return filePath;};const success = filepath => {  console.log(    chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)  );};const run = async () => {  // show script introduction  init();  // ask questions  const answers = await askQuestions();  const { FILENAME, EXTENSION } = answers;  // create the file  const filePath = createFile(FILENAME, EXTENSION);  // show success message  success(filePath);};run();

使用這個指令碼

想要在其它地方執行這個指令碼,在你的 package.json 檔案中新增一個 bin 部分,並執行 npm link

{  "name": "creator",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "start": "node index.js"  },  "author": "",  "license": "ISC",  "dependencies": {    "chalk": "^2.4.1",    "figlet": "^1.2.0",    "inquirer": "^6.0.0",    "shelljs": "^0.8.2"  },  "bin": {    "creator": "./index.js"  }}

執行 npm link 使得這個指令碼可以在任何地方呼叫。

這就是是當你執行這個命令時的結果。

/usr/bin/creator -> /usr/lib/node_modules/creator/index.js/usr/lib/node_modules/creator -> /home/hugo/code/creator

這會連線 index.js 作為一個可執行檔案。這是完全可能的,因為這個 CLI 指令碼的第一行是 #!/usr/bin/env node

現在我們可以通過執行如下命令來呼叫。

$ creator

總結

正如你所看到的,Node.js 使得構建一個好的命令列工具變得非常簡單。如果你希望了解更多內容,檢視下列包。

  • meow:一個簡單的命令列助手工具
  • yargs:一個命令列引數解析工具
  • pkg:將你的 Node.js 程式包裝在一個可執行檔案中。

在評論中留下你關於構建命令列工具的經驗吧!