Vue-Cli 專案基礎搭建

Ethan_Ceng發表於2019-05-06

寫在開頭的開頭

目標搭建一個Vue Cli 中後臺專案的基礎。一步一步搭建,眾多知識點已經有很多文字,這裡會綜合比較多的連線。接觸的點會多,但是篇幅,不希望太大。
學習的時候,希望多翻閱文件,資料地址也會引入到原文

資料

後臺可能是這樣的以 iview-admin 為栗子線上 Demo

Vue-Cli 專案基礎搭建

拆解(結合將要做的做一個iView 拆解)

  • 側邊欄選單許可權過濾,這部分實現需要配合路由,許可權資料儲存,跨元件通訊(iview 使用了vuex)
  • 標籤頁,這部分也需要吧開啟的頁面使用資料存起來,也搭配 keep-alive 附錄中的 VUE 9個效能優化祕密?(vue-9-perf-secrets) 其中之一優化辦法就是 keep-alive

將要做什麼

@vue/cli 建立專案

開發環境:
+ Win10 x64
+ node v10.15.3
+ npm v6.4.1
+ @vue/cli 3.6.3
複製程式碼
vue create project-name
複製程式碼

縮減篇幅,省略具體建立過程。

  1. step.1 選擇設定,預設設定或者自定義Manually
  1. step.2 自定義配置,有 TypeScript支援,也有PWA。
  1. step.3 路由模式選擇 history
  1. step.4 CSS 編譯器選擇
  1. step.5 ESLint 以及配置選擇
  1. step.6 何時檢查 Lint
  1. step.7 ESLint 配置檔案寫在哪裡,可以單獨檔案,也可以在package.json
  1. step.8 是否儲存配置資訊,下次專案使用 N
    Vue-Cli 專案基礎搭建
  2. 自動安裝依賴
    Vue-Cli 專案基礎搭建

目錄規劃

.
├── build  專案構建配置
├── public  打包所需靜態資源
└── src
    ├── api  AJAX請求
    └── assets  專案靜態資源
        ├── icons  SVG 圖示資源
        ├── fonts  字型圖示資源
        └── images  圖片資源
    ├── components  業務元件
    ├── config  專案執行配置
    ├── directive  自定義指令
    ├── libs  封裝工具函式
    ├── router  路由配置
    ├── store  Vuex配置
    └── views  頁面檔案
複製程式碼

字型庫 && SVG

main.js 引入全域性 阿里 Ant 圖示字型庫

Vue-Cli 專案基礎搭建

SVG

圖示字型,也可以用SVG代替,方案可以做一個SVG元件,通過名字,載入不同的 SVG圖示,通過size,控制圖示大小,color,控制顏色即可


網路請求 axios封裝api

給axios做個挺靠譜的封裝(報錯,鑑權,跳轉,攔截,提示) iview-admin axios 用繼承封裝。當中亮點,對請求佇列做了處理,多次請求同一個地址,會節流。

// 安裝
npm i axios
複製程式碼
  • 統一捕獲介面報錯 : 用的axios內建的攔截器
  • 彈窗提示: 引入 Element UI的Message元件
  • 報錯重定向: 路由鉤子
  • 基礎鑑權: 服務端過期時間戳和token,還有藉助路由的鉤子
  • 客戶端支援防止 CSRF/XSRF
  • 表單序列化: 我這邊直接用qs(npm模組),你有時間也可以自己寫
  • 號外,對請求佇列優化,尤其是翻頁時多次請求。(未完成)

請求攔截器 Axios.interceptors.request

帶上自己需要的引數,比如CSRF/XSRF,基礎鑑權 token,請求時間戳
對請求資料做處理,轉表單,或轉Json
對錯誤的情況統一處理

響應攔截器 Axios.interceptors.interceptors

對響應結果統一處理,響應結果狀態status 判斷解封裝,錯誤處理等

axios可配置

iview-admin libs/axios.js

import axios from 'axios'
import store from '@/store'
// import { Spin } from 'iview'
const addErrorLog = errorInfo => {
  const { statusText, status, request: { responseURL } } = errorInfo
  let info = {
    type: 'ajax',
    code: status,
    mes: statusText,
    url: responseURL
  }
  if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
}

