從 1 到完美,用 node 寫一個命令列工具
1. package.json
中的 bin
欄位
現在,不管是前端專案還是 node
專案,一般都會用 npm
做包管理工具,而 package.json
是其相關的配置資訊。
對 node
專案而言,模組匯出入口檔案由 package.json
的 main
欄位指定,而如果是要安裝到命令列的工具,則是由 package.json
的 bin
欄位指定。
1.1 配置單個命令
與包名同名
{ "name": "pro", "bin": "bin/pro.js" }
這樣安裝的命令名稱就是 pro
。
自定義命令名稱(與包名不同名)
{ "name": "pro-cli", "bin": { "pro": "bin/pro.js" } }
這樣安裝的命令名稱也是 pro
。
1.2 配置多個命令
{ "name": "pro-cli", "bin": { "pro": "bin/pro.js", "mini": "bin/mini.js" } }
這樣安裝就有 pro
與 mini
兩個命令。
2. 對應 bin/pro.js
檔案的寫法
#!/usr/bin/env node require('../lib/pro');
與普通的 js
檔案寫法一樣,只是前面要加上 #!/usr/bin/env node
。
這段字首程式碼叫 shebang
,具體可以參考 Unix)" target="_blank" rel="nofollow,noindex">Shebang (Unix) - Wikipedia .
3. 安裝方式
3.1 全域性安裝
npm i -g pro-cli
這種安裝方式可以在命令列全域性使用。
pro dev pro build
3.2 本地安裝
npm i --save-dev pro-cli
這種安裝方式需要配合 npm
一起使用,比如:
# package.json { "scripts": { "dev": "pro dev", "build": "pro build" } } # 使用 npm run dev npm run build
4. 選擇合適的命令列封裝庫
一般來說,一個命令都會有如下的一些引數:
-
-v, --version
或-V, --version
: 檢視版本號 -
-h, --help
: 檢視幫助資訊
如果完全自己來寫的,就會很麻煩,尤其是幫助資訊。所以,選擇一個好的命令列封裝庫,能夠幫我們省去很多工作。
用的比較多的:
以 commander.js
為例:
4.1 安裝
npm install commander --save
4.2 註冊
const commander = require('commander');
註冊版本號與描述
commander .version('0.0.1') .description('A cli application named pro');
註冊引數(非子命令引數)
commander .option('-p, --peppers', 'Add peppers') .option('-P, --pineapple', 'Add pineapple') .option('-b, --bbq-sauce', 'Add bbq sauce') .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
註冊子命令
commander .command('rm <dir>') .option('-r, --recursive', 'Remove recursively') .action((dir, cmd) => { console.log('remove ' + dir + (cmd.recursive ? ' recursively' : '')) })
解析
commander.parse(process.argv);
4.3 使用
檢視版本號
pro -V pro --version # 列印結果 0.0.1
執行 rm
子命令
pro rm dir
檢視幫助( commander
會自動生成)
pro -h pro --help # 列印結果 Usage: pro [options] A cli application named pro Options: -h, --helpoutput usage information -V, --versionoutput the version number -p, --peppersAdd peppers -P, --pineappleAdd pineapple -b, --bbqAdd bbq sauce -c, --cheese <type>Add the specified type of cheese [marble] -C, --no-cheeseYou do not want any cheese
更多用法檢視 commander.js 。
5. 常用的命令列相關工具庫
5.1 minimist : 解析命令列的引數
var argv = require('minimist')(process.argv.slice(2)); console.dir(argv);
$ node example/parse.js -a beep -b boop { _: [], a: 'beep', b: 'boop' }
$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz { _: [ 'foo', 'bar', 'baz' ], x: 3, y: 4, n: 5, a: true, b: true, c: true, beep: 'boop' }
更多參考 minimist 。
5.2 chalk : 讓命令列的字元帶上顏色

更多參考 chalk 。
5.3 Inquirer.js : 讓命令列與使用者進行互動,如輸入、選擇等

更多參考 Inquirer.js 。
5.4 shelljs : 跨平臺 Unix shell 命令 的 node 封裝
var shell = require('shelljs'); if (!shell.which('git')) { shell.echo('Sorry, this script requires git'); shell.exit(1); } // Copy files to release dir shell.rm('-rf', 'out/Release'); shell.cp('-R', 'stuff/', 'out/Release'); // Replace macros in each .js file shell.cd('lib'); shell.ls('*.js').forEach(function (file) { shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file); shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file); }); shell.cd('..'); // Run external tool synchronously if (shell.exec('git commit -am "Auto-commit"').code !== 0) { shell.echo('Error: Git commit failed'); shell.exit(1); }
更多參考 shelljs 。
5.5 blessed-contrib : 命令列圖表

更多參考 blessed-contrib 。
5.6 cash : 跨平臺 linux 命令 的 node 封裝
與 shelljs 功能差不多。
const $ = require('cash'); const out = $.ls('.', {l: true});
更多參考 cash 。
5.7 prompts : 又一個讓命令列與使用者進行互動的工具
與 Inquirer.js 功能差不多。

更多參考 prompts 。
5.8 ora : 命令列載入中圖示

更多參考 ora 。
5.9 progress : 命令列進度條
downloading [===== ] 39/bps 29% 3.7s
更多參考 progress 。
5.10 更多
更多關於命令列的工具庫可以參考 command-line-utilities 。
6. 比較常用的命令列 APP
命令列相關的應用就很多啦,比如 babel
、 webpack
、 rollup
、 eslint
等,但這些不僅僅是命令列工具。
下面介紹一些純命令列應用:
- vtop : 美美的 linux top 命令介面
- speed-test : 測試網路連結速度
- http-server : 零配置啟動一個 http 伺服器
- fkill-cli : 跨平臺 kill 命令
更多純命令列應用可以參考 command-line-apps 。
後續
更多部落格,檢視 https://github.com/senntyou/blogs
轉載:作者: 深予之 (@senntyou)