前端工程化日益盛行,腳手架成爲了咱們平常開發中必不可少的東西,例如:vue-cli、react-create-app
等等。前端
使用腳手架,咱們能夠很方便的簡化咱們的開發流程,有效的提升咱們的研發能效vue
例如咱們須要從零開始搭建一個項目,首先須要去建立目錄,在個目錄下去建立相應初始化的文件,去配置 webpack、gulp、rollup
等模塊打包器,這每每會花費咱們一天甚至數天的時間。然而腳手架只須要在命令行敲入簡簡單單的一行命令,便可在短短的幾分鐘內爲你建立一個項目模板,極大程度上節省了咱們的時間成本。java
相信大部分的同窗對腳手架的認識只停留在使用上面,今兒咱們就來了解一下腳手架的原理。node
注:本文章是使用 Node.js 進行腳手架開發的react
你們能夠想想腳手架的做用是什麼?開發腳手架的核心目標是什麼?webpack
沒錯,就是提高研發效能!git
項目重複、代碼拷貝、git 操做、發佈上線操做
項目建立、git flow、發佈流程、回滾流程
研發過程系統化、數據化、使研發過程能夠被量化
有的同窗可能會問到,世面上已經有了 jenkins、travis
等自動化構建工具了,並且也很成熟,爲何還要開發相關的腳手架?web
jenkins、travis
一般在 git hooks
中觸發,須要在服務端執行,沒法覆蓋研發人員本地的功能,如:建立項目自動化、本地 git
操做自動化等jenkins、travis
定製過程須要開發插件,其過程較爲複雜,須要使用 java
語言,對前端開發不夠友好腳手架本質上來講,其實就是一個操做系統的客戶端。vue-cli
它經過命令行來執行,例如:npm
vue create vue-project
複製代碼
爲何咱們在命令行中輸入 vue create vue-project
後就能執行呢?
用戶在命令行中輸入了命令 vue create vue-project
,操做系統首先會在全局的環境變量裏面去查找 vue
這個環境變量,找到後就會去執行它,沒有找到就會報錯,以下圖所示:
經過 npm
全局安裝一個腳手架例如 @vue/cli
後,會去解析 package.json
文件中的 bin
配置,而後會去在 node
的安裝目錄下的 bin
目錄中,建立一個軟鏈接而且鏈接到軟件包中,軟鏈接的名稱就是 bin
配置的 key(鍵值對的鍵)
,鏈接的文件就是 bin
配置的 value(鍵值對的值)
,value
指向的文件中須要設置 #! /usr/bin/env node
來標識文件執行的方法
第一步:咱們須要建立一個文件夾 test-cli
;
第二步:在命令行中,進入到 test-cli
文件夾,而後執行 npm init
初始化項目;
第三步:修改 package.json
文件,在裏面的配置項里加上以下的:
{
...
"bin": {
"test-cli": "./bin/index.js"
},
...
}
複製代碼
第四步:在 test-cli
裏面新建一個 bin
文件夾,而且在裏面建立一個 index.js
文件,接下來打開 index.js
文件在裏面第一行寫上 #! /usr/bin/env node
;
第五步:能夠寫上一些內容了,好比 console.log('xxx')
滑稽臉;
第六步:在命令行中,進入到 test-cli
文件夾,而後執行 npm link
;
第七步:在命令行中,輸入 test-cli
而且回車,你就會發如今命令行中就會打印出 xxx
;
這就是一個最簡單的腳手架了,若是你想作的更好一點的,好比經常使用腳手架的一些命令式操做能夠了解一下 yargs、commander
兩個插件,這裏給上一個基於 commander
的註冊命令的代碼,有興趣的同窗能夠複製到剛剛的 index.js
裏面執行一下 test-cli --help
:
#! /usr/bin/env node
const commander = require('commander')
const pkg = require('../package.json')
// 獲取 commander 的單例
// const { program } = commander
// 手動實例化一個 commander 實例
const program = new commander.Command()
program
.name(Object.keys(pkg.bin)[0])
.usage('<command> [options]')
.version(pkg.version)
.option('-d, --debug', '是否開啓調試模式', false)
.option('-e, --env <envName>', '獲取環境變量名稱', false)
// addCommand 註冊子命令
const service = new commander.Command('service')
service
.command('start [port]')
.description('start service at some port')
.action((prot, cmdObj) => {
console.log('do server start', prot)
})
service
.command('stop')
.description('stop service')
.action(() => {
console.log('do server stop')
})
program.addCommand(service)
program.on('option:debug', () => {
console.log('debug')
})
program.on('command:*', (obj) => {
console.log('未知的命令', obj)
const availableCommands = program.commands.map(cmd => cmd.name())
console.log('可用的命令', availableCommands)
})
program
.parse(process.argv)
// console.log(program.debug)
// console.log(program.env)
// console.log(program.opts())
複製代碼
腳手架的開發博大精深,它爲我打開了一個新世界的大門,同時也讓我對 Node.js 也有了更深刻的瞭解。也是突破現有技術瓶頸的一個方向,也是做爲一個高級前端開發工程師必需要掌握的技能。