class HttpRequest {
  constructor (baseUrl = baseURL) {
    this.baseUrl = baseUrl
    this.queue = {}
  }
  getInsideConfig () {
    const config = {
      baseURL: this.baseUrl,
      headers: {
        //
      }
    }
    return config
  }
  destroy (url) {
    delete this.queue[url]
    if (!Object.keys(this.queue).length) {
      // Spin.hide()
    }
  }
  interceptors (instance, url) {
    // 請求攔截
    instance.interceptors.request.use(config => {
      // 新增全域性的loading...
      if (!Object.keys(this.queue).length) {
        // Spin.show() // 不建議開啟,因為介面不友好
      }
      this.queue[url] = true
      return config
    }, error => {
      return Promise.reject(error)
    })
    // 響應攔截
    instance.interceptors.response.use(res => {
      this.destroy(url)
      const { data, status } = res
      return { data, status }
    }, error => {
      this.destroy(url)
      let errorInfo = error.response
      if (!errorInfo) {
        const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
        errorInfo = {
          statusText,
          status,
          request: { responseURL: config.url }
        }
      }
      addErrorLog(errorInfo)
      return Promise.reject(error)
    })
  }
  request (options) {
    const instance = axios.create()
    options = Object.assign(this.getInsideConfig(), options)
    this.interceptors(instance, options.url)
    return instance(options)
  }
}
export default HttpRequest


複製程式碼

Vuex 資料管理

面試通常都會被問到,資料通訊的問題,跨元件之間如何實現資料管理。

當然方法不止 vuex ,

  • props
  • provide / inject
  • 本地儲存Local Storage,Cookies 也可以實現。
  • vuex,專案比較簡單時,store 都在一個檔案中,或者 getter,actions,mutations,mutations-types,state拆分。應用比較大的時候,可以按模組拆分。

擴充套件閱讀

沒有廢話的vue高階進階( 二 ) 8種元件通訊詳解

import Vue from 'vue'
import Vuex from 'vuex'
// 按模組拆分
import app from './module/app'
// 開啟 vuex logs
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
  state: {

  },
  mutations: {

  },
  actions: {

  },
  // 按模組引入
  modules: {
    app
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
複製程式碼

Vue Router. 做好路由守衛

包含的功能:

  • 巢狀的路由/檢視表
  • 模組化的、基於元件的路由配置
  • 路由引數、查詢、萬用字元
  • 基於 Vue.js 過渡系統的檢視過渡效果
  • 細粒度的導航控制
  • 帶有自動啟用的 CSS class 的連結
  • HTML5 歷史模式或 hash 模式,在 IE9 中自動降級
  • 自定義的滾動條行為

高階進階

  • 導航守衛
  • 路由元資訊
  • 過度動效
  • 資料獲取
  • 滾動行為
  • 路由懶載入

我們可以做什麼

  • 巢狀路由/檢視表,子路由 children 可以更好的組織頁面
  • 路由引數,跳轉,傳參,匹配
  • 過渡效果,滾動行為
  • 導航守衛,許可權限定
  • 路由懶載入,結合 Vue 的非同步元件和 Webpack 的程式碼分割功能,輕鬆實現路由元件的懶載入
  • 判斷使用者是否已經登入,控制進入許可權頁面。
  • 定義路由的時候可以配置 meta 欄位,個性化定製一些功能
  • 等等

全域性前置守衛

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // todo 在路由守衛中,可以判斷使用者登入情況,鑑權,
})
複製程式碼

選單欄許可權過濾

iview-admin 中側邊選單欄許可權,是在 router meta增加一個欄位,

流程

  • vuex 搭配使用 vuex-persistedstate vuex 資料持久化
  • 1.使用者登入後,獲取使用者許可權,許可權列表(列表必須能和,router meta 欄位對比)
  • 2.提交使用者資料,許可權等到 Vuex(資料中心)
  • 3.使用者許可權和 router meta 生成許可權列表,提交到vuex
  • 4.選單欄頁面,getter 到資料變化,更新選單欄
  • 5.注意:思考是否需要,資料需要本地化一份,在使用者重新整理頁面,或者vuex(資料中心)資料丟失時,還要能拿到使用者許可權,token等資料。

vue.config.js

Vue CLI.

調整 webpack 配置最簡單的方式就是在 vue.config.js 中的 configureWebpack 選項提供一個物件:

// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  }
}
複製程式碼

該物件將會被 webpack-merge 合併入最終的 webpack 配置。

文件中,提及鏈式操作 (高階)、修改 Loader 選項、替換Loader、新建Loader、修改外掛,等等。

環境變數和模式

NODE_ENV
如果在環境中有預設的 NODE_ENV,你應該移除它或在執行 vue-cli-service 命令的時候明確地設定 NODE_ENV。

模式

模式是 Vue CLI 專案中一個重要的概念。預設情況下,一個 Vue CLI 專案有三個模式:

  • development 模式用於 vue-cli-service serve
  • production 模式用於 vue-cli-service buildvue-cli-service test:e2e
  • test 模式用於 vue-cli-service test:unit

注意模式不同於 NODE_ENV,一個模式可以包含多個環境變數。也就是說,每個模式都會將 NODE_ENV 的值設定為模式的名稱——比如在 development 模式下 NODE_ENV 的值會被設定為 "development"

你可以通過為 .env 檔案增加字尾來設定某個模式下特有的環境變數。比如,如果你在專案根目錄建立一個名為 .env.development 的檔案,那麼在這個檔案裡宣告過的變數就只會在 development 模式下被載入。

