vue-element-admin(基礎篇)

原文鏈接:https://juejin.im/post/59097cd7a22b9d0065fb61d2
關注

手摸手,帶你用vue擼後臺 系列一(基礎篇)

完整項目地址:vue-element-admin

系列文章:

前言

說好的教程終於來了,第一篇文章主要來說一說在開始寫實際業務代碼之前的一些準備工作吧,但這裏不會教你 webpack 的基礎配置,熱更新原理是什麼,webpack速度優化等等,有需求的請自行 google,相關文章已經很多了。

目錄結構

├── build                      // 構建相關  
├── config                     // 配置相關
├── src                        // 源代碼
│   ├── api                    // 所有請求
│   ├── assets                 // 主題 字體等靜態資源
│   ├── components             // 全局公用組件
│   ├── directive              // 全局指令
│   ├── filtres                // 全局 filter
│   ├── icons                  // 項目所有 svg icons
│   ├── lang                   // 國際化 language
│   ├── mock                   // 項目mock 模擬數據
│   ├── router                 // 路由
│   ├── store                  // 全局 store管理
│   ├── styles                 // 全局樣式
│   ├── utils                  // 全局公用方法
│   ├── vendor                 // 公用vendor
│   ├── views                   // view
│   ├── App.vue                // 入口頁面
│   ├── main.js                // 入口 加載組件 初始化等
│   └── permission.js          // 權限管理
├── static                     // 第三方不打包資源
│   └── Tinymce                // 富文本
├── .babelrc                   // babel-loader 配置
├── eslintrc.js                // eslint 配置項
├── .gitignore                 // git 忽略項
├── favicon.ico                // favicon圖標
├── index.html                 // html模板
└── package.json               // package.json
複製代碼

這裏來簡單講一下src文件

api 和 views

簡單截取一下公司後臺項目,現在後臺大概有四五十個 api 模塊

如圖可見模塊有很多,而且隨着業務的迭代,模塊還會會越來越多。 所以這裏建議根據業務模塊來劃分 views,並且 將views 和 api 兩個模塊一一對應,從而方便維護。如下圖:

如 article 模塊下放的都是文章相關的 api,這樣不管項目怎麼累加,api和views的維護還是清晰的,當然也有一些全區公用的api模塊,如七牛upload,remoteSearch等等,這些單獨放置就行。

components

這裏的 components 放置的都是全局公用的一些組件,如上傳組件,富文本等等。一些頁面級的組件建議還是放在各自views文件下,方便管理。如圖:

store

這裏我個人建議不要爲了用 vuex 而用 vuex。就拿我司的後臺項目來說,它雖然比較龐大,幾十個業務模塊,幾十種權限,但業務之間的耦合度是很低的,文章模塊和評論模塊幾乎是倆個獨立的東西,所以根本沒有必要使用 vuex 來存儲data,每個頁面裏存放自己的 data 就行。當然有些數據還是需要用 vuex 來統一管理的,如登錄token,用戶信息,或者是一些全局個人偏好設置等,還是用vuex管理更加的方便,具體當然還是要結合自己的業務場景的。總之還是那句話,不要爲了用vuex而用vuex!


webpack

這裏是用 vue-cliwebpack-template 爲基礎模板構建的,如果你對這個有什麼疑惑請自行google,相關的配置紹其它的文章已經介詳細了,這裏就不再展開了。簡單說一些需要注意到地方。

jquery (本項目已移除)

管理後臺不同於前臺項目,會經常用到一些第三方插件,但有些插件是不得不依賴 jquery 的,如市面很多富文本基都是依賴 jquery 的,所以乾脆就直接引入到項目中省事(gzip之後只有34kb,而且常年from cache,不要考慮那些吹毛求疵的大小問題,這幾kb和提高的開發效率根本不能比)。但是如果第三方庫的代碼中出現.xxx或jQuery.xxx或window.jQuery或window.則會直接報錯。要達到類似的效果,則需要使用 webpack 內置的 ProvidePlugin 插件,配置很簡單,只需要

new webpack.ProvidePlugin({
  $: 'jquery' ,
  'jQuery': 'jquery'
})
複製代碼

這樣當 webpack 碰到 require 的第三方庫中出現全局的$、jQeury和window.jQuery 時,就會使用 node_module 下 jquery 包 export 出來的東西了。

alias

當項目逐漸變大之後,文件與文件直接的引用關係會很複雜,這時候就需要使用alias 了。 有的人喜歡alias 指向src目錄下,再使用相對路徑找文件

resolve: {
  alias: {
    '~': resolve(__dirname, 'src')
  }
}

//使用
import stickTop from ‘~/components/stickTop’
複製代碼

或者也可以

