vue create my-vue-project
html
用過Vue的同窗基本都接觸過vue腳手架:vue-cli,經過上面那行命令,回答幾個問題,咱們就能輕鬆建立出一個Vue項目。由於團隊工程化須要,我最近開始學習cli,打算用做團隊腳手架或收攏我的經常使用命令(如按照格式提交代碼)。vue
vue-cli的原理網上已經有不少不錯的分析,而本文將從基礎知識學習開始,一步步進階到實際應用。但願能幫助你們在學會使用工具的同時,瞭解背後的原理。養成「打破砂鍋問到底」的學習習慣。node
當你在控制檯敲下npm -v
並回車的時候,到底發生了什麼?linux
咱們先來看看npm
這個命令在哪。經過執行which npm
,(不瞭解which命令的同窗能夠參考這裏:linux命令之which),能夠看到,npm
命令的可執行文件在/usr/local/bin/npm
,打開文件夾一看,是個替身,右鍵「顯示原身」(Mac用戶的方法,其餘用戶請搜索「軟連接」),就能定位到該命令在哪:/usr/local/lib/node_modules/npm/bin/npm-cli.js
,看到是js代碼相信你們已經鬆了一口氣,咱們先不急着看npm-cli.js
裏面的源,咱們先思考一個問題:git
Q1:系統是怎麼找到
npm
這個這個命令的可執行文件的?github
A1:瞭解
which
命令的同窗都知道,which
命令會按照PATH
變量中的路徑順序來查找可執行文件。執行echo $PATH
能夠打印出該變量內容:/usr/local/bin:/usr/bin:/bin
(例如這是個人部份內容,目錄間用‘:’分隔),因此係統會先在/usr/local/bin
下面找npm
執行文件,/usr/local/bin/npm
連接到/usr/local/lib/node_modules/npm/bin/npm-cli.js
。因此調用npm
命令至關於執行npm-cli.js
。vue-cli
總的來講:在控制檯執行命令時,系統會先去環境路徑(PATH)中找到可執行文件,而後執行該文件。shell
那麼,有沒有同窗好奇:npm
Q2:系統又是怎麼執行這些文件(例如上面的npm-cli)的呢?json
A2:打開
npm-cli.js
文件,咱們能看到的第一行代碼就是:#!/usr/bin/env node
,這行代碼到底有什麼用呢?具體可參考:stackoverflow - #!/usr/bin/env到底有什麼用?,大體意思是告知系統用什麼解釋程序來執行該文件,例如#!/usr/bin/env node
就是告知系統,npm-cli.js
要用node
來執行。所以npm -v
至關於node /usr/local/lib/node_modules/npm/bin/npm-cli.js -v
。
$ node /usr/local/lib/node_modules/npm/bin/npm-cli.js -v
6.4.1
複製代碼
瞭解完命令執行過程以後,咱們就能夠打造本身的cli命令了。
①先編寫my-cli.js
文件:
#!/usr/bin/env node
console.log('Hello cli!');
複製代碼
②在/usr/local/bin
下(或者PATH
裏的任意路徑下)建立軟連接:
ln -s my-cli.js my-cli
複製代碼
③給my-cli命令添加可執行權限:(若不添加權限,會報錯bash: /usr/local/bin/my-cli: Permission denied
)
chmod 777 my-cli
複製代碼
④驗證效果:
$ my-cli
Hello cli!
複製代碼
在上面的基礎上,咱們雖然能打造本身的命令,可是這個命令要想給團隊使用,就須要每一個人都拷貝my-cli.js
文件,建立軟連接,添加可執行權限,很是繁瑣。怎麼將本身的命令分發出去給別人使用呢?
咱們再往前探索一步,一塊兒打造一個基於npm分發的命令。
咱們在下載使用一個npm模塊命令的時候,咱們會這樣:
npm install -g @vue/cli
vue create my-project
複製代碼
全局安裝vue-cli
這個npm模塊以後,咱們全局新增了vue
命令,這背後到底發生了什麼?實際上是npm install
幫咱們把上面提到的②③步自動執行了(我的假設,尚未時間去看npm的源碼,若有錯誤,歡迎指出)。既然npm
已經幫咱們完成這些簡單可是繁瑣的腳本操做,那咱們只須要按照npm
的規範來配置一下代碼便可。流程比較簡單,請參考:經過npm包來製做命令行工具的原理。
總結一下開發過程:
npm init
新建npm模塊目錄;my-cli.js
);package.json
中添加bin
字段(bin: { "my-cli": "./my-cli.js" }
);my-cli
;看了前面一二節,咱們已經掌握開發一個團隊cli的方法,剩下的內容將參考[vue-cli源碼](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli/bin/vue.js)
瞭解怎麼優雅地實現一個cli。
這裏直接和你們介紹幾個vue-cli
裏面用到的幾個庫:
更多好用的cli開發庫歡迎你們留言補充。
commander
幾乎是開發cli必不可少的工具,基本使用方法以下:
#!/usr/bin/env node
var program = require('commander');
program
.version('0.1.0')
.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')
.parse(process.argv);
複製代碼
這裏簡單分析一下其原理(參考commander源碼),核心流程以下:
1. 經過option定義收集命令的功能選項;
2. parse解析命令參數(有process得到);
3. 由命令參數去匹配前面收集到的功能選項,執行前面的方法(將參數傳入);
核心源碼以下:
/** * Parse `argv`, settings options and invoking commands when defined. * * @param {Array} argv * @return {Command} for chaining * @api public */
Command.prototype.parse = function(argv) {
// implicit help
if (this.executables) this.addImplicitHelpCommand();
// store raw args
this.rawArgs = argv;
// guess name
this._name = this._name || basename(argv[1], '.js');
// github-style sub-commands with no sub-command
if (this.executables && argv.length < 3 && !this.defaultExecutable) {
// this user needs help
argv.push('--help');
}
// process argv
var parsed = this.parseOptions(this.normalize(argv.slice(2)));
var args = this.args = parsed.args;
var result = this.parseArgs(this.args, parsed.unknown);
// executable sub-commands
var name = result.args[0];
var aliasCommand = null;
// check alias of sub commands
if (name) {
aliasCommand = this.commands.filter(function(command) {
return command.alias() === name;
})[0];
}
if (this._execs[name] && typeof this._execs[name] !== 'function') {
return this.executeSubCommand(argv, args, parsed.unknown);
} else if (aliasCommand) {
// is alias of a subCommand
args[0] = aliasCommand._name;
return this.executeSubCommand(argv, args, parsed.unknown);
} else if (this.defaultExecutable) {
// use the default subcommand
args.unshift(this.defaultExecutable);
return this.executeSubCommand(argv, args, parsed.unknown);
}
return result;
};
複製代碼
最後咱們以vue create my-project
這個命令執行過程結尾,有興趣的同窗推薦看vue-cli的源碼,看源碼是一個很好的學習過程。
vue create my-project
命令執行過程:
bin/vue.js
文件,經過node bin/vue.js create my-project
來執行該文件;bin/vue.js
利用commander
來定義命令選項create
,將create
命令匹配到create方法(lib/create.js
),執行該方法;lib/create.js
使用Inquirer.js來詢問用戶,進行項目配置;package.json
文件(基礎信息,從項目配置中注入對應的開發依賴devDependencies);npm i
來安裝依賴;(PS: 這裏封裝了經常使用的npm操做,能夠直接拷貝到本身項目中使用)vue-cli
插件(@vue/cli-service是第一個被執行的插件);README.md
文件;上面就是create
命令的基本執行過程,若是咱們想擴展create
方法,例如按照咱們的定義的模板生成目錄結構,能夠新建一個插件(generator,能夠參考cli-service),在插件裏生成自定義的目錄結構便可。
經過閱讀源碼有兩個收穫:
至此,咱們已經具有寫出一個實現良好,易於擴展的團隊cli的知識,剩下的事情,就在鍵盤上完成吧。
此外,我提倡「打破砂鍋問到底」,而文章內顯然沒有作到,例如npm
甚至是node
的執行過程尚未去深刻了解。時間永遠是有限的,先有一個好的思考方向,再逐步去深刻就行了。而這每每也能解決當代人的焦慮,方向和努力缺一不可,共勉。