你可以通過傳遞 --mode 選項引數為命令列覆寫預設的模式。例如,如果你想要在構建命令中使用開發環境變數,請在你的 package.json 指令碼中加入:

"dev-build": "vue-cli-service build --mode development",
複製程式碼

在客戶端側程式碼中使用環境變數

只有以 VUE_APP_ 開頭的變數會被 webpack.DefinePlugin 靜態嵌入到客戶端側的包中。你可以在應用的程式碼中這樣訪問它們:

console.log(process.env.VUE_APP_SECRET)
複製程式碼

vue.config.js

  • 有了 NODE_ENV 可以對不同環境做出不同的配置
  • 資料夾別名 resolve.alias
  • 設定代理 devServer,解決跨域開發問題
const path = require('path')
// Webpack包檔案分析器
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

function resolve (dir) {
  return path.join(__dirname, './', dir)
}

// 專案部署基礎 (webpack 的 devServer 地址)
// process.env.NODE_ENV
// 正式環境 production
// 開發環境 development
// 預設情況下,我們假設你的應用將被部署在域的根目錄下,
// 例如:https://www.my-app.com/
// 預設:'/'
// 如果您的應用程式部署在子路徑中,則需要在這指定子路徑
// 例如:https://www.foobar.com/my-app/
// 需要將它改為'/my-app/'
const BASE_URL = process.env.NODE_ENV === 'production'
  ? '/my-app/'
  : '/'

module.exports = {
  // 這裡是對環境的配置,不同環境對應不同的BASE_API,以便 axios 的請求地址不同 baseUrl 從 Vue CLI 3.3 起已棄用,請使用publicPath
  publicPath: BASE_URL,
  // tweak internal webpack configuration.
  // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
  // 如果你不需要使用eslint,把lintOnSave設為false即可
  lintOnSave: false,

  /**
   * 對內部的 webpack 配置進行更細粒度的修改
   * https://github.com/neutrinojs/webpack-chain see
   * https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
   * @param config
   */
  chainWebpack: (config) => {
    // key,value自行定義,比如.set('@@', resolve('src/components'))
    config.resolve.alias
      .set('@', resolve('src'))
      .set('api', resolve('src/api'))
      .set('common', resolve('src/common'))
      .set('components', resolve('src/components'))
  },
  /**
   * 調整 webpack 配置
   * https://cli.vuejs.org/zh/guide/webpack.html#%E7%AE%80%E5%8D%95%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F
   * @param config
   */
  configureWebpack: config => {
    // 生產and測試環境
    let pluginsPro = [
      // Webpack包檔案分析器(https://github.com/webpack-contrib/webpack-bundle-analyzer)
      // new BundleAnalyzerPlugin()
    ]
    // 開發環境
    let pluginsDev = []
    if (process.env.NODE_ENV === 'production') {
      // 為生產環境修改配置... process.env.NODE_ENV !== 'development'
      config.plugins = [...config.plugins, ...pluginsPro]
    } else {
      // 為開發環境修改配置...
      config.plugins = [...config.plugins, ...pluginsDev]
    }
  },
  // 打包時不生成.map檔案
  productionSourceMap: false,
  // webpack-dev-server 相關配置 https://webpack.js.org/configuration/dev-server/
  // 這裡寫你呼叫介面的基礎路徑,來解決跨域,如果設定了代理,那你本地開發環境的axios的baseUrl要寫為 '' ,即空字串
  // devServer: {
  //   proxy: 'localhost:3000'
  // }
  devServer: {
    // host: 'localhost',
    host: '0.0.0.0',
    port: 8000, // 埠號
    https: false, // https:{type:Boolean}
    open: true, // 配置自動啟動瀏覽器
    hotOnly: true, // 熱更新
    // 配置跨域處理,只有一個代理
    proxy: {
      '/my-app/*': {
        target: 'http://xxx.xxx.xxx.xxx:xxxx/',
        changeOrigin: true,
        pathRewrite: {
          '^/my-app': ''
        }
      },
      '/SocketWeb/*': {
        target: 'http://xxx.xxx.xxx.xxx:xxxx',
        changeOrigin: true,
        // websocket支援
        ws: true,
        secure: false
      }
    }
  }
}

複製程式碼
開發基礎環境可以了,開發中遇到的資料夾別名,請求跨域的問題解決了,自定義配置,也可以更具自己公司的情況配置。還有比較自定義的部分可以參照文件配置。

webpack-bundle-analyzer

安裝

$ npm intall webpack-bundle-analyzer --save-dev
複製程式碼
  1. 配置vue.config.js 開啟註釋 webpack-bundle-analyzer 的部分。
  2. 在script中新增
// 在執行 build 時,後臺面新增  --report
npm run build --report
// 或者在script中新增新命令
"analyze": "npm_config_report=true npm run build"
複製程式碼

VUE 9個效能優化祕密?(vue-9-perf-secrets)

相關文章