前端工程化系列[06]-Yeoman腳手架核心機制

前端工程化系列[05] Yeoman腳手架使用入門這邊文章中,對Yeoman的使用作了簡單的入門介紹,這篇文章咱們將接着探討Yeoman這個腳手架工具內部的核心機制,主要包括如下內容

❏ Yeoman腳手架工具的價值討論
❏ generator[生成器]的內部結構
❏ generator[生成器]的項目模板
❏ Yeoman腳手架工具的核心運起色制
❏ Yeoman 的主要組裝流程css

Yeoman這樣的腳手架工具解決了什麼問題?

全部新事物都不是憑空產生的,它們的出現總有某些內在的驅動力。一項新技術,一個新工具的出現更是如此。不知道從何時開始起,我接觸新事物新技術以及某些工具的時候,總願意多花點時間想想它出現的緣由是什麼?由於時間、精力等等這些東西都很寶貴,IT從業人員對這些資源尤爲敏感,因此新技術或者新工具的出現我認爲有幾種狀況:html

  • 已有的技術或工具存在缺陷,做者們靠本身的才學推出更完美的替代方案
  • 已有的技術或工具沒法解決既定的需求,做者們探索出解決問題的技術方案
  • 純粹閒的蛋疼(這種狀況通常比較少見)

如今,咱們來研究下Yeoman的價值,或者說Yeoman出現的意義是什麼?Yeoman的出現解決了什麼樣的問題?前端

咱們假設有這樣的開發場景:公司的開發團隊,基於某些特定的技術棧已經完成了項目A的開發和上線等工做,項目A的基本狀況以下node

技術棧:JavaScript + HTML + CSS + Bootstrap + jQuery
工做流:npm(包管理工具) + bower(下載器) + grunt
版本管理工具:Gitjquery

項目總體目錄結構(簡化後)git

.
├── Gruntfile.js
├── bower.json
├── node_modules
│ ├── abbrev
···
│ └── xtend
├── package-lock.json
├── package.json
├── build
│ ├── css
│ │ └── style.min.css
│ └── js
│ ├── index.js
│ └── index.min.js
├── dist
└── src
├── css
│ └── style.css
├── index.html
├── js
│ └── index.js
├── libs
│ ├── bootstrap
│ └── jquery
└── template
說明:上面的目錄中src爲代碼的工做目錄,bulid爲構建後目錄,dist爲發佈目錄。

由於項目A已經上線發佈,如今公司要求着手開展新的項目B,通過需求評審和技術選型後,新項目B採用的工做流和項目A保持一致,技術棧在原有的基礎上嘗試使用TypeScript來處理腳本部分引入Vue框架,其它部分保持不變。咱們發現項目A和項目B它們的結構基本上是一致的(好比項目的目錄就夠,都須要擁有Gruntfile.js和package.json等文件),可是有些部分又不太同樣,好比package.json文件中的項目名稱、開發依賴等。typescript

這個時候,咱們在對項目B進行初始化的方式能夠嘗試如下操做方式:npm

  • 方案① 從0開始建立目錄結構,集成工做流配置開發環境
  • 方案② 從項目A中拷貝目錄結構和固定文件,對於不一樣的部分一個個修改

若是咱們採用方案① 你會發現這個過程你在初始化項目A的時候就已經作過了,是重複性的工做,毫無技術含量可是又費時費力。
若是咱們採用方案② 你會發現要修改的文件有些多,每一個文件要改的字段也比較多,並且容易遺漏老是調不通會出現各類問題,心煩意亂。json

若是你會使用Yeoman腳手架工具的話,那麼對於上面的開發場景你就會多一個方案③,在使用方案③來初始化項目B的時候,你只須要動動手指在終端中輸入$ yo 生成器名稱再使用交互方式簡單配置某些特定值,初始化的工做就完成了。這就是Yeoman的價值所在,初始化項目的時候你沒必要再把本身沉入到瑣碎重複無技術成長的費力工做中,也沒必要老是像個機器人般進入到拷貝-粘貼-修改這樣無止境的循環中。腳手架工具是那麼的簡單直接和高效,你甚至能夠省出點加班的時間來看世界盃了 : )bootstrap

我知道有一些槓精要出來噴了。「解決這種初始化問題不用搞的這麼複雜,我徹底能夠把項目結構和固定不變的部分抽取出來託管到gitHub倉庫,要初始化項目的時候 $ git clone一下不就行了嗎?」

