本文帶你瞭解建立一個Node-CLI工具所需知識點。javascript
在NodeJS中能夠經過如下代碼獲取命令行中傳遞的參數:css
process.argv.slice(2)
複製代碼
可是這對於構建一個CLI工具遠遠不夠,首先須要考慮參數輸入的各類風格:html
這裏能夠經過正則表達式對process.argv進行加工:vue
/** * 解析Unix、BSD和GNU參數風格 * @param {Array} argv 命令行參數數組 * @returns */
function parseArgv (argv) {
const max = argv.length
const result = {
_: []
}
for (let i = 0; i < max; i++) {
const arg = argv[i]
const next = argv[i + 1]
if (/^--.+/.test(arg)) {
// GNU風格
const key = arg.match(/^--(.+)/)[1]
if (next != null && !/^-.+/.test(next)) {
result[key] = next
i++
} else {
result[key] = true
}
} else if (/^-[^-]+/.test(arg)) {
// Unix風格
const items = arg.match(/^-([^-]+)/)[1].split('')
for (let j = 0, max = items.length; j < max; j++) {
const item = items[j]
// 非字母不解析
if (!/[a-zA-Z]/.test(item)) {
continue
}
if (next != null && !/^-.+/.test(next) && j === max - 1) {
result[item] = next
i++
} else {
result[item] = true
}
}
} else {
// BSD風格
result._.push(arg)
}
}
return result
}
複製代碼
經過以上的方法能夠獲得以下結果:java
node example1.js --save-dev -age 20 some
// => 結果
{
_: ['some'],
'save-dev': true,
a: true,
g: true,
e: 20
}
複製代碼
上面這個示例不單單爲了展現解析的結果,並且還強調了Unix參數風格只解析單個字母,因此這種風格的參數可能表達的意思不太明確而且數量有限,那麼就須要在正確的場景中使用這種風格的參數:node
npm --save-dev webpack
npm -D webpack
複製代碼
npm中採用Unix參數風格表示簡寫,這就是一種很恰當的方式,那麼前面示例中的-age按照語義應該改成--age更加合理一點。webpack
NodeJS中的readline模塊提供question和prompt方法構建命令行界面,下面是一個簡單的問答式的交互界面:git
const readline = require('readline');
const question = ['請輸入您的姓名', '請輸入您的年齡']
const result = []
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: `?${question[0]} `
});
rl.prompt();
rl.on('line', (line) => {
result.push(line.trim())
const max = result.length
if (max === question.length) {
rl.close()
}
rl.setPrompt(`?${question[max]} `)
rl.prompt();
}).on('close', () => {
console.log(`謝謝參與問答 *** 姓名: ${result[0]} 年齡: ${result[1]}`);
process.exit(0);
});
複製代碼
固然交互界面的元素並不僅有這一種,在使用各種CLI工具時,你應該會遇到諸如:單項選擇、下載進度條...
下面能夠嘗試實現一個單項選擇交互界面:github
const readline = require('readline')
let selected = 0
const choices = ['javascript', 'css', 'html']
let lineCount = 0
const rl = readline.createInterface(process.stdin, process.stdout)
function reader () {
let str = ''
for (let i = 0; i < choices.length; i++) {
lineCount++
str += `${selected === i ? '[X]' : '[ ]'} ${choices[i]}\r\n`
}
process.stdout.write(str)
}
reader()
process.stdin.on('keypress', (s, key) => {
const name = key.name
const max = choices.length
if (name === 'up' && selected > 0) {
selected--
} else if (name === 'down' && selected < max - 1) {
selected++
} else if (name === 'down' && selected === max - 1) {
selected = 0
} else if (name === 'up' && selected === 0) {
selected = max - 1
} else {
return true
}
// 移動光標至起始位置,確保後續輸入覆蓋當前內容
readline.moveCursor(process.stdout, 0, -lineCount)
lineCount -= choices.length
reader()
})
rl.on('line', () => {
console.log(`you choose ${choices[selected]}`)
process.exit(0)
}).on('close', () => {
rl.close()
})
複製代碼
爲了有效的區別命令行界面中信息的差別性,咱們能夠爲這裏輸出信息添加適當的樣式。web
這裏介紹一下字符串添加樣式的語法:
\x1b[背景顏色編號;字體顏色編號m
複製代碼
每條樣式都要以\x1b[開頭:
// \x1b[0m 清除樣式
process.stdout.write('\x1b[44;37m OK \x1b[0m just do it\n')
複製代碼
接下來就是自定義Node命令,首先須要建立一個命令執行的文件:
// hello.js 首行須要指定腳本的解釋程序
#!/usr/bin/env node
console.log('hello')
複製代碼
再利用package.json中的bin配置:
{
"bin": {
"hello": "./hello.js"
},
}
複製代碼
執行npm的link命令:
npm link
# 輸入自定義命令
hello
# 輸出 hello
複製代碼
上面介紹了開發Node-CLI時所須要的一些基本知識,可是對於用過諸如webpack-cli、vue-cli工具的你可能會發現這些優秀的CLI工具還具備:
那麼下面這些成熟的框架會給你很大的幫助: