摘要:拷貝成功在任意文件夾打開輸入執(zhí)行成功,目錄中多出了目錄加速初始其實中有一款工具包可以快速開發(fā)命令行工具,它就是。
寫在前面最近接手任務——使用nodejs開發(fā)一個公司內(nèi)部使用的cli工具,簡而言之就是輸入一行命令快速搭建好項目結構,也可以通過不同的命令引入不同的文件。
了解首先要基于node環(huán)境,然后我們需要知道cli是什么?cli是command-line interface的縮寫,即命令行工具,常用的vue-cli, create-react-app,express-generator 等都是cli工具。
回顧創(chuàng)建一個exercise-cli目錄,并使用cmd進入該目錄:
mkdir exercise-cli && cd exercise-cli
在該目錄下新建index.js:
//index.js
console.log("謝邀,人在美國,剛下飛機。");
使用node運行index.js:
這是node的基本用法,那么如何使用自定義命令行輸出這句話呢?
點火
使用npm init創(chuàng)建package.json,一路回車,當然你也可以配置相關信息,有興趣可自己選擇:
現(xiàn)在目錄中自動生成一個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"
}
現(xiàn)在在package.json中添加字段bin,用來存放一個可執(zhí)行的文件,我們此處的可執(zhí)行文件就是index.js,因此配置如下:
"bin":{
"exercise-cli":"./index.js"
},
此時我們配置exercise-cli命令來執(zhí)行index.js文件,需要在index.js文件頭部添加#!/usr/bin/env node, 讓系統(tǒng)自己去找node的執(zhí)行程序。至于這玩意具體什么,百度出這么個東西,可自行參考。
//index.js
#!/usr/bin/env node
console.log("謝邀,人在美國,剛下飛機。");
然后在cmd輸入npn link或npm install -g將當前項目安裝到全局環(huán)境,這樣就可以直接使用exercise-cli來運行文件了:
再學一點,在package.json的scripts字段里添加腳本名:
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"exercise":"exercise-cli"
}
命令行輸入npm run exercise,同樣輸出了index.js里的內(nèi)容,聯(lián)想起vue-cli的npm run dev、npm run build等會不會若有所思呢?
起飛有點樣子了,接下來讓我們看看它是如何生成項目模板的,一個思路是用一個templates文件夾保存項目模板,然后通過fs.mkdir()來創(chuàng)建項目目錄,最后把文件從templates文件夾拷貝到項目中去。本地templates目錄如下圖所示:
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,該文件夾下會publicjsvue.min.js:
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);//創(chuàng)建讀取流
let writable=fs.createWriteStream(_dst);//創(chuàng)建寫入流
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文件:
3.接收命令行參數(shù)
平常我們使用命令行工具時都會用到參數(shù),如webpack -p, express -e 等,在此我們?yōu)?b>exercise-cli配置-l,當使用exercise-cli -l時,添加layerJS。
我們可以使用process.argv來獲取命令行參數(shù),process.argv是一個參數(shù)數(shù)組,第一項為node.exe的絕對路徑,第二項為執(zhí)行該js的絕對路徑,使用process.argv.slice(2)即可獲取輸入的參數(shù)數(shù)組。
//index.js console.log(process.argv);
通過遍歷參數(shù)數(shù)組來檢查命令中輸入了哪些參數(shù)。如果輸入了預設的參數(shù),就為config對象添加對應的屬性,在生成文件時根據(jù)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,執(zhí)行成功,js目錄中多出了layerJS目錄:
加速 初始commander.js
其實node中有一款工具包可以快速開發(fā)命令行工具,它就是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 后面跟的參數(shù)值 checkname: " + checkname);
console.log(option);
// 獲得了參數(shù),可以在這里做響應的業(yè)務處理
})
//自定義幫助信息
.on("--help", function() {
console.log(" 下面我隨便說兩句:")
console.log("")
console.log("$ 人有多大膽,母豬多大產(chǎn),i love xx")
console.log("$ 廣闊天地,大有所為,呱~")
})
program.parse(process.argv)
命令行執(zhí)行:
看完輸出一臉懵逼,別急,這就帶您瞧瞧這都是些什么東西:
version - 定義命令程序的版本號,.version("0.0.1", "-v, --version"),第一個參數(shù)版本號必須,第二個參數(shù)可省略,默認為 -V 和 --version
command – 定義命令行指令,后面可跟上一個name,用空格隔開,如 .command("app [name]")
alias – 定義一個更短的命令行指令 ,如執(zhí)行命令$ exercise-cli c 與之是等價的
description – 描述,它會在help里面展示
option – 定義參數(shù)。它接受四個參數(shù),在第一個參數(shù)中,它可輸入短名字 -a和長名字–name ,使用 | 或者,分隔,在命令行里使用時,這兩個是等價的,區(qū)別是后者可以在程序里通過回調(diào)獲取到;第二個為描述, 會在 help 信息里展示出來;第三個參數(shù)為回調(diào)函數(shù),他接收的參數(shù)為一個string,有時候我們需要一個命令行創(chuàng)建多個模塊,就需要一個回調(diào)來處理;第四個參數(shù)為默認值
action – 注冊一個callback函數(shù),這里需注意目前回調(diào)不支持let聲明變量
parse – 用于解析process.argv,設置options以及觸發(fā)commands,用法示例:.parse(process.argv)
看到這,多多少少對如何編寫命令行工具有個大體的認知了,光說不練嘴把式,自我實踐:用commander.js完成上個段落3.接收命令行參數(shù)中的例子。
分割線(以下深入和淺出部分于2019.4.30 更)
深入inquirer.js創(chuàng)建腳手架的時候我們會發(fā)現(xiàn)很多腳手架都需要我們和命令行頻繁交互,就像我們開始使用npm init的時候一樣,那么是如何實現(xiàn)和命令行交互的呢?此時inquirer.js閃亮登場。
//命令行安裝
npm install inquirer
//index.js引入
var inquirer = require("inquirer");
基本語法
var inquirer = require("inquirer");
inquirer.prompt([/* Pass your questions in here */]).then(function (answers) {
// Use user feedback for... whatever!!
})
參數(shù)詳解
type:表示提問的類型,包括:input, confirm, list, rawlist, expand, checkbox, password, editor;
name: 存儲當前問題回答的變量;
message:問題的描述;
default:默認值;
choices:列表選項,在某些type下可用,并且包含一個分隔符(separator);
validate:對用戶的回答進行校驗;
filter:對用戶的回答進行過濾處理,返回處理后的值;
transformer:對用戶回答的顯示效果進行處理(如:修改回答的字體或背景顏色),但不會影響最終的答案的內(nèi)容;
when:根據(jù)前面問題的回答,判斷當前問題是否需要被回答;
pageSize:修改某些type類型下的渲染行數(shù);
prefix:修改message默認前綴;
suffix:修改message默認后綴。
實例分析
在.action的回調(diào)函數(shù)里輸入以下內(nèi)容:
// 獲得了參數(shù),可以在這里做響應的業(yè)務處理
var prompList = [
{
type:"input",
message:"姓名",
name:"name"
},{
type:"input",
message:"手機號",
name:"phone",
validate:val=>{
if(val.match(/d{11}/g)){
return true
}
return "請輸入11位數(shù)字"
}
},{
type:"confirm",
message:"是否參加本次考核?",
name:"assess",
prefix:"前綴"
},{
type:"confirm",
message:"是否同意本次考核須知?",
name:"notice",
suffix:"后綴",
when:answers=>{
return answers.assess
}
},{
type:"list",
message:"歡迎來到本次考核,請選擇學歷:",
name:"eductionBg",
choices:[
"大專",
"本科",
"本科以上"
],
filter:val=>{//將選擇的內(nèi)容后面加學歷
return val+"學歷"
}
},{
type:"rawlist",
message:"請選擇你愛玩的游戲:",
name:"game",
choices:[
"LOL",
"DOTA",
"PUBG"
]
},{
type:"expand",
message:"請選擇你喜歡的水果:",
name:"fruit",
choices: [
{
key: "a",
name: "Apple",
value: "apple"
},
{
key: "O",
name: "Orange",
value: "orange"
},
{
key: "p",
name: "Pear",
value: "pear"
}
]
},{
type:"checkbox",
message:"請選擇你喜歡的顏色:",
name:"color",
choices:[
{
name: "red"
},
new inquirer.Separator(), // 添加分隔符
{
name: "blur",
checked: true // 默認選中
},
{
name: "green"
},
new inquirer.Separator("--- 分隔符 ---"), // 自定義分隔符
{
name: "yellow"
}
]
},{
type:"password",
message:"請輸入你的游戲密碼:",
name:"pwd"
}
]
inquirer.prompt(prompList).then(answers=>{
console.log(answers);
})
命令行交互如下:
淺出chalk.js
最后我們引入chalk這個美化命令行的模塊,它具有輕量級、高性能、學習成本低等特點。繼續(xù)在以上例子中引入chalk進行輸出:
//命令行安裝
npm install chalk
//index.js引入
var chalk = require("chalk");
在inquirer里打印如下:
inquirer.prompt(prompList).then(answers=>{
console.log(answers);
console.log(chalk.green("考核完成"))//字體綠色
console.log(chalk.blue("你最棒了"))//字體藍色
console.log(chalk.blue.bgRed("五一放假嘍")) //支持設置背景
console.log(chalk.blue(answers))
})
命令行最終顯示如下:
感興趣的話還是自己敲一下吧。
著陸
想讓別人來安裝你的cli工具,你需要把它發(fā)布到npm上,先在npm官網(wǎng)創(chuàng)個賬號(注意需要郵件驗證),在命令行輸入npm adduser,依次填上你注冊的username、password、email。接著輸入npm publish即可:
輸入npm install -g exercise-cli或npm install exercise-cli安裝一下你的cli感受它的魅力吧。
代碼已上傳至我的GitHub,歡迎Fork。
感謝跟著老司機玩轉(zhuǎn)命令行
用node編寫cli工具
用commander.js構建自己的腳手架工具
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/7346.html
摘要:關于本文是一個開源的應用容器引擎,讓開發(fā)者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發(fā)布到任何流行的機器上。比如說,通過堆棧來開發(fā)應用的每個部分。開發(fā)環(huán)境之前提到的,能夠很容易的引入文件并且使用它們。 關于本文Docker 是一個開源的應用容器引擎,讓開發(fā)者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發(fā)布到任何流行的 Linux 機器上。幾乎沒有性能開銷,可以很容...
摘要:現(xiàn)實情況公司也不可能再給我配幾個屏幕,辛虧自開始可以在屏幕中實現(xiàn)分屏了。 前言:本人前端開發(fā),在日常開發(fā)中需要打開多個窗口進行開發(fā),如:本地服務窗口,ide工具,設計圖,prd文檔,瀏覽器,瀏覽器調(diào)試工具; 如此多的窗口同時打開并且時常需要查看的情況下,遺憾的是,即使我是雙屏開發(fā)也有一種力不從心的感覺。現(xiàn)實情況公司也不可能再給我配幾個屏幕,辛虧自windows7開始可以在屏幕中實現(xiàn)分屏...
摘要:現(xiàn)實情況公司也不可能再給我配幾個屏幕,辛虧自開始可以在屏幕中實現(xiàn)分屏了。 前言:本人前端開發(fā),在日常開發(fā)中需要打開多個窗口進行開發(fā),如:本地服務窗口,ide工具,設計圖,prd文檔,瀏覽器,瀏覽器調(diào)試工具; 如此多的窗口同時打開并且時常需要查看的情況下,遺憾的是,即使我是雙屏開發(fā)也有一種力不從心的感覺。現(xiàn)實情況公司也不可能再給我配幾個屏幕,辛虧自windows7開始可以在屏幕中實現(xiàn)分屏...
閱讀 566·2021-11-18 10:02
閱讀 1048·2021-11-02 14:41
閱讀 674·2021-09-03 10:29
閱讀 1893·2021-08-23 09:42
閱讀 2728·2021-08-12 13:31
閱讀 1199·2019-08-30 15:54
閱讀 1952·2019-08-30 13:09
閱讀 1427·2019-08-30 10:55