說的頗有道理,可是clone下來的倉庫雖然結構和必要文件已經準備好了,但不少文件是否是還得修改?那你會頂回來「難道使用Yeoman初始化就不須要修改了嗎?」固然也要修改,不過就算是修改那改起來也頗有趣味還So快!

Yeoman使用交互式的方式來對項目文件中須要靈活處理的部分進行配置,這部份內容咱們稱爲組裝指令,具體再文章的後面會進行講解。

另外,若是新項目的總體結構以及技術選型和已有的項目很不同,那你抽取後交由git管理的倉庫就沒用了,由於八字不合啊。使用Yeoman就沒用這樣的顧慮,在Yeoman-generator列表有好幾千現成的generator供你選擇,總有一款適合你!!!

 

我要求太太…過高,實在誰也看不上?不要緊,generator這傢伙還能夠私人訂製,你徹底能夠根據本身的需求來定製須要的generator,你一高興甚至還能把它發佈到社區造福全人類。

Yeoman-generator的內部結構

搞清楚 generator的價值所在和應用場景以後,咱們就能夠開始談論generator相關的話題了,前面介紹過Yeoman腳手架工具的做用是幫助咱們依據特定的技術棧需求來初始化項目,在安裝了yo工具以後,只須要在終端中使用相似$ yo generator--xx的命令先安裝對應的generator而後再$ yo xx搭建便可。至於如何找到匹配當前技術選型的generator,能夠去官網的generator列表搜索,這些生成器中有很大一部分來自於對應框架的做者或者Yeoman官方團隊,質量有保證且更新很及時。固然,咱們也能夠建立本身的generator併發布。關於如何建立本身的generator,咱們放到另外一篇文章Yeoman腳手架生成器建立來解決。

簡單說Yeoman作的工做其實就是根據當前的生成器(generator)來複制固定的項目模板文件到新項目中,而新項目中的某些文件須要配置,這部分工做由安裝時候的交互式指令來完成(至關於傳遞參數給模板文件)。

須要注意的是,Yeoman的設計僅僅只提供了一小部分核心的API,而真正繁重的初始化工做是交給每一個具體的generator來完成的。

generator主要由組裝指令項目模板兩部分組成。

組裝指令

Yeoman generator中的generators/app/index.js文件是整個生成器的核心部分,該文件用於告知Yeoman該如何來組織並搭建項目,咱們能夠在該文件中設置初始化項目時必要的安裝提示和選項來讓用戶選擇,以及每一個文件應該如何複製和修改,是否須要加載依賴和Node包等內容。

項目模板

項目模板包括初始化項目須要的全部必須文件。這些文件又能夠簡單的劃分爲固定文件靈活文件可選文件依賴文件。所謂固定文件就是在每一個初始項目中都如出一轍的文件,譬如index.js、style.css等文件,在具體處理的時候這些文件只須要簡單複製便可。靈活文件指的是那些須要根據用戶選擇來作簡單修改而後才能複製的文件,譬如index.html文件(title等信息需根據用戶輸入來指定)。對於可選文件來講,它們並非必須的,譬如某些基礎框架有的項目中須要,有的項目中也許並不須要,這部分文件的處理方式須要交給用戶來決定

項目模板文件的類別

前面已經介紹過了Yeoman生成器的組成部分主要是組裝指令和項目模板。對於整個Yeman腳手架工具來講,項目模板這部分就至關因而搭建腳手架須要用到的原材料,而組裝指令用來決定和控制全部的具體行動是什麼。

如今咱們開始深刻的來討論項目模板這部份內容,須要先明白的是「可以知足全部需求的萬能的項目模板是不存在的」。由於這世界上每一個項目組,每一個產品甚至每一個人的需求(要求)都各有不一樣。因此,在實踐中你必需要對當前項目的需求和採用的技術棧有深刻的理解,這樣你才能知道目標項目的目錄結構會是什麼樣的? 哪些文件是必不可少的。

若是你的項目和採用的技術棧比較大衆化,那麼搜索一個合適的generator基本就能知足需求,拿來主義便可。若是你的項目無論結構仍是所採用的技術看上去都那麼的非凡和特別,那麼就多花一點點時間建立個本身的generator吧,若是你須要處理多個這樣的項目,那就更應該了。在建立或者理解generator的時候,咱們能夠根據前面對項目模板文件的劃分狀況來區別對待不一樣的文件。

 

固定文件

固定文件是在每一個項目中初始內容都同樣的必要文件。

