Vue-Cli 專案基礎搭建

Ethan_Ceng發表於2019-05-06

寫在開頭的開頭

目標搭建一個Vue Cli 中後臺專案的基礎。一步一步搭建,希望能有所收益。
學習的時候,希望多翻閱文件,資料地址也會引入到原文
後臺可能是這樣的(參考 AdminLTE)

Vue-Cli 專案基礎搭建

主要包含

  • 側邊選單 aside
  • 右側 container
    • 頭部 header
    • 主體 main。頁面主要變化的部分

資料

將要做什麼

@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

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

請求攔截器 Axios.interceptors.request

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

響應攔截器 Axios.interceptors.interceptors

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

axios可配置

import axios from "axios";
import qs from "qs";
import { Message } from "element-ui";
import router from "../router";

const Axios = axios.create({
  baseURL: "/", // 因為我本地做了反向代理
  timeout: 10000,
  responseType: "json",
  withCredentials: true, // 是否允許帶cookie這些
  headers: {
    "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
  }
});

//POST傳參序列化(新增請求攔截器)
Axios.interceptors.request.use(
  config => {
    // 在傳送請求之前做某件事
    if (
      config.method === "post"
    ) {
      // 序列化 若是能直接接受json 格式,可以不用 qs 來序列化的
      config.data = qs.stringify(config.data);
    }

    // 若是有做鑑權token , 就給頭部帶上token
    // 若是需要跨站點,存放到 cookie 會好一點,限制也沒那麼多,有些瀏覽環境限制了 localstorage 的使用
    // 這裡localStorage一般是請求成功後我們自行寫入到本地的,因為你放在vuex重新整理就沒了
    // 一些必要的資料寫入本地,優先從本地讀取
    if (localStorage.token) {
      config.headers.Authorization = localStorage.token;
    }
    return config;
  },
  error => {
    // error 錯誤處理
    Message({
      //  餓了麼的訊息彈窗元件,類似toast
      showClose: true,
      message: error && error.data.error.message,
      type: 'error'
    });
    return Promise.reject(error.data.error.message);
  }
);

//返回狀態判斷(新增響應攔截器)
Axios.interceptors.response.use(
  res => {
    //對響應資料做些事
    if (res.data && !res.data.success) {
      Message({
        //  餓了麼的訊息彈窗元件,類似toast
        showClose: true,
        message: res.data.error.message.message
          ? res.data.error.message.message
          : res.data.error.message,
        type: "error"
      });
      return Promise.reject(res.data.error.message);
    }
    return res;
  },
  error => {
    // 使用者登入的時候會拿到一個基礎資訊,比如使用者名稱,token,過期時間戳
    // 直接丟localStorage或者sessionStorage
    if (!window.localStorage.getItem("loginUserBaseInfo")) {
      // 若是介面訪問的時候沒有發現有鑑權的基礎資訊,直接返回登入頁
      router.push({
        path: "/login"
      });
    } else {
      // 若是有基礎資訊的情況下,判斷時間戳和當前的時間,若是當前的時間大於伺服器過期的時間
      // 乖乖的返回去登入頁重新登入
      let lifeTime =
        JSON.parse(window.localStorage.getItem("loginUserBaseInfo")).lifeTime *
        1000;
      let nowTime = new Date().getTime(); // 當前時間的時間戳
      console.log(nowTime, lifeTime);
      console.log(nowTime > lifeTime);
      if (nowTime > lifeTime) {
        Message({
          showClose: true,
          message: "登入狀態資訊過期,請重新登入",
          type: "error"
        });
        router.push({
          path: "/login"
        });
      } else {
        // 下面是介面回撥的satus ,因為我做了一些錯誤頁面,所以都會指向對應的報錯頁面
        if (error.response.status === 403) {
          router.push({
            path: "/error/403"
          });
        }
        if (error.response.status === 500) {
          router.push({
            path: "/error/500"
          });
        }
        if (error.response.status === 502) {
          router.push({
            path: "/error/502"
          });
        }
        if (error.response.status === 404) {
          router.push({
            path: "/error/404"
          });
        }
      }
    }
    // 返回 response 裡的錯誤資訊
    let errorInfo =  error.data.error ? error.data.error.message : error.data;
    return Promise.reject(errorInfo);
  }
);

export default Axios

複製程式碼

Vuex 資料管理

面試通常都會被問到,資料通訊的問題,跨元件之間如何實現資料管理。當然方法不止 vuex ,本地儲存Local Storage,Cookies 也可以實現。專案小的時候,可以不使用vuex,專案比較簡單時,store 都在一個檔案中,或者 getter,actions,mutations,mutations-types,state拆分。應用比較大的時候,可以按模組拆分。

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 在路由守衛中,可以判斷使用者登入情況,鑑權,
})
複製程式碼

側邊選單欄配置

使用者登入後,獲取使用者許可權,比對 routers 提交一份資料到 vuex 根據使用者許可權更新資料,渲染選單欄目


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中新增新命令
"analyz": "npm_config_report=true npm run build"
複製程式碼

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

相關文章