alias: {
  'src': path.resolve(__dirname, '../src'),
  'components': path.resolve(__dirname, '../src/components'),
  'api': path.resolve(__dirname, '../src/api'),
  'utils': path.resolve(__dirname, '../src/utils'),
  'store': path.resolve(__dirname, '../src/store'),
  'router': path.resolve(__dirname, '../src/router')
}

//使用
import stickTop from 'components/stickTop'
import getArticle from 'api/article'
複製代碼

沒有好與壞對與錯,純看個人喜好和團隊規範。


ESLint

不管是多人合作還是個人項目,代碼規範是很重要的。這樣做不僅可以很大程度地避免基本語法錯誤,也保證了代碼的可讀性。這所謂工欲善其事,必先利其器,個人推薦 eslint+vscode 來寫 vue,絕對有種飛一般的感覺。效果如圖:

eslintGif.gif
每次保存,vscode就能標紅不符合eslint規則的地方,同時還會做一些簡單的自我修正。安裝步驟如下:

首先安裝eslint插件

eslint1.png

安裝並配置完成 ESLint 後,我們繼續回到 VSCode 進行擴展設置,依次點擊 文件 > 首選項 > 設置 打開 VSCode 配置文件,添加如下配置


    "files.autoSave":"off",
    "eslint.validate": [
       "javascript",
       "javascriptreact",
       "html",
       { "language""vue""autoFix"true }
     ],
     "eslint.options": {
        "plugins": ["html"]
     }

複製代碼

這樣每次保存的時候就可以根據根目錄下.eslintrc.js你配置的eslint規則來檢查和做一些簡單的fix。這裏提供了一份我平時的eslint規則地址,都簡單寫上了註釋。每個人和團隊都有自己的代碼規範,統一就好了,去打造一份屬於自己的eslint 規則上傳到npm吧,如餓了麼團隊的 config,vue的 config

vscode 插件和配置推薦


封裝 axios

我們經常遇到一些線上 的bug,但測試環境很難模擬。其實可以通過簡單的配置就可以在本地調試線上環境。 這裏結合業務封裝了axios ,線上代碼

import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// 創建axios實例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 5000 // 請求超時時間
})

// request攔截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  if (store.getters.token) {
    config.headers['X-Token'] = getToken() // 讓每個請求攜帶token--['X-Token']爲自定義key 請根據實際情況自行修改
  }
  return config
}, error => {
  // Do something with request error
  console.log(error) // for debug
  Promise.reject(error)
})

// respone攔截器
service.interceptors.response.use(
  response => response,
  /**
  * 下面的註釋爲通過response自定義code來標示請求狀態,當code返回如下情況爲權限有問題,登出並返回到登錄頁
  * 如通過xmlhttprequest 狀態碼標識 邏輯可寫在下面error中
  */
  //  const res = response.data;
  //     if (res.code !== 20000) {
  //       Message({
  //         message: res.message,
  //         type: 'error',
  //         duration: 5 * 1000
  //       });
  //       // 50008:非法的token; 50012:其他客戶端登錄了;  50014:Token 過期了;
  //       if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
  //         MessageBox.confirm('你已被登出,可以取消繼續留在該頁面,或者重新登錄', '確定登出', {
  //           confirmButtonText: '重新登錄',
  //           cancelButtonText: '取消',
  //           type: 'warning'
  //         }).then(() => {
  //           store.dispatch('FedLogOut').then(() => {
  //             location.reload();// 爲了重新實例化vue-router對象 避免bug
  //           });
  //         })
  //       }
  //       return Promise.reject('error');
  //     } else {
  //       return response.data;
  //     }
  error => {
    console.log('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  })

export default service
import request from '@/utils/request'

//使用
export function getInfo(params) {
  return request({
    url: '/user/info',
    method: 'get',
    params
  });
}

比如後臺項目,每一個請求都是要帶 token 來驗證權限的,這樣封裝以下的話我們就不用每個請求都手動來塞 token,或者來做一些統一的異常處理,一勞永逸。 而且因爲我們的 api 是根據 env 環境變量動態切換的,如果以後線上出現了bug,我們只需配置一下 @/config/dev.env.js 再重啓一下服務,就能在本地模擬線上的環境了。

module.exports = {
    NODE_ENV: '"development"',
    BASE_API: '"https://api-dev"', //修改爲'"https://api-prod"'就行了
    APP_ORIGIN: '"https://wallstreetcn.com"' //爲公司打個廣告 pc站爲vue+ssr
}

媽媽再也不用擔心我調試線上bug了。
當然這裏只是簡單舉了個例子,axios還可以執行多個併發請求,攔截器什麼的,大家自行去研究吧。


多環境

vue-cli 默認只提供了devprod兩種環境。但其實正真的開發流程可能還會多一個sit或者stage環境,就是所謂的測試環境和預發佈環境。所以我們就要簡單的修改一下代碼。其實很簡單就是設置不同的環境變量

"build:prod": "NODE_ENV=production node build/build.js",
"build:sit": "NODE_ENV=sit node build/build.js",
複製代碼

之後在代碼裏自行判斷,想幹就幹啥

var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
複製代碼

新版的 vue-cli 也內置了 webpack-bundle-analyzer 一個模塊分析的東西,相當的好用。使用方法也很簡單,和之前一樣封裝一個 npm script 就可以。

//package.json
 "build:sit-preview": "cross-env NODE_ENV=production env_config=sit npm_config_preview=true  npm_config_report=true node build/build.js"

//之後通過process.env.npm_config_report來判斷是否來啓用webpack-bundle-analyzer

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())

效果圖

analyzer.png
webpack-bundle-analyzer這個插件還是很有用的,對後期的代碼優化什麼的,最重要的是它夠裝逼~


前後端交互

每個公司都有自己一套的開發流程,沒有絕對的好與壞。這裏我來講講我司的前後端交互流程。

跨域問題

首先前後端交互不可避免的就會遇到跨域問題,我司現在全是用 cors來解決的,如果你司後端嫌麻煩不肯配置的話,dev環境也可以通過 webpack-dev-serverproxy來解決,開發環境用nginx反代理一下就好了,具體配置這裏就不展開了。

前後端的交互問題

其實大家也知道,平時的開發中交流成本佔據了我們很大一部分時間,但前後端如果有一個好的協作方式的話能解決很多時間。我司開發流程都是前後端和產品一起開會討論項目,之後後端根據需求,首先定義數據格式和api,然後 mock api 生成好文檔,我們前端纔是對接接口的。這裏推薦一個文檔生成器 swaggerswagger是一個REST APIs文檔生成工具,可以在許多不同的平臺上從代碼註釋中自動生成,開源,支持大部分語言,社區好,總之就是一個強大,如下圖的api 文檔(swagger自動生成,ui忽略)

api 地址,需要傳是沒參數,需要的傳參類型,返回的數據格式什麼都一清二楚了。

前端自行mock

如果後端不肯來幫你 mock 數據的話,前端自己來 mock 也是很簡單的。你可以使用mock server 或者使用 mockjs + rap 也是很方便的。 不久前出的 easy-mock也相當的不錯,還能結合 swagger。 我們大前端終於不用再看後端的臉色了~

iconfont

element-ui 默認的icon不是很多,這裏要安利一波阿里的iconfont簡直是神器,不管是公司項目還是個人項目都在使用。它提供了png,ai,svg三種格式,同時使用也支持unicode,font-class,symbol三種方式。由於是管理後臺對兼容性要求不高,樓主平時都喜歡用symbol,曬一波我司後臺的圖標(都是樓主自己發揮的)。

iconfont.png
詳細具體的使用可以見文章 手摸手,帶你優雅的使用 icon


router-view

different router the same component vue。真實的業務場景中,這種情況很多。比如

router-view.png
我創建和編輯的頁面使用的是同一個component,默認情況下當這兩個頁面切換時並不會觸發vue的created或者mounted鉤子,官方說你可以通過watch $route的變化來做處理,但其實說真的還是蠻麻煩的。後來發現其實可以簡單的在 router-view上加上一個唯一的key,來保證路由切換時都會重新渲染觸發鉤子了。這樣簡單的多了。

<router-view :key="key"></router-view>

computed: {
    key() {
        return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date()
    }
 }

優化

有些人會覺得現在構建是不是有點慢,我司現在技術棧是容器服務,後臺項目會把dist文件夾裏的東西都會打包成一個docker鏡像,基本步驟爲

npm install
npm run build:prod
加打包鏡像,一共是耗時如下
複製代碼

Paste_Image.png

還是屬於能接受時間的範圍。 主站PC站基於nodejs、Vue實現服務端渲染,所以不僅需要依賴nodejs,而且需要利用pm2進行nodejs生命週期的管理。爲了加速線上鏡像構建的速度,我們利用taobao源 registry.npm.taobao.org 進行加速, 並且將一些常見的npm依賴打入了基礎鏡像,避免每次都需要重新下載。 這裏注意下 建議不要使用cnpm install或者update 它的包都是一個link,反正會有各種詭異的bug,這裏建議這樣使用

npm install --registry=https://registry.npm.taobao.org
複製代碼

如果你覺得慢還是有可優化的空間如使用webpack dll 或者把那些第三方vendor單獨打包 external出去,或者我司現在用的是http2 可以使用AggressiveSplittingPlugin等等,這裏有需求的可以自行優化。


佔坑

常規佔坑,這裏是手摸手,帶你用vue擼後臺系列。 完整項目地址:vue-element-admin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章