好比咱們可能老是會把代碼的結構劃分爲srcbuilddist三個目錄,在src目錄下面擁有js、css和lib文件目錄,index.js和style.css等文件。這些文件都是必要的,剛開始的時候多是空的或者只有幾行簡單的代碼。這些文件的特色是,在使用組裝指令操做(一般是複製-移動)這些文件的時候,不須要對它們進行任何的修改。

 

靈活文件

靈活文件和固定文件差很少,也是初始化項目所必須的,但不一樣的項目中這些文件的內容也會稍有不一樣,這些不一樣之處可能很細微(好比僅僅是名字、協議這些),也可能差別巨大。好比,咱們經常使用的構建工做流中的bower.jsonpackage.json文件,它們是必不可少的,可是它們都須要當前項目的項目名稱和協議等信息才能正常工做。像這樣的靈活文件還有index.html,在這個文件中的title標籤中應該使用當前項目的名稱。

靈活文件中的部份內容須要在安裝該生成器的時候,由用戶交互式配置輸入的信息來進行設定。

 

可選文件

可選文件並非搭建初始化項目時所必須的文件,若是沒有那麼不要緊,若是有那彷佛更好。這些通常在用戶交互式配置的時候,以是否題的方式交由用戶決定,譬如是否使用less 是否安裝Bootstrap等。

 

依賴文件

依賴文件指的是某些經常使用的框架、插件或者是Node模塊,這些文件並不須要你在項目模板文件中提供,而後經過組裝指令去一個個複製。由於基本上成熟的項目中都會使用既定的工做流(主要包括依賴和包的下載、項目的自動化構建等),因此咱們徹底只須要在package.json或者bower.json等文件中設置好依賴便可,而後在組裝指令的相關代碼中經過this.installDependencies()相似的代碼來調用npm或者是bower執行install命令便可。

Yeoman腳手架運轉的核心機制

當您爲項目準備好(搜索或本身建立)合適的generator以後,就能夠用它們來搭建項目了。generator的執行須要在終端中使用yo命令來操做。yo是Yeoman的核心命令,主要用來鏈接生成器和項目結構。咱們能夠把yo命令理解爲generator的執行器,它知道怎麼找到對應的generator,也知道該如何執行它們。

注意:yo基於NodeJS且須要在任何文件目錄中使用,因此在安裝yo命令的時候應該使用-g來進行全局安裝。安裝過程請參考: Yeoman腳手架使用入門

在使用yo命令行工具和生成器來初始化項目以前,須要先把指定的生成器(generator)下載安裝到本地(若是是本身建立的生成器,那麼能夠經過$ npm link命令以軟鏈接的方式生成一個全局的npm包,個人是mac OSX系統,生成的npm包會保存在/usr/local/lib/node_modules/路徑,若是使用的是別人發佈的generator,那麼請使用$ npm install -g generator-xxx的方式來安裝)。

這裏須要注意的是yo命令行工具主要負責前期工做,在使用的時候它主要檢查當前安裝的generator有哪些,指定的generator是否可以正常工做,若是能,那麼它就會調用generator的組裝指令,把剩下部分的工做交接給generator來完成。generator接管項目的組裝流程以後,會按app/index.js中的要求來處理文件的複製等工做

下面給出腳手架工具初始化項目時的核心流程。

這裏對yo的主要命令進行簡單說明

$ yo 執行該命令的時候,yo會搜索並列出全部本地可用的生成器
$ yo 生成器名稱 好比對於generator-typescript生成器,那麼執行的命令就是$ yo typescript。該命令會先檢查enerator-typescript生成器是否可用。若是可用,那麼就接着以 ①交互式配置 ② 寫入文件 ③ 下載安裝依賴的順序來執行組裝指令。

Yeoman的主要組裝流程

組裝指令是用來讓Yeoman建立項目所需文件的一系列具體的命令(代碼)。典型的組裝流程分爲三個步驟:

① 交互式配置。這個步驟經過向用戶提問或直接輸入配置信息來完成模板傳參。
② 寫入文件。把項目模板中的指定文件複製到新項目的指定目錄中。
③ 安裝依賴。下載並安裝全部保存在bower.json和package.json文件中的依賴和Node模塊。

① 交互式配置

Yeoman在執行生成器的時候,首先會執行安裝提示以交互式的方式來詢問用戶,目的是爲了獲取生成器所須要的一些參數,好比項目的名稱、做者、使用的開原協議以及是否安裝和使用某些組件等。

這部分功能,須要使用到inquirer包,這個包的做用是生成選項來讓用戶選擇。下面給出代碼示例:

