衆所周知,使用 vue-cli
能夠快速初始化一個基於 Vue.js
的項目,官方提供了 webpack
、pwa
、browserify-simple
等經常使用 templates。html
當開發一個獨立項目的時候,使用官方提供的 template
確實很是方便,省去了繁瑣的依賴安裝配置、webpack
配置,甚至連項目結構也不用多加考慮。vue
可是,當咱們須要開發多個系統,每一個系統相對獨立但又有一些配置、依賴或邏輯相互通用的時候(例如集羣的多後臺系統),每次使用官方提供的 template
初始化項目以後,都須要進一步調整(添加依賴、修改配置、增長通用組件等等),這顯然是十分麻煩的。
本着懶惰是第一輩子產力的初衷,咱們須要定製一份本身的 template
,以便咱們...額...偷懶哈~node
在開始定製咱們本身的 Vue template
前,咱們須要瞭解一些前置知識:webpack
模板結構
首先咱們先來了解模板的主要結構,模板結構很簡單,主要包括兩個部分:git
Metalsmith
在渲染項目文件流程中角色至關於 gulp.js
,能夠經過添加一些插件對構建文件進行處理,如重命名、合併等。download-git-repo
使用 vue-cli
初始化項目時會使用該工具來下載目標倉庫。默認的 webpack
等模板直接下載 vue-templates
中對應的模板倉庫。
自定義的模板也能夠是一個 GitHub 倉庫,使用以下命令來初始化項目:github
vue init username/repo my-project
其中username
爲自定義模板倉庫所在的 GitHub 用戶或組織名,repo
爲倉庫名。
Inquirer.js
vue-cli
在模板倉庫下載完成後,將經過 Inquirer.js
根據模板倉庫中的 meta.js
或 meta.json
文件中的設置,與用戶進行一些簡單的交互以肯定項目的一些細節,以下圖:web
該交互配置是可選的,當項目中 沒有meta.js
或meta.json
文件時,模板倉庫下載完成後將直接進入模板構建階段。
vue-cli
選用的是 Handlebars.js
—— 一個簡單高效的語義化模板構建引擎。 畫了一張圖,更有助於理清這些依賴在 vue-cli
初始化項目時的相互關聯:vue-cli
定製模板主要圍繞着 命令行交互(Inquirer.js
)與 模板文件開發(Handlebars.js
)這兩部分。
因爲 meta.js
至關於模板項目的配置文件(雖然非必選),因此這裏先看看它主要能幹些啥。
設置都在 meta.js
或 meta.json
中配置,推薦使用 meta.js
,更靈活一些。如下也將以 meta.js
進行展開說明。
meta.js
一共可包含以下幾個字段,簡單列一下各字段功能:npm
helpers
: 自定義 Handlebars.js
的輔助函數prompts
: 基於 Inquirer.js
的命令行交互配置filters
: 根據命令行交互的結果過濾將要渲染的項目文件metalsmith
: 配置 Metalsmith
插件,文件會像 gulp.js
中的 pipe
同樣依次通過各個插件處理completeMessage
: 將模板渲染爲項目後,輸出一些提示信息,取值爲字符串complete
: 與 completeMessage
功能相同,二選其一,取值爲函數,函數最後需返回輸出的字符串 命令行交互主要是 meta.js
中 prompts
字段的配置,詳細的配置能夠閱讀 Inquirer.js
的 README.md,這裏說一下經常使用的交互配置:json
// meta.js module.export = { // ... "prompts": { "isCustomName": { "type" : "confirm", "message": "是否自定義系統名稱?", }, "sysName": { "type" : "input", "when" : "isCustomName", "default" : "默認系統名稱", "message" : "請輸入系統名稱:", "required": true, "validate": function (val) { if (!val) return '(✘) 請輸入系統名稱,該名稱將設爲 index.html 的 title'; return true; }, }, // ... }, }
字段說明:
isCustomName
與 sysName
: 交互字段名稱,可在後續條件交互或模板渲染時經過該字段讀取到交互結果 type
: 交互類型,有 input
, confirm
, list
, rawlist
, expand
, checkbox
, password
, editor
八種類型message
: 交互的提示信息when
: 進行該條件交互的先決條件,在該例子中,sysName
這個交互動做只在 isCustomName
交互結果爲真時纔會出現default
: 默認值,當用戶輸入爲空時,交互結果即爲此值required
: 默認爲 false
,該值是否爲必填項validate
: 輸入驗證函數注:示例中default
required
validate
三個字段存在邏輯問題,僅爲舉例方便放到一塊兒。
在模板編寫中,咱們能夠用 Mustache
語法在任何文本類型的文件中輸出在命令行交互中獲得的一些數據:
// dev.js export default { //... token: '{{token}}', //... };
<!-- index.html --> <!DOCTYPE html> <html> <head> <title>{{sysName}}</title> </head> <!-- ... --> </html>
以 {%raw%}{{xxx}}{%endraw%}
即爲一個 Mustache
句法標記。以上例子中 token
與 sysName
爲匹配命令行交互數據對應的鍵名。
對vue
有過了解的都知道,在模板標籤中直接輸出實例上的數據也是用的Mustache
語法。
若是定製vue template
模板時不對這些數據作相應處理,在最終輸出由模板初始化的項目時,這些與命令行交互獲得的數據沒法匹配的Mustache
句法標記會被移除。
此時咱們須要使用反斜槓\{%raw%}{{xxx}}{%endraw%}
或者{%raw%}{{{xxx}}}{%endraw%}
來跳過Handlebars
的處理,直接輸出{%raw%}{{xxx}}{%endraw%}
vue-cli
中爲 Handlebars
預置了 if_eq
與 unless_eq
輔助函數,用於使用交互所得數據來處理模板中是否渲染的兩種邏輯關係,此外 Handlebars
中還內置了 if
、unless
、each
等 輔助函數。
// sys.js export default { {{#if_eq projType 'admin'}} id: {{#if_eq sysId ''}}undefined{{else}}{{sysId}}{{/if_eq}}, {{/if_eq}} name: '{{sysName}}', };
如上,這裏用了 if_eq
輔助函數,projType
表明將要匹配的鍵,'admin'
表明將要匹配的值。這個鍵值來自於在命令行界面與用戶交互的操做結果。該栗子中,當命令行交互數據中 CLI[projType] == 'admin'
時,將在 sys.js
文件的導出數據中輸出 id
字段;id
的值來自一個嵌套的 if_eq
輔助函數,當 CLI[sysId] == ''
時,id
將被設置爲 undefined
不然 ({%raw%}{{else}}{%endraw%}
)輸出 CLI[sysId]
命令行交互所得數據中的 sysId
。
輔助函數使用語法:{%raw%}{{{%endraw%}#
+函數名
+ ' '(空格)+以空格分隔的參數列表
+}}
以空格分隔的參數列表:未用引號包裹的參數名將被將爲自動取值爲命令行交互結果中對應的數據
有時候現有的輔助函數可能不能知足咱們的需求,經過 mate.js
中的 helpers
字段咱們能夠自定義輔助函數:
// mate.js module.exports = { "helpers": { "neither": function (k, v1, v2, options) { if (k !== v1 && k !== v2) { return options.fn(this); } return options.inverse(this); }, }, //... }
輔助函數能夠接受若干的參數,最後一個參數 options
爲輔助函數的鉤子,調用 options.fn(this)
即輸出該輔助函數運算結果爲真時的內容,反之調用 options.inverse(this)
則輸出 {%raw%}{{else}}{%endraw%}
的內容(若是有的話)。
如今咱們能夠在模板中直接使用 neither
輔助函數了:
{{#neigher sysType 'admin' 'mobile'}} isAdmin = false isMobile = false {{else}} isAdminOrMobile = true {{/neigher}}
輔助函數只能夠控制文件內一部份內容的輸出與否,有時候咱們須要根據交互結果控制某些文件自己是否輸出。
在 mate.js
中的 filters
字段中進行相應的設置,就能夠達到控制文件輸出的效果:
module.exports = { //... "filters": { "project/config/test.env.js": "unit || e2e", "project/src/router/**/*": "router" }, //... }
filters
中鍵名是要控制輸出的文件的路徑,可以使用字面量,也可以使用 簡化的 glob 表達式。鍵名對應的值爲命令行交互中獲得的數據。
在模板項目比較複雜或是有特殊需求的時候,好比:
能夠經過 mate.js
中的 metalsmith
字段配置相關插件來實現豐富的文件操做:
var renamer = require('metalsmith-renamer') module.exports = { //... "metalsmith": function(metalsmith, opts, helpers) { metalsmith.use(renamer({ index: { pattern: 'project/**/+(Mobile|Admin)Index.vue', rename: function(fileName) { return 'Index.vue'; } }, config: { pattern: 'project/src/+(mobile|admin)Config.js', rename: 'config.js' }, //... })) }, //... }
以上是 metalsmith-renamer
插件的簡單使用,更多插件能夠在這裏查找
使用metalsmith
插件請注意:因爲vue-cli
在下載完成模板倉庫後並無npm install
安裝模板的項目依賴這一操做,因此在打包模板倉庫的時候也須要將依賴目錄node_modules
一同打包,metalsmith
的插件都很精簡,通常不會有什麼嵌套依賴。不過仍是建議在使用前查看一下插件的相關Github
倉庫。
關於 vue
項目模板的開發涉及到的問題差很少就介紹完了,爲本身或團隊開發一份專屬的 Vue Template
吧!
原文: 深度定製團隊本身的 Vue template