是時候擁有一個你自己的命令列工具了
本篇部落格主要介紹瞭如何使用commander, inquirer以及chalk從零開始,建立屬於自己的命令列工具。
0. 一分鐘體驗
首先我們先花一分鐘的時間,體驗一下建立自己的命令列cli工具是什麼感覺。
0.1. 新建專案目錄
假如我們的專案名稱叫hello-cli
,使用如下命令新建專案目錄。
mkdir hello-cli && cd hello-cli
0.2. 初始化專案
接下里使用npm-init命令來初始化一個簡單的package.json檔案。
npm init -y
-y
命令表示接受npm的一切預設引數設定。然後替換package.json為如下程式碼。
{ "name": "hello-cli", "version": "1.0.0", "description": "", "main": "index.js", "bin": { "hello": "hello" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "chalk": "^2.4.2", "commander": "^2.20.0", "inquirer": "^6.3.1", "shelljs": "^0.8.3" } }
然後使用npm install
安裝依賴。
0.3. 新建入口檔案
在專案根目錄下新建名為hello
的檔案,不需要任何字尾,值得注意的是此時的檔名就是你的cli工具第一個鍵入的命令,例如npm install
,那麼hello
就等價於npm
。並將程式碼替換如下。
#! /usr/bin/env node const program = require('commander'); const inquirer = require('inquirer'); const chalk = require('chalk'); program .command('init') .alias('i') .description('初始化專案') .action(option => { // 該物件用於儲存所有與使用者互動的資料 let config = { // 假設我們需要使用者自定義專案名稱 projectName: null }; // 使用chalk列印美化的版本資訊 console.log(chalk.default.bold('hello v1.0.0')); // 用於儲存所有的互動步驟,例如讓使用者輸入專案名稱就是其中一個步驟 let promps = []; if (config.projectName === null) { promps.push({ type: 'input', name: 'projectName', message: '請輸入專案名稱', validate: input => { if (!input) { return '專案名稱不能為空'; } // 更新物件中屬性的資料 config.projectName = input; return true; } }); } // 至此,與使用者的所有互動均已完成,answers是收集到的使用者所填的所有資料 // 同時,這也是你開始操作的地方,這個cli工具的核心程式碼應該從這個地方開始 inquirer.prompt(promps).then(async (answers) => { // do something here console.log(answers); }); }); program.parse(process.argv);
0.4. npm link
那麼問題來了,
在你的專案根目錄下使用npm link
,然後在你本地上就相當於安裝了名為hello-cli
這樣的一個全域性npm包了。其原理是將你本地的專案在全域性的node_modules中做了一個軟連結,拿此專案舉例,全域性的hello
命令已經指向了你的本地目錄。如果你想取消測試專案在全域性中的對映,同樣的進入項根目錄,輸入命令npm unlink
即可。
然後搭配以下命令食用你的第一個cli工具吧。如果報錯提示沒有許可權,在命令前加上sudo即可。
hello init
# 或者
# hello i
1. commander
commander是一個Node.js環境下的命令列介面解決方案。在上面的一分鐘體驗例子中,我們用到了command
alias
,description
,action
這四個API。
command
command
代表了這個cli工具向用戶暴露的命令列指令。我們還是拿npm install
來舉例子,command('init')
聲明瞭一個叫init的命令,在此處,init等價於installalias
alias
是對於當前命令列指令的更短的指令。例如大家都知道,npm install
可以簡寫為npm i
。i
就是定義的aliasdescription
description
是對當前命令列指令的描述,commander會自動的生成當前cli工具的幫助文件,而該描述就會在hello -h
中展示,如果你的一分鐘體驗專案還在的話,在命令列中輸入hello -h
就可以看到自動生成的幫助文件了action
action
是我們註冊我們自己回撥函式的地方parse
parse
命令則是解析命令列
下面是一分鐘體驗專案中沒有使用的命令,option。還是舉一個例子。如果有用過hexo的應該熟悉這個命令。
hexo new post $YOUR_POST_NAME
沒用過也沒關係,這個命令是用於建立一個可以自定義名字的Markdown的文件的。大家可能會發現,上面的命令包含了4個單詞,而我們的例子中只有兩個。那是因為一分鐘專案中沒有使用commander的option
API。
如果你想在hello專案中實現一樣的命令,那麼只需要在program中呼叫該API即可。.option('-p, --post', 'add post')
,然後就可以通過option
引數獲取到-p後面,使用者輸入的引數的值。
2. inquirer
大家也發現了,在命令列輸入init命令後,我們需要不停地與命令列進行互動拿到資料,但是在程式碼裡並沒有怎麼體現,這是因為我們用了inquirer來幫我們做這些事情。
通過inquirer,我們可以實現輸入框,獲取使用者的輸入資料,還可以實現選擇框。舉個例子,用過antd-design-pro應該熟悉建立專案的流程。在命令列中輸入命令yarn create umi
,在之後的流程中就會出現一個可選擇的list。只需要將步驟中的程式碼替換成如下即可。
promps.push({
type: 'list',
name: 'projectName',
message: '請輸入專案名稱',
choices: [
{
name: 'ant-design-pro',
value: 'ant-design-pro'
},
{
name: 'dva',
value: 'dva'
}
]
});
在專案中,還使用了validate
來對使用者的輸入資料進行驗證,如果不需要驗證的話,直接把validate整個程式碼刪除掉就好。
3. chalk
chalk沒有什麼好介紹的,官網上的文件已經寫的很詳細了。給大家列一下專案中使用的例子就好。
// 使用預設的字型顏色,加粗字型
console.log(chalk.default.bold('hello v1.0.0'));
// 列印藍色的提示資訊
console.log(chalk.blue('hello v1.0.0'));
// 字串模板用法,在同一行中列印不同樣式的資訊
console.log(chalk`{white.bold [1/3]}