cli 的全稱 command-line interface(命令列介面),也就是前端同學常用的腳手架,比如 yo、vue cli、react cli 等。
cli 可以方便我們快速建立專案,下圖是引用 vue cli 的介紹:
建立專案
執行下面的命令,建立一個專案:
npm init
執行命令完成後,可以看到專案根目錄只有一個 package.json 檔案。
在 package.json 檔案增加 bin 物件,並指定入口檔案 dist/index.js。
在命令列執行需要在入口檔案的第一行增加
#!/usr/bin/env node
,告訴系統用 node 執行這個檔案。
{
"name": "cli-demo",
"version": "0.0.1",
"description": "cli demo",
"keywords": [
"cli"
],
"bin": {
"cli-demo": "dist/index.js"
}
...
}
安裝依賴
命令列工具,也會涉及到使用者互動的動作,那麼 node.js 是怎麼實現呢?早有大佬提供了非常好的庫,我們只要拿過來用,主要有兩個庫:
將這兩個庫安裝到專案裡:
yarn add commander inquirer
由於是用 typescript 開發,再通過 rollup 打包,先安裝相關的依賴庫:
yarn add typescript rollup rollup-plugin-terser rollup-plugin-typescript2 @types/inquirer -D
配置
由於是用 typescript 開發,首先需要配置一下 tsconfig.json。
{
"compilerOptions": {
"target": "ES6",
"module": "ESNext",
"sourceMap": false,
"declaration": false,
"outDir": "./dist",
"moduleResolution": "Node",
"esModuleInterop": true,
"resolveJsonModule": true,
"removeComments": false,
"importHelpers": true,
"strict": true,
"lib": ["ES6", "DOM"]
},
"include": ["src"]
}
接下來在根目錄增加一個 rollup.config.js,把 typescript 程式碼編譯成 javascript 程式碼。前面提到的要在第一行增加 #!/usr/bin/env node
來告訴系統用 node 執行,那麼可以在 rollup.config.js 的 banner
選項,把 #!/usr/bin/env node
寫在最前面。
import typescript from 'typescript'
import json from '@rollup/plugin-json'
import { terser } from 'rollup-plugin-terser'
import typescript2 from 'rollup-plugin-typescript2'
import { dependencies } from './package.json'
const external = Object.keys(dependencies || '')
const globals = external.reduce((prev, current) => {
const newPrev = prev
newPrev[current] = current
return newPrev
}, {})
const defaultConfig = {
input: './src/index.ts',
output: {
file: './dist/index.js',
format: 'cjs',
banner: '#!/usr/bin/env node',
globals
},
external,
plugins: [
typescript2({
exclude: 'node_modules/**',
useTsconfigDeclarationDir: true,
typescript,
tsconfig: './tsconfig.json'
}),
json(),
terser()
]
}
export default defaultConfig
實現一個簡單的 cli
在根目錄建立一個 src
資料夾,然後再建立一個 index.ts
。
新增引用
新增引用並例項化 Command
物件。
import { Command } from 'commander'
import pkg from '../package.json'
const program = new Command(pkg.name)
自定義命令
實現一個可互動的自定義命令,模擬在終端(命令列)的登入功能。使用 command
方法建立一個命令,description
可以用來描述這個命令的作用,登入處理邏輯則寫在 action
方法裡。最後使用 parse(process.argv)
方法,解析命令。更多詳細介紹和使用,可移步:https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md。
program
.command('login')
.description('模擬登入。')
.action(() => {
handleLogin()
})
program.parse(process.argv)
互動的話,用到前面說的 inquirer
庫,接收輸入的使用者名稱和密碼。選項的 type
的值有 input
、password
、number
、checkbox
、editor
、list
、rawList
、expand
、confirm
,選項 name
是 inquirer.prompt
方法返回的物件,選項 validate
可用來驗證輸入是否符合規則。更多詳細介紹和使用,可移步:https://github.com/SBoudrias/Inquirer.js/blob/master/README.md
如果選項
type
是password
,可通過mask
設定掩碼。
const handleLogin = () => {
// 配置互動的使用者名稱和密碼
const prompt = [
{
type: 'input',
name: 'userName',
message: '使用者名稱:',
validate: (value: string) => value.length > 0 || '使用者名稱不能為空'
},
{
type: 'password',
name: 'password',
message: '密碼:',
mask: '? ',
validate: (value: string) => value.length > 0 || '密碼不能為空'
}
]
inquirer.prompt(prompt).then(({ userName, password }) => {
if (userName === 'demo' || password === '123456') {
console.log('登入成功')
return
}
console.log('使用者名稱或密碼錯誤')
})
}
其他
一個 cli 工具,幫助資訊也是必須的,可以通過 on('--help')
修改自定義幫助資訊。
必須在
parse
方法之前。
program.on('--help', () => {
console.log('\n執行 cli-demo -h | --help 檢視命令使用。\n')
})
然後再來修改一下,沒有輸入任何引數的時候,會出現錯誤,可以使用 exitOverride
方法重新退出,在終端(命令列)輸出幫助資訊。
program.exitOverride()
try {
program.parse(process.argv)
} catch (error) {
program.outputHelp()
}
到這裡,一個簡單的 cli 工具完成了,先本地來測試下看看。在終端(命令列)輸入 npm link
,生成一個全域性軟連線,可以方便除錯和測試。