
1 前言
本文面向有JavaScript開發經驗且希望入門CLI工具制作的開發人員。文中沒有太多理論知識,通過從0到1開發一個簡單的CLI工具,分享了CLI工具的開發、釋出流程。看完本文,你可以學會如何"私人定制"一個CLI工具來提升開發效率。
總之,簡單,實用,有趣。
2 什麼是CLI工具
維基百科是這樣定義CLI的
CLI(Command-line Interface),指令行界面,指通過輸入字元組成的指令行進行操作的使用者界面。
常見的CLI工具舉例
- 系統指令:cd、mkdir、ifconfig
- 腳手架工具:create-react-app、vue-cli、yeoman
- 預處理器:less、sass、babel
- 測試工具:mocha、karma、wrk
- 建構工具:webpack、gulp、grunt
3 為什麼要自己開發CLI工具
舉例,如果想檢視本機ip位址,通常我會使用
ifconfig
指令,如圖
ifconfig執行結果
執行指令後系統輸出了一堆資訊,從這堆資訊中找到ip位址大概需要花5秒時間,這不是我想要的。我希望的結果是這樣的
ip執行結果
輸入
ip
指令,直接得到本機ip位址,1秒搞定,簡單快捷。
理想很豐滿,現實很骨感。真實的情況是:當我在終端敲下
ip
指令時,系統給我的回報是"command not found:ip"。
ip執行結果
很顯然,系統并沒有為我提供
ip
這個指令,是以我們需要自己來實作它。
4 開始開發CLI工具
4.1 第一步:確定安裝了Node.jsnode版本檢測
4.2 第二步:編寫腳本、測試運作建立檔案夾
ip-cli
,并建立
index.js
mkdir ip-cli && cd ip-cli
touch index.js
編輯
index.js
,内容如下
const os = require("os")
const ip = os.networkInterfaces().en0[1].address
const options = process.argv.slice(2)
if (options[0] === '-v') {
console.log('v1.0.0')
} else {
console.log(`your ip is: ${ip}`)
}
執行
node index.js
,結果如下
執行腳本
4.3 聲明執行環境執行
which env
which env
将傳回的結果設定到
index.js
腳本的第一行,并指定腳本的解釋器為
node
。
然後,代碼就變成了下面這樣
#!/usr/bin/env node
const os = require("os")
const ip = os.networkInterfaces().en0[1].address
const options = process.argv.slice(2)
if (options[0] === '-v') {
console.log('v1.0.0')
} else {
console.log(`your ip is: ${ip}`)
}
代碼中的
#!
被稱為
Shebang
,是用來告訴編譯器用什麼指令執行檔案的。
Shebang
的一些具體用法羅列如下
1、如果腳本檔案中沒有這一行,那麼執行時會預設采用目前Shell去解釋這個腳本(即:
#!
$SHELL
環境變量)。
2、如果
#!
之後的解釋程式是一個可執行檔案,那麼執行這個腳本時,它就會把檔案名及其參數一起作為參數傳給那個解釋程式去執行。
3、如果
指定的解釋程式沒有可執行權限,則會報錯“bad interpreter: Permission denied”。如果
#!
#!
指定的解釋程式不是一個可執行檔案,那麼指定的解釋程式會被忽略,轉而交給目前的SHELL去執行這個腳本。
4、如果
指定的解釋程式不存在,那麼會報錯“bad interpreter: No such file or directory”。注意:
#!
之後的解釋程式,需要寫其絕對路徑(如:
#!
),它是不會自動到
#!/bin/bash
$PATH
中尋找解釋器的。
5、當然,如果你使用類似于”bash test.sh”這樣的指令來執行腳本,那麼
#!
這一行将會被忽略掉,解釋器當然是用指令行中顯式指定的bash。
6、腳本檔案必須擁有可執行權限。
env
可以在系統的
PATH
目錄中查找腳本解釋器安裝目錄。
添加
#!/usr/bin/env node
是告訴系統,這個腳本使用
Node.js
來執行。這樣我們就可以簡化指令,執行
index.js
直接得到ip位址,不需要顯式的調用
node index.js
。
4.4 配置設定執行權限在我們直接執行
index.js
後,結果如下
執行index.js
我們并沒有得到ip位址,檢視檔案發現
index.js
沒有可執行權限。
檢視檔案
執行
chmod +x index.js
給腳本配置設定可執行權限,然後
index.js
就可以執行了。
增加可執行權限
4.5 設定環境變量執行
$PATH
檢視環境變量
PATH
可以看到我電腦的
PATH
變量為
/usr/local/mongodb/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:“/usr/libexec/java_home”::/platform-tools:/tools:“/usr/libexec/java_home”:“/usr/libexec/java_home”/bin:/usr/local/mongodb/bin:/Users/qianxuemin/bin/
這裡
usr
指
Unix System Resource
,而不是
User
, 通常
/usr/bin
下面的都是系統預裝的可執行程式,會随着系統更新而改變,
/usr/local/bin
目錄是給使用者放置自己的可執行程式的地方,推薦放在這裡,不會被系統更新而覆寫同名檔案。如果兩個目錄下有相同的可執行程式,誰優先執行受到
PATH
環境變量的影響,比如我的電腦
PATH
變量中,
/usr/local/bin
優先于
/usr/bin
。
接下來執行
ln index.js /usr/local/bin/ip
,建立
index.js
的一個硬連結檔案
/usr/local/bin/ip
,如圖
ln
然後就可以直接使用自定義的指令
ip
了 。
ip
如果隻是自己使用,那麼一個簡單的CLI工具就開發完畢了,但作為一名喜歡分享的童鞋,我希望可以把這個CLI工具分享給他人。
這時候可以選擇使用npm管理項目,與他人共享開發成果。為了示範在npm項目中開發CLI工具的流程,我們暫時先删除剛才的指令
ip
删除指令
5 使用npm 管理項目
5.1 初始化npm項目執行
npm init -y
将項目初始化為npm項目
初始化
目錄結構如下
.
├── index.js
└── package.json
5.2 設定bin字段 在
package.json
中設定
bin
字段,定義一個指令
ip
并指定該指令執行
./index.js
檔案
{
"name": "ip-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": {
"ip": "./index.js"
},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
5.3 測試CLI工具 執行
npm link
,在全局的
node_modules
下生成一個符号連結
npm link
然後就可以在全局使用
package.json
中
bin
字段定義的指令
ip
了,執行
ip
指令結果如下
ip
輸出了本機IP位址,測試成功。
5.4 釋出CLI工具執行
npm login
登入賬号,登入成功後執行
npm whoami
可以看到npm使用者名
npm whoami
确認無誤後執行
npm publish
釋出npm包。
釋出包的時候需要確定包的名字沒有被占用,如下是包名沖突的情況
npm publish
遇到這種情況可以選擇換個名字或者加
scope
,如下我給包名增加
scope
,将包名由
ip-cli
改為
@qianxuemin/ip-cli
{
"name": "@qianxuemin/ip-cli",
"version": "1.0.2",
"description": "",
"main": "index.js",
"bin": {
"ip": "./index.js"
},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
加了
scope
後,釋出包的時候需要設定通路級别,我們設定為公開
npm publish
釋出成功後,其他開發人員就可以通過
npm install @qianxuemin/ip-cli -g
安裝并使用了。
ip
至此,一個簡單的CLI工具開發、釋出完成。
6 注意事項
上面示範了CLI工具的整體開發、釋出流程,沒有對細節做太多說明。如下總結了在日常開發CLI工具中需要注意的事項與大家分享:
1、工具應當包含完整的
README.md
2、工具應當包含
help
和
version
資訊
3、工具應當包含運作訓示,比如加載中
4、釋出之前要到 https://www.npmjs.com 查找一下自己的包名有沒有被占用,如果被占用需要先修改包名或加
scope
5、釋出包時,可以通過在項目中添加
.npmignore
或
.gitignore
檔案限制釋出的檔案内容,
.npmignore
優先級高于
.gitignore
。或者在
package.json
中
files
字段設定釋出哪些檔案或目錄,它的優先級高于
.npmignore
和
.gitignore
。
7 開發CLI工具常用的庫
相比原生Node.js,使用一些開源子產品能夠簡化CLI工具的開發,提高開發效率。如下是開發CLI工具常用的子產品:
- commander: 注冊、解析指令行參數
- Inquirer: 讓指令行與使用者進行互動
- chalk: 給指令行字元加顔色
- shelljs: 跨平台調用shell指令的node封裝
- Ora: 指令行提示圖示
- progress: 指令行進度條
- blessed-contrib: 指令行可視化元件
- download-git-repo:拉取git倉庫源代碼
由于文章篇幅有限,這裡就不一一進行介紹了,使用時可以直接到 https://www.npmjs.com/搜尋。
8 總結
本文通過一個簡單的例子分享了CLI工具的開發、釋出流程,并總結了一些開發注意事項和常用的庫。旨在幫助JavaScript開發人員入門CLI工具開發。希望大家都能在掌握CLI工具開發流程後,發揮想象力,開發出一些實用、好玩的東西,讓我們的開發變得高效、有趣。
9 參考資料
- npm官網:https://www.npmjs.com.cn/
- Shebang:https://zh.wikipedia.org/wiki/Shebang
- Shebang:https://blog.csdn.net/u012294618/article/details/78427864
- awesome-nodejs:https://github.com/sindresorhus/awesome-nodejs#command-line-apps