prompting() {
const prompts = [
{
type : 'input',
name : 'appName',
message : '請輸入項目名稱:',
default : this.appname //appname是內置對象,表明工程名,這裏就是ys
},
{
type : 'input',
name : 'appAuthor',
message : '請輸入做者姓名:',
default : '文頂頂'
},
{
type: 'list',
name: 'appLicense',
message: '請選擇使用的license:',
choices: ['MIT', 'ISC', 'Apache-2.0', 'AGPL-3.0']
},
{
type : 'confirm',
name : 'isIncludeBootstrap',
message : '是否須要使用bootStrap框架?',
default : false
},
 
];
return this.prompt(prompts).then(props => {
// To access props later use this.props.someAnswer;
this.props = props;
}); 

咱們能夠看到在代碼中,這些交互式配置都由prompts來進行維護,prompts是一個對象數組,數組中的每一個元素對象就表明着一個具體的安裝提示,在使用yo命令運行該生成器的時候,它的執行狀況以下:

_-----_ ╭──────────────────────────╮
| | │ 歡迎使用 │
|--(o)--| │ generator-wen! │
`---------´ │ Author:文頂頂 │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
 
? 請輸入項目名稱: wendingdingTest
? 請輸入做者姓名: 文頂頂
? 請選擇使用的license: Apache-2.0
? 是否須要使用bootStrap框架? (y/N) yes

 

prompts中的每一個對象元素就表明着一個安裝提示,上面代碼一共提供了四個安裝提示。每一個對象中的type屬性用於代表交互的類型,其中輸入項目名稱和做者姓名是input型的,表示接收用戶的輸入,至關於填空題。選擇使用的license是list型的,它提供了多個選項供用戶選擇,您能夠認爲這種類型是單選題。是否須要使用bootStrap框架是confirm型的,默認爲false,若是須要安裝那麼須要輸入YES,這至關因而非題。 

交互式配置這部分能夠根據項目的實際狀況來設置prompts中的對象元素,除上面介紹的這些類型外,您還能夠經過查看 inquirer.js的文檔來獲取更多內容。

交互式配置過程當中用戶作出的全部選擇和輸入都會被保存到this.props對象中,能夠經過訪問this.props.isIncludeBootstrap屬性來肯定是否須要安裝Bootstrap。

message屬性保存是每一條安裝提示的提示信息。
name屬性是最重要的屬性之一,它做爲key用來訪問用戶的選擇結果。
default屬性保存的是默認值,即當用戶跳過當前安裝提示的時候,name對應的value值將使用default中保存的默認值來設置。

② 寫入文件

寫入文件這個過程會把項目模板複製到指定的目錄中,若是是固定文件那麼就直接拷貝,若是是靈活文件那麼還須要把某些參數傳遞給指定的模板文件。這個過程在代碼中由writing() 函數體現,另外系統還提供了兩個函數(fs.copyTpl和fs.copy)用來執行具體的操做。

writing() {
mkdirp("build"); //建立build文件目錄
mkdirp("dist"); //建立dist文件目錄
mkdirp("src/template"); //建立src/template文件目錄
 
//傳遞參數this.props.appName渲染index.html文件
//把項目模板中的index.html文件複製到新項目的src路徑下
this.fs.copyTpl(
this.templatePath('index.html'),
this.destinationPath('src/index.html'),
{appName: this.props.appName}
);
 
//把項目模板中的style.css文件複製到新項目的src/css路徑下
this.fs.copy(
this.templatePath('css/style.css'),
this.destinationPath('src/css/style.css')
);
 
//......
}

fs.copy方法會把指定文件複製到目標路徑。
fs.copyTpl方法會先傳遞參數給模板文件,通過模板引擎處理後再進行復制。

③ 下載和安裝依賴

這個階段作的事情很是簡單,就是調用npm或者是bower來下載並安裝依賴和相關的node模塊。Yeoman提供了幾個對應的方法來處理這個過程。

this.npmInstall()
使用Npm來安裝package.json中的依賴和模塊,至關於在終端中輸入$ npm install指令。

this.bowerInstall()
使用Bower來安裝bower.json中的依賴和模塊,至關於在終端中輸入$ bower install指令。

this.installDependencies()
調用Bower和Npm而且安裝package.json和bower.json中依賴的全部模塊,至關於前後調用了npmInstall和bowerInstall方法。

最後,爲了幫助更好的理解Yeoman組裝流程的三個階段,給出下面的示意圖。

相關文章
相關標籤/搜索