vue-cli 插件開發指南html
TLDR前端
背景介紹
vue-cli 3 徹底推翻了 vue-cli 2 的總體架構設計,因此當你須要給組裏定製一份基於 vue-cli 的前端項目初始化模板時,就須要去思考:我該怎麼作?vue
咱們要作的事情很簡單,就是當別人使用 vue create xxx
命令初始化一個前端項目時,能夠從 git repo 去拉取項目初始化信息,好處有兩點:ios
- 團隊內部全部的新項目都是統一的目錄結構和代碼組織方式,便於維護
- 後期能夠開發公共插件服務於不一樣的項目,提升效率
由於 vue-cli 3 纔出來不久,因此探索的過程當中踩了不少坑,這裏就來總結下。git
總體設計
vue-cli 官網介紹到:github
你能夠經過發佈 git repo 將一個 preset 分享給其餘開發者。這個 repo 應該包含如下文件:vue-router
- preset.json: 包含 preset 數據的主要文件(必需)。
- generator.js: 一個能夠注入或是修改項目中文件的 Generator。
- prompts.js: 一個能夠經過命令行對話爲 generator 收集選項的 prompts 文件。
# 從 GitHub repo 使用 preset vue create --preset username/repo my-project
GitLab 和 BitBucket 也是支持的。若是要從私有 repo 獲取,請確保使用 --clone 選項:
vue create --preset gitlab:username/repo --clone my-project vue create --preset bitbucket:username/repo --clone my-project
是否是看上去很簡單,起碼我在實踐過程當中仍是遇到了一些問題,接下來就重點講下。vuex
git repo 參數vue-cli
上面 --preset
後跟的參數 username/repo
實際是下圖中的紅框內部分(千萬別覺得是 git clone
後的地址):
preset.json 文件
先說一點:當你直接用 vue create xxx
初始化項目時,若是你將初始化信息保存成一個本地模板後,會寫入到你係統的 ~/.vuerc
文件中。該文件中的內容其實就是咱們接下來須要配置的 present.json
。
此處直接 show code :
{ "useConfigFiles": true, "cssPreprocessor": "less", "plugins": { "@vue/cli-plugin-babel": { "version": "^3.0.0" }, "@vue/cli-plugin-eslint": { "version": "^3.0.0", "config": "recommended", "lintOn": ["save", "commit"] } }, "configs": { "vue": { "baseUrl": "/", "outputDir": "dist", "assetsDir": "static", "filenameHashing": true, "lintOnSave": true, "runtimeCompiler": false, "transpileDependencies": [], "productionSourceMap": false, "pages": { "index": { "entry": "src/main.js", "template": "public/index.html", "filename": "index.html", "title": "首頁", "chunks": ["chunk-vendors", "chunk-common", "index"] } }, "devServer": { "open": true, "host": "127.0.0.1", "https": false, "hotOnly": false, "proxy": null }, "pwa": {}, "pluginOptions": {} }, "postcss": {}, "eslintConfig": { } }, "router": true, "vuex": false, "routerHistoryMode": false }
其中當 "useConfigFiles": true
時, configs
內的配置信息會直接覆蓋初始化後項目中的 vue.config.js
。
prompts.js 文件
prompts.js 其實就是你在初始化項目時,系統會詢問你的配置選項問題,好比你的項目需不須要安裝 vuex
? 需不須要安裝 vue-router
?
你的回答會直接影響後面初始化生成的項目文件。
這裏最須要注意一點!!!
當你查看官方文檔時,第一眼看到就是下圖:
只要你這樣寫,就必定會 報錯 !!!
緣由很簡單:上圖中 prompts.js
的寫法是開發基於 vue-cli-service
插件的代碼。而當你是要開發項目模板時,正確寫法以下:
module.exports = [ { name: "vuex", type: "confirm", message: `是否須要使用 vuex`, default: false }, { name: "elementUI", type: "confirm", message: `element-ui`, default: false } ];
這一點其實官網也有提到,只是很不容易注意到。
此處再給你們安利下 vue-cli-plugin-vuetify 這個開源插件中 prompts.js
的寫法。程序猿嘛,最愛的就是栗子。
generator.js 文件
接下來就是 generator.js
,這個文件負責的就是 注入或是修改項目中文件。
一樣,我仍是直接 show code :
module.exports = (api, options, rootOptions) => { // 安裝一些基礎公共庫 api.extendPackage({ dependencies: { "axios": "^0.18.0", "lodash": "^4.17.10", "keymirror": "^0.1.1" }, devDependencies: { "mockjs": "^1.0.1-beta3" } }); // 安裝 vuex if (options.vuex) { api.extendPackage({ dependencies: { vuex: '^3.0.1' } }); api.render('./template/vuex'); } // 安裝 element-ui 庫 if (options.elementUI) { api.extendPackage({ devDependencies: { "element-ui": "^2.4.6" } }); } // 公共基礎目錄和文件 api.render('./template/default'); // 配置文件 api.render({ './.eslintrc.js' : './template/_eslintrc.js', './.gitignore' : './template/_gitignore', './.postcssrc.js' : './template/_postcssrc.js' }); }
核心 api:
-
api.extendPackage
: 負責給初始化項目中的package.json
添加額外依賴並安裝; -
api.render
: 負責將模板項目中提早定義好的目錄和文件拷貝到初始化的項目中; -
api.postProcessFiles
: 負責具體處理模板項目中的文件,關於它能夠參考 How to build your own vue-cli 3 plugin 和 GeneratorAPI.js 源碼
對於 api.render
須要注意幾點:
- 拷貝目錄的話,直接傳地址字符串,
render
函數會將你所傳目錄內的全部文件覆蓋初始化項目中src
目錄下的文件(個人測試結果是限於兩層目錄); - 拷貝文件的話,直接傳入一個
object
,其中key
對應初始化項目中的目標位置,value
對應模板項目中的文件位置; - 當你須要建立一個以
.
開頭的文件時,模板項目中須要用_
替代.
,這點官網有說明;
最後再說個很重要點,vue-cli 3 在拷貝文件時使用的是 EJS
模板去實現的,因此開發者是能夠在任意文件中使用 EJS
語法去作更細粒度的控制。好比個人 main.js
:
import Vue from 'vue' import App from './App.vue' <%_ if (options.vuex) { _%> import store from './store' <%_ } _%> <%_ if (options.elementUI) { _%> import ElementUI from 'element-ui'; Vue.use(ElementUI); <%_ } _%> // simulation data import './mock/index'; Vue.config.productionTip = false new Vue({ router, <%_ if (options.vuex) { _%> store, <%_ } _%> render: h => h(App) }).$mount('#app')
其中 options.vuex
和 options.elementUI
就是用戶在處理 prompts.js
中設定的問題的回答值。正是基於這點,我沒有再去使用 api.postProcessFiles
這個 api 。
今天就寫到這裏,後續有補充再寫~