如何使用 vue-cli 3 的 preset 打造基於 git repo 的前端項目模板

vue-cli 之 Presetcss

vue-cli 插件開發指南html

TLDR前端

背景介紹

vue-cli 3 徹底推翻了 vue-cli 2 的總體架構設計,因此當你須要給組裏定製一份基於 vue-cli 的前端項目初始化模板時,就須要去思考:我該怎麼作?vue

咱們要作的事情很簡單,就是當別人使用 vue create xxx 命令初始化一個前端項目時,能夠從 git repo 去拉取項目初始化信息,好處有兩點:ios

  1. 團隊內部全部的新項目都是統一的目錄結構代碼組織方式,便於維護
  2. 後期能夠開發公共插件服務於不一樣的項目,提升效率

由於 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 後的地址):

clipboard.png

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?

你的回答會直接影響後面初始化生成的項目文件。

這裏最須要注意一點!!!

當你查看官方文檔時,第一眼看到就是下圖:

clipboard.png

只要你這樣寫,就必定會 報錯 !!!

緣由很簡單:上圖中 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 pluginGeneratorAPI.js 源碼

對於 api.render 須要注意幾點:

  1. 拷貝目錄的話,直接傳地址字符串,render 函數會將你所傳目錄內的全部文件覆蓋初始化項目中 src 目錄下的文件(個人測試結果是限於兩層目錄);
  2. 拷貝文件的話,直接傳入一個 object,其中 key 對應初始化項目中的目標位置,value 對應模板項目中的文件位置;
  3. 當你須要建立一個以 . 開頭的文件時,模板項目中須要用 _ 替代 .,這點官網有說明;

clipboard.png

最後再說個很重要點,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.vuexoptions.elementUI 就是用戶在處理 prompts.js 中設定的問題的回答值。正是基於這點,我沒有再去使用 api.postProcessFiles 這個 api 。

今天就寫到這裏,後續有補充再寫~

相關文章
相關標籤/搜索