commanderJs編寫命令行工具(cli)

前言:

  最近須要作一個內部的node cli來獨立構建流程,對整個命令行工具實現流程有了大體瞭解,下面來解釋一下如何實現一個cli,和如何使用  commander 庫。
 

新手誤區:

  在開始實現以前,我知道有  commander 這個node庫,有不少cli使用了它,對它的大體瞭解就是它能夠幫助開發者簡化實現命令流程。  因而最初覺得不利用庫要去實現命令行會很麻煩, commander 幫咱們解決了各類兼容問題等等。  後來發現並非的,沒有 commander 咱們也能夠不用化多大力氣實現命令行, commander 僅僅是一個自己也不太複雜的封裝(源碼也只有1200行)。  咱們的第一步仍是應該先搞清楚,經過 npm如何實現命令行。
 

一個簡單的cli:

bin:

  package.json 中有一個 bin 字段,指定各個內部命令對應的可執行文件的位置。   在包安裝時,若是是全局安裝,npm 將會把 package.json 裏定義的 bin 文件軟鏈接到全局 node_modules/bin,若是是非全局安裝,會軟連接到項目文件夾./node_modules/.bin/。  根據下面代碼的配置,當咱們全局安裝此包後,在任意位置運行 cli-test,都會執行全局 node_modules 中的 cli-test 文件。node

/*cli-test 的 package.json*/
"bin": {
    "cli-test": "./bin/cli-test"
}

 

若是咱們把cli安裝在項目A node_modules中,經過設置項目中 package.json scripts,運行 npm run clinpm 就會在項目的 node_modules/.bin 尋找並運行 cli-test 文件。 npm

/*項目A package.json*/
"scripts": {
    "cli": "cli-test"
}

 

cli文件:

  下面是 cli-test 文件,第一行必寫,是告訴Unix和Linux系統這個文件中的代碼用node可執行程序去運行它。  後面就作咱們要作的事情就好了 。json

#!/usr/bin/env node

//do something

 

好了,到這裏咱們的cli就完成了。  其實有不少三方cli也並無用相似 commandernode 庫,若是咱們的 cli 足夠簡單,以上這樣就能夠了。  下面接着講 commander數組

 

commander:

如今咱們先寫一個簡單的文件來理解(也推薦先自行預覽一下 commander 官方文檔),下面是 bin 文件夾的 cli-test,代碼以下:工具

 

#!/usr/bin/env node

const program =require('commander');
program
.usage('[option]', '--type required')
.option('--type [typeName]', 'type: dev && build')
.parse(process.argv);

const {type} = program;
if(type == 'dev'){
    console.log('do something', type)
}else if(type == 'build'){
    console.log('do something', type)
}else{
    console.log('params error');
    program.help();
}

 

解釋一下上面的代碼,從查看源碼裏發現 require('commander')  會 new一個commander 內部的單例對象並返回,program 已是一個實例,。  .usage  僅僅描述了參數規則,會在 --help 中打印出來。.option 定義了一個參數名和描述,  parse 會解析命令之中的參數,根據上面定義好的規則執行相關命令。  好比上面的代碼定義了 option 類型的參數 --type,執行 .parse 的時候,parse 根據 process.argv 之中的參數,獲取到 --type,並把參數命和參數值存儲在內部 commander 實例的屬性之中,所以後面的代碼就能從 program 之中取到 type,若是 type 不存在或者不是咱們約定的值,最後咱們打印參數錯誤,並執行help方法打印了 --help。  以下截圖,咱們 node 執行 cli-test,由於沒有約定參數,因此執行了 else 的程序。(由於這裏是本地的demo程序,因此直接使用node命令)學習

 

接着,咱們執行正確的命令參數,以下ui

 

這樣一個簡單的demo就實現了,看起來也挺簡單的,commander 封裝了一些也不算很複雜的功能。 spa

 

再來一個例子:

新建了兩個文件,要以 bin 命令的執行文件命後面加上 -name,做爲子命令文件命令行

 

 

cli-test:code

#!/usr/bin/env node

const program =require('commander');

program
.usage('<command> [option]', 'option --type required')
.command('h5', 'to h5')
.command('rn', 'to rn')
.parse(process.argv);

 

cli-test-h5:

#!/usr/bin/env node

const program =require('commander');
program
.option('--type [typeName]', 'type: dev && build')
.parse(process.argv);

const {type} = program;
if(type == 'dev'){
    console.log('do something h5', type)
}else if(type == 'build'){
    console.log('do something h5', type)
}else{
    console.log('params error');
    program.help();
}

 

cli-test-rn:

#!/usr/bin/env node

const program =require('commander');
program
.option('--type [typeName]', 'type: dev && build')
.parse(process.argv);

const {type} = program;
if(type == 'dev'){
    console.log('do something rn', type)
}else if(type == 'build'){
    console.log('do something rn', type)
}else{
    console.log('params error');
    program.help();
}

 

先直接運行3個命令運行程序,看下結果,然後分別解釋一下:

 

node ./bin/cli-test:

定義了.command子命令卻沒有相應執行參數,commander對象會直接打印-help,process.exit退出進程。  

 

node ./bin/cli-test h5 --type dev:

cli-test 經過 command 方法約定子命令名稱和描述,如 h5,當執行 node cli-test h5 --type dev的時候,cli-test 執行到 .command('h5', 'to h5')  ,會在當前 commander 實例內部,new 一個 name h5 的子 commander,存儲在當前父實例的 commands 數組中,當 .parse(process.argv) 執行,獲取到參數中 h5 後,在 commands 裏查找是否有 nameh5commander 子實例,若是查找到,啓動一個子進程按照命名規則執行 cli-test-h5 文件並帶入後面的 option 參數這樣 commander 就幫助咱們實現了多文件命令劃分,咱們能夠把不一樣類型的執行代碼放在不一樣的文件中

 

node ./bin/cli-test rn --type build:

同上

 

小結

bin 文件夾下的這3個 node 文件他們都是 commander 實例,commander 庫只是一個簡單的封裝,幫助定義 多文件命令、執行參數 、簡易文檔,參數驗證等。  以上就是 commander 的大體使用和我對其的理解。   源碼很少,建議能夠深刻學習一下。

 

最後

  到最後你們結合實現以上所說的 cli commander,一個 commander 實現的命令行工具就能完成了,是否是很簡單!?  

 

注意

  若是執行命令發現報錯爲 error: xx(1) not executable. try chmod or run with root,要注意下建立的文件類型。

相關文章
相關標籤/搜索