用一次就會愛上的cli工具開發

dongfangyiyu發表於2019-04-28

寫在前面

最近接手任務——使用nodejs開一個發公司內部使用的cli工具,簡而言之就是輸入一行命令快速搭建好專案結構,也可以通過不同的命令引入不同的檔案。

瞭解

首先要基於node環境,然後我們需要知道cli是什麼?cli是command-line interface的縮寫,即命令列工具,常用的vue-clicreate-react-appexpress-generator 等都是cli工具。

回顧

建立一個exercise-cli目錄,並使用cmd進入該目錄:

mkdir exercise-cli && cd exercise-cli
複製程式碼

在該目錄下新建index.js:

//index.js
console.log('謝邀,人在美國,剛下飛機。');
複製程式碼

使用node執行index.js:

用一次就會愛上的cli工具開發
這是node的基本用法,那麼如何使用自定義命令列輸出這句話呢?

點火

使用npm init建立package.json,一路回車,當然你也可以配置相關資訊,有興趣可自己選擇:

用一次就會愛上的cli工具開發
現在目錄中自動生成一個package.json檔案:

{
  "name": "exercise-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
複製程式碼

現在在package.json中新增欄位bin,用來存放一個可執行的檔案,我們此處的可執行檔案就是index.js,因此配置如下:

"bin":{
    "exercise-cli":"./index.js"
},
複製程式碼

此時我們配置exercise-cli命令來執行index.js檔案,需要在index.js檔案頭部新增#!/usr/bin/env node, 讓系統自己去找node的執行程式。至於這玩意具體什麼,百度出這麼個東西,可自行參考。

//index.js
#!/usr/bin/env node
console.log('謝邀,人在美國,剛下飛機。');
複製程式碼

然後在cmd輸入npn linknpm install -g將當前專案安裝到全域性環境,這樣就可以直接使用exercise-cli來執行檔案了:

用一次就會愛上的cli工具開發
再學一點,在package.json的scripts欄位裡新增指令碼名:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "exercise":"exercise-cli"
 }
複製程式碼

命令列輸入npm run exercise,同樣輸出了index.js裡的內容,聯想去vue-clinpm run devnpm run build等會不會若有所思呢?

起飛

有點樣子了,接下來讓我們看看它是如何生成專案模板的,一個思路是用一個templates資料夾儲存專案模板,然後通過fs.mkdir()來建立專案目錄,最後把檔案從templates資料夾拷貝到專案中去。本地templates目錄如下圖所示:

用一次就會愛上的cli工具開發

1.拷貝檔案

模擬場景:將本地templates中的vue.min.js拷貝到新生成的專案模板中。在新生成的專案模板中新建public目錄,該目錄下新建js目錄,將vue.min.js通過copyTemplate()方法從templates裡拷貝到新建的js目錄下面:

//index.js
#!/usr/bin/env node

var fs = require('fs');
var path = require('path');

// 複製檔案
function copyTemplate (from, to) {
  from = path.join(__dirname, 'templates', from);
  console.log(from);
  write(to, fs.readFileSync(from, 'utf-8'))
}
function write (path, str, mode) {
  fs.writeFileSync(path, str)
}
// 新建目錄
function mkdir (path, fn) {
  fs.mkdir(path, function (err) {
    fn && fn()
  })
}

var PATH = ".";
mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js');
	})
})

複製程式碼

用cmd開啟任意資料夾輸入exercise-cli,該資料夾下會public\js\vue.min.js:

用一次就會愛上的cli工具開發

2.拷貝資料夾

我們學會了拷貝檔案,那麼如何拷貝整個資料夾呢,例如我想將templates下的整個js目錄全部拷貝到新生成的專案模板中,又該如何?有需求就有方案,我們可以遍歷整個資料夾,對遍歷到的path進行判斷,如果是檔案則直接拷貝,如果是資料夾則遞迴:

//index.js
// 複製目錄
var copy=function(src,dst){
    let paths = fs.readdirSync(src); //同步讀取當前目錄(只能讀取絕對路徑,相對路徑無法獲取)
    paths.forEach(function(path){
        var _src=src+'/'+path;
        var _dst=dst+'/'+path;
        fs.stat(_src,function(err,stats){  //stats  該物件 包含檔案屬性
            if(err)throw err;
            if(stats.isFile()){ //如果是個檔案則拷貝 
                let  readable=fs.createReadStream(_src);//建立讀取流
                let  writable=fs.createWriteStream(_dst);//建立寫入流
                readable.pipe(writable);
            }else if(stats.isDirectory()){ //是目錄則 遞迴 
                checkDirectory(_src,_dst,copy);
            }
        });
    });
}
var checkDirectory=function(src,dst,callback){
    fs.access(dst, fs.constants.F_OK, (err) => {
        if(err){
            fs.mkdirSync(dst);
            callback(src,dst);
        }else{
            callback(src,dst);
        }
      });
};

mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		checkDirectory('C:/Users/Administrator/Desktop/vue-3.0/nodeTest/exercise/templates/js',PATH+'/public/js',copy);
	})
})
複製程式碼

依然在找一個資料夾開啟cmd輸入exercise-cli,該資料夾下會生成public目錄,該目錄下面會生成templates下的整個js檔案:

用一次就會愛上的cli工具開發

3.接收命令列引數

平常我們使用命令列工具時都會用到引數,如webpack -p, express -e 等,在此我們為exercise-cli配置-l,當使用exercise-cli -l時,新增layerJS。

我們可以使用process.argv來獲取命令列引數,process.argv是一個引數陣列,第一項為node.exe的絕對路徑,第二項為執行該js的絕對路徑,使用process.argv.slice(2)即可獲取輸入的引數陣列。

//index.js
console.log(process.argv);
複製程式碼

用一次就會愛上的cli工具開發
通過遍歷引數陣列來檢查命令中輸入了哪些引數。如果輸入了預設的引數,就為config物件新增對應的屬性,在生成檔案時根據config判斷是否將模板檔案拷貝到專案中。

var config = {};
process.argv.slice(2).forEach(item=>{
	if(item=="-l"){
		config.layer = true;
	}
})
var PATH = ".";
mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		// copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js');
		checkDirectory('C:/Users/Administrator/Desktop/vue-3.0/nodeTest/exercise/templates/js',PATH+'/public/js',copy);
		if(config.layer){
			checkDirectory('C:/Users/Administrator/Desktop/exercise-cli/templates/layer',PATH+'/public/js',copy);
			//此處注意layerJS存放在templates中的路徑。
		}
	})
})
console.log('拷貝成功');
複製程式碼

在任意資料夾開啟cmd輸入exercise-cli -l,執行成功,js目錄中多出了layerJS目錄:

用一次就會愛上的cli工具開發

加速

初始commander.js

其實node中有一款工具包可以快速開發命令列工具,它就是commander.js

首先全域性安裝一下:

npm install commander -g
複製程式碼

看個例子:

var program = require('commander');
program
    .version('1.0.0','-v, --version')
    .command('check [checkname]')
    .alias('c')
    .description('yo yo check now')
    .option('-a, --name [moduleName]', '模組名稱')
    .action((checkname,option) => {
        console.log('指令 install 後面跟的引數值 checkname: ' + checkname);
        console.log(option);
        // 獲得了引數,可以在這裡做響應的業務處理
    })
    	//自定義幫助資訊
    .on('--help', function() {
        console.log('  下面我隨便說兩句:')
        console.log('')
        console.log('$ 人有多大膽,母豬多大產,i love xx')
        console.log('$ 廣闊天地,大有所為,呱~')
    })
program.parse(process.argv)
複製程式碼

命令列執行:

用一次就會愛上的cli工具開發

用一次就會愛上的cli工具開發
看完輸出一臉懵逼,別急,這就帶您瞧瞧這都是些什麼東西:

  • version - 定義命令程式的版本號,.version('0.0.1', '-v, --version'),第一個引數版本號必須,第二個引數可省略,預設為 -V 和 --version
  • command – 定義命令列指令,後面可跟上一個name,用空格隔開,如 .command('app [name]')
  • alias – 定義一個更短的命令列指令 ,如執行命令$ app m 與之是等價的
  • description – 描述,它會在help裡面展示
  • option – 定義引數。它接受四個引數,在第一個引數中,它可輸入短名字 -a和長名字–app ,使用 | 或者,分隔,在命令列裡使用時,這兩個是等價的,區別是後者可以在程式裡通過回撥獲取到;第二個為描述, 會在 help 資訊裡展示出來;第三個引數為回撥函式,他接收的引數為一個string,有時候我們需要一個命令列建立多個模組,就需要一個回撥來處理;第四個引數為預設值
  • action – 註冊一個callback函式,這裡需注意目前回撥不支援let宣告變數
  • parse – 用於解析process.argv,設定options以及觸發commands,用法示例:.parse(process.argv)

看到這,多多少少對如何編寫命令列工具有個大體的認知了,光說不練嘴把式,自我實踐:用commander.js完成上個段落3.接收命令列引數中的例子。

著陸

想讓別人來安裝你的cli工具,你需要把它釋出到npm上,先在npm官網創個賬號(注意需要郵件驗證),在命令列輸入npm adduser,依次填上你註冊的username、password、email。接著輸入npm publish即可:

用一次就會愛上的cli工具開發
輸入npm install -g exercise-clinpm install exercise-cli安裝一下你的cli感受它的魅力吧。

程式碼已上傳至我的GitHub,歡迎Fork。

感謝

相關文章