1. 程式人生 > 實用技巧 >Vue的前端架構

Vue的前端架構

1.分解需求

技術棧

  • 考慮到後續招人和現有人員的技術棧,選擇 Vue 作為框架。

  • 公司主要業務是 GIS 和 BIM,通常開發一些中大型的系統,所以 vue-router 和 vuex 都是必不可少的。

  • 放棄了 Element UI 選擇了 Ant Design Vue(最近 Element 好像復活了,麻蛋)。

  • 工具庫選擇 lodash。

建立腳手架

  • 搭建 NPM 私服。

  • 使用 Node 環境開發 CLI 工具,參考我自己寫過的一篇 -【 搭建自己的腳手架—“優雅”生成前端工程】。

  • 基於 @vue/cli 搭建基礎的模板(大家都比較瞭解,節省開發時間,遠勝於從零開始搭建)。

  • 根據業務需求定義各種開發中可能用到的功能(元件庫、狀態管理、過濾器、指令、CSS內建變數、CSS Mixins、表單驗證、工具函式等)。

  • 效能優化,例如對 Ant Design Vue 元件庫的優化。

開發規範

  • 對程式碼風格、命名規則、目錄結構進行統一規範。

  • 靜態資源的使用規範。

  • 單元測試、提交線上測試規範。

  • Git 提交記錄和多人協作規範。

2.樣式

CSS 前處理器的選擇

  • Sass/Scss ✅
  • Less ✅
  • Stylus ⭕

為什麼選擇了兩個?因為公司團隊跟傾向於使用 scss 開發,less 是為了覆蓋 ant design vue 的樣式,stylus 只有我自己喜歡這種風格。

區域性樣式與全域性樣式

區域性樣式

一般都是使用 scoped 方案:

<style lang="scss" scoped>
...
</style>

全域性樣式

全域性樣式 目錄:@/styles

variable.scss: 全域性變數管理 mixins.scss: 全域性 Mixins 管理 global.scss: 全域性樣式

其中 variable.scss 和 mixins.scss 會優先於 global.css 載入,並且可以不通過 import 的方式在專案中任何位置使用這些變數和 mixins。

//vue.config.js
module.exports={
css:{
loaderOptions:{
sass:{
prependData:`
@import'@/styles/variable.scss';
@import'@/styles/mixins.scss';
`,
},
},
},
}

體驗優化

頁面載入進度條

使用 nprogress 對路由跳轉時做一個偽進度條,這樣做在網路不好的情況下可以讓使用者知道頁面已經在載入了:

importNProgressfrom'nprogress';

router.beforeEach(()=>{
NProgress.start();
});

router.afterEach(()=>{
NProgress.done();
});


美化滾動條

一直用 Mac 做前端,突然發現同事的 Windows 上出現了十分醜陋的滾動條,為了保持一致:

::-webkit-scrollbar{
width:6px;
height:6px;
}

::-webkit-scrollbar-track{
width:6px;
background:rgba(#101F1C,0.1);
-webkit-border-radius:2em;
-moz-border-radius:2em;
border-radius:2em;
}

::-webkit-scrollbar-thumb{
background-color:rgba(#101F1C,0.5);
background-clip:padding-box;
min-height:28px;
-webkit-border-radius:2em;
-moz-border-radius:2em;
border-radius:2em;
}

::-webkit-scrollbar-thumb:hover{
background-color:rgba(#101F1C,1);
}

靜態資源載入頁面

首次載入頁面時,會產生大量的白屏時間,這時做一個 loading 效果看起來會很友好,其實很簡單,直接在 public/index.html 裡寫一些靜態的樣式即可。

移動端 100vh 問題

在移動端使用 100vh 時,發現在 Chrome、Safari 瀏覽器中,因為瀏覽器欄和一些導航欄、連結欄導致不一樣的呈現:

你以為的 100vh === 視口高度

實際上 100vh === 視口高度 + 瀏覽器工具欄(位址列等等)的高度

解決方案

安裝 vh-checknpm install vh-check \--save

importvhCheckfrom'vh-check';
vhCheck('browser-address-bar');

定義一個 CSS Mixin

@mixin vh($height: 100vh) {
height: $height;
height: calc(#{$height} - var(--browser-address-bar, 0px));
}

之後就是哪裡不會點哪裡。

3.元件庫

因為 Element UI 長期沒更新,並且之前使用過 React 的 Ant Design(重點),所以元件庫選擇了Ant Design Vue。

覆蓋 Ant Design Vue 樣式

設計師眼中的 Ant Design === '醜'(心酸)。

1.使用 .less 檔案

Ant Design Vue 的樣式使用了 Less 作為開發語言,並定義了一系列全域性/元件的樣式變數,所以需要安裝了 less、less-loader,在@/styles/antd-theme.less可以覆蓋預設樣式。

優點是:

方便快捷,可以修改 class,覆蓋預設變數。

缺點是:

必須引入@import '~ant-design-vue/dist/antd.less';,引入後會將所有的元件樣式全部引入,導致打包後的 css 體積達到 500kb 左右。

2.使用 JavaScript 物件

通過 JavaScript 物件的方式可以修改內建變數,需要對 Less 進行配置:

//vue.config.js
constmodifyVars=require('./src/styles/antdTheme.js');

module.exports={
css:{
loaderOptions:{
less:{
lessOptions:{
javascriptEnabled:true,
modifyVars,
},
},
},
},
}

這一步還可以繼續優化,通過 babel-plugin-import 使 Ant Design Vue 的元件樣式可以按需載入:

//babel.config.js
module.exports={
presets:[
'@vue/cli-plugin-babel/preset',
],
plugins:[
[
'import',
{libraryName:'ant-design-vue',libraryDirectory:'es',style:true},
],
],
};

優點是:

可以按需引入,打包後的 CSS 體積取決於你引用了多少個元件。

缺點是:

不能使用 class 進行樣式覆蓋。

幹掉無用的圖示

Ant Design Vue 把所有的 Icon 一次性引入(不管你因用了多少個元件),這使得體積打包後圖標所佔的體積竟然有幾百 kb 之多。這些圖示大多數不會被設計師所採納,所以部分圖示都應該被幹掉:

建立一個 icons.js 來管理 Ant Design Vue 圖示,這裡以一個 Loading 圖示為例:

//@/src/assets/icons.js
export{defaultasLoadingOutline}from'@ant-design/icons/lib/outline/LoadingOutline';

如何知道你要載入的圖示在什麼路徑下?

在 @ant-design/icons/lib 目錄下有三種風格的圖示,分別是 fill、outline、twotone,這裡面內部的檔案並不是 svg 格式,而是 js 和 ts 格式,這就是為什麼我們可以這麼引入圖示的關鍵所在了。

下一步是通過配置 vue.config.js 將這個檔案引入進來:

//vue.config.js
module.exports={
configureWebpack:{
resolve:{
alias:{
'@ant-design/icons/lib/dist$':path.resolve(__dirname,'./src/assets/icons.js'),
},
},
},
}

解決 Moment 多國語

解決到這之後,Ant Design Vue 居然還很大,這是因為 moment 是 Ant Design Vue 中有強依賴該外掛,所以使用 webpack 外掛減小打包體積,這裡我們只保留 zh-cn 語言包:

//vue.config.js
module.exports={
chainWebpack:(config)=>{
config
.plugin('ContextReplacementPlugin')
.use(webpack.ContextReplacementPlugin,[/moment[/\\]locale$/,/zh-cn/]);
},
}

部分元件需要在頁面內引用

Ant Design Vue 中部分體積較大的元件,例如DatePicker,根據業務需求,應考慮在頁面中進行載入,儘量保證首屏載入的速度:

<script>
import { DatePicker } from 'ant-design-vue';
export default {
components: {
ADatePicker: DatePicker,
},
}
</script>

4.靜態資源與圖示

靜態資源

所有的靜態資原始檔都會上傳到 阿里雲 OSS 上,所以在環境變數上加以區分。

.env.development.env.productionVUE_APP_STATIC_URL屬性分別配置了本地的靜態資源伺服器地址和線上 OSS 的地址。

本地的靜態資源伺服器是通過 pm2 + http-server 建立的,設計師切完直接扔進來就好了。

自動註冊 Svg 圖示

在日常的開發中,總是會有著大量的圖示需要使用,這裡我們直接選擇使用 SVG 圖示。但是如果每次使用圖示還需要通過路徑找到這張圖示豈不是很麻煩?

下面這種才是我想要的方案(直接 name 等於 檔名即可):

<template>
<svg name="logo" />
</template>

而且最後打包後需要合併成一張雪碧圖。

首先需要對@/assets/icons資料夾下的 svg 圖示進行自動註冊,需要對 webpack 和 svg-sprite-loader 進行了相關設定,檔案全部打包成 svg-sprite。

module.exports={
chainWebpack:(config)=>{
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end();

config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader');
},
}

寫一個全域性用的 Vue 元件<m-svg />:

// @/components/m-svg/index.js

constrequireAll=(requireContext)=>requireContext.keys().map(requireContext);
constreq=require.context('@/assets/icons',false,/\.svg$/);
requireAll(req);

@/components/m-svg/index.vue

<template>
<svg class="mw-svg" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'm-svg',
props: {
name: { type: String, default: '' },
},
computed: {
iconName() {
return `#${this.name}`;
},
},
};
</script>
<style lang="scss" scoped>
.mw-svg {
width: 1.4em;
height: 1.4em;
fill: currentColor;
overflow: hidden;
line-height: 1em;
display: inline-block;
}
</style>

引數 name

  • 型別:String
  • 預設值:null
  • 說明:放置在@/assets/icons資料夾下的檔名

樣式

  • 圖示的大小可以通過 width + height 屬性改變。
  • 通過改變 font-size 屬性改變,寬高 = font-zise * 1.4

5.非同步請求

封裝 Axios

@/libs/request.js路徑下對 Axios 進行封裝,封裝了請求引數,請求頭,以及錯誤提示資訊、 request 攔截器、response 攔截器、統一的錯誤處理、baseURL 設定等。

廢話不說直接貼程式碼:

importaxiosfrom'axios';
importgetfrom'lodash/get';
importstoragefrom'store';
//建立axios例項
constrequest=axios.create({
//API請求的預設字首
baseURL:process.env.VUE_APP_BASE_URL,
timeout:10000,//請求超時時間
});

//異常攔截處理器
consterrorHandler=(error)=>{
conststatus=get(error,'response.status');
switch(status){
/*eslint-disableno-param-reassign*/
case400:error.message='請求錯誤';break;
case401:error.message='未授權,請登入';break;
case403:error.message='拒絕訪問';break;
case404:error.message=`請求地址出錯:${error.response.config.url}`;break;
case408:error.message='請求超時';break;
case500:error.message='伺服器內部錯誤';break;
case501:error.message='服務未實現';break;
case502:error.message='閘道器錯誤';break;
case503:error.message='服務不可用';break;
case504:error.message='閘道器超時';break;
case505:error.message='HTTP版本不受支援';break;
default:break;
/*eslint-disabled*/
}
returnPromise.reject(error);
};

//requestinterceptor
request.interceptors.request.use((config)=>{
//如果token存在
//讓每個請求攜帶自定義token請根據實際情況自行修改
//eslint-disable-next-lineno-param-reassign
config.headers.Authorization=`bearer${storage.get('ACCESS_TOKEN')}`;
returnconfig;
},errorHandler);

//responseinterceptor
request.interceptors.response.use((response)=>{
constdataAxios=response.data;
//這個狀態碼是和後端約定的
const{code}=dataAxios;
//根據code進行判斷
if(code===undefined){
//如果沒有code代表這不是專案後端開發的介面
returndataAxios;
//eslint-disable-next-lineno-else-return
}else{
//有code代表這是一個後端介面可以進行進一步的判斷
switch(code){
case200:
//[示例]code===200代表沒有錯誤
returndataAxios.data;
case'xxx':
//[示例]其它和後臺約定的code
return'xxx';
default:
//不是正確的code
return'不是正確的code';
}
}
},errorHandler);

exportdefaultrequest;

  • 通過 VUE_APP_BASE_URL 區分線上與開發環境的 API 地址。
  • code 起到一個比較關鍵的作用,例如 token 過期時的驗證。
  • 使用了一個叫 sotre 的包作為本地儲存的工具用來儲存 token。

跨域問題

跨域問題一般情況直接找後端解決了,你要是不好意思打擾他們的話,可以用 devServer 提供的 proxy 代理:

//vue.config.js
devServer:{
proxy:{
'/api':{
target:'http://47.100.186.132/your-path/api',
ws:true,
changeOrigin:true,
pathRewrite:{
'^/api':''
}
}
}
}

Mock 資料

一個很常見的情況,後端介面沒出來,前端在這乾瞪眼。

Mock 資料功能是基於 mock.js (opens new window)開發,通過 webpack 進行自動載入 mock 配置檔案。

規則

  • 所有的 mock 配置檔案均應放置在@/mock/services路徑內。
  • @/mock/services內部可以建立業務相關的資料夾分類存放配置檔案。
  • 所有的配置檔案應按照***.mock.js的命名規範建立。
  • 配置檔案使用 ES6 Module 匯出export defaultexport一個數組。

入口檔案

importMockfrom'mockjs';

Mock.setup({
timeout:'500-800',
});

constcontext=require.context('./services',true,/\.mock.js$/);

context.keys().forEach((key)=>{
Object.keys(context(key)).forEach((paramKey)=>{
Mock.mock(...context(key)[paramKey]);
});
});

示例模板

importMockfrom'mockjs';

const{Random}=Mock;

exportdefault[
RegExp('/example.*'),
'get',
{
'range|50-100':50,
'data|10':[
{
//唯一ID
id:'@guid()',
//生成一箇中文名字
cname:'@cname()',
//生成一個url
url:'@url()',
//生成一個地址
county:Mock.mock('@county(true)'),
//從陣列中隨機選擇一個值
'array|1':['A','B','C','D','E'],
//隨機生成一個時間
time:'@datetime()',
//生成一張圖片
image:Random.dataImage('200x100','MockImage'),
},
],
},
];

6.路由

Layout

佈局暫時分為三大類:

  • frameIn:基於BasicLayout,通常需要登入或許可權認證的路由。

  • frameOut:不需要動態判斷許可權的路由,如登入頁或通用頁面。

  • errorPage:例如404。

許可權驗證

通過獲取當前使用者的許可權去比對路由表,生成當前使用者具的許可權可訪問的路由表,通過 router.addRoutes 動態掛載到 router 上。

  • 判斷頁面是否需要登陸狀態,需要則跳轉到 /user/login
  • 本地儲存中不存在 token 則跳轉到 /user/login
  • 如果存在 token,使用者資訊不存在,自動呼叫 vuex '/system/user/getInfo'

在路由中,集成了許可權驗證的功能,需要為頁面增加許可權時,在 meta 下新增相應的 key:

auth

  • 型別:Boolean
  • 說明:當 auth 為 true 時,此頁面需要進行登陸許可權驗證,只針對 frameIn 路由有效。

permissions

  • 型別:Object
  • 說明:permissions 每一個 key 對應許可權功能的驗證,當 key 的值為 true 時,代表具有許可權,若 key 為 false,配合v-permission指令,可以隱藏相應的 DOM。

在這裡貼一下路由跳轉時許可權驗證的程式碼:

importrouterfrom'@/router';
importstorefrom'@/store';
importstoragefrom'store';
importutilfrom'@/libs/utils';

//進度條
importNProgressfrom'nprogress';
import'nprogress/nprogress.css';

constloginRoutePath='/user/login';
constdefaultRoutePath='/home';

/**
*路由攔截
*許可權驗證
*/
router.beforeEach(async(to,from,next)=>{
//進度條
NProgress.start();
//驗證當前路由所有的匹配中是否需要有登入驗證的
if(to.matched.some((r)=>r.meta.auth)){
//是否存有token作為驗證是否登入的條件
consttoken=storage.get('ACCESS_TOKEN');
if(token&&token!=='undefined'){
//是否處於登入頁面
if(to.path===loginRoutePath){
next({path:defaultRoutePath});
//查詢是否儲存使用者資訊
}elseif(Object.keys(store.state.system.user.info).length===0){
store.dispatch('system/user/getInfo').then(()=>{
next();
});
}else{
next();
}
}else{
//沒有登入的時候跳轉到登入介面
//攜帶上登陸成功之後需要跳轉的頁面完整路徑
next({
name:'Login',
query:{
redirect:to.fullPath,
},
});
NProgress.done();
}
}else{
//不需要身份校驗直接通過
next();
}
});

router.afterEach((to)=>{
//進度條
NProgress.done();
util.title(to.meta.title);
});

頁面開發

  • 根據業務需要劃分,按照路由層級在 views 中建立相對應的頁面元件,以資料夾的形式建立,並在資料夾內建立 index.vue 檔案作為頁面的入口檔案。
  • 頁面內的元件:在頁面資料夾下建立 components 資料夾,在其內部對應建立相應的元件檔案,如果是複雜元件,應以資料夾的形式建立元件。
  • 工具模組:能夠高度抽象的工具模組,應建立在 @/src/libs 內建立 js 檔案。

7、構建優化

包分析工具

構建程式碼之後,到底是什麼佔用了這麼多空間?靠直覺猜測或者使用 webpack-bundle-analyzer。

constWebpackBundleAnalyzer=require('webpack-bundle-analyzer');

module.exports={
chainWebpack:(config)=>{
if(process.env.use_analyzer){
config
.plugin('webpack-bundle-analyzer')
.use(WebpackBundleAnalyzer.BundleAnalyzerPlugin);
}
},
};

開啟 Gzip

對,這這麼一句話,後端就得支援你的 .gz 檔案了,而你只需要坐著等老闆誇:

chainWebpack:(config)=>{
config
.plugin('CompressionPlugin')
.use(CompressionPlugin,[]);
},

路由懶載入

這塊 @vue/cli 已經幫忙處理好了,但也需要了解一下他的原理和如何配置。

{
path:'home',
name:'Home',
component:()=>import(
/*webpackChunkName:"home"*/'@/views/home/index.vue'
),
},

webpackChunkName 這條註釋還是很有必要加的,至少你打包後知道又是哪個頁面變得又臭又大。

Preload & Prefetch

不清楚這兩個功能的去 @vue/cli 補課,這兩個功能非常有助於你處理載入的效能。

8.測試框架

直接使用了官方提供的 Vue Test Utils,這東西可以對元件進行測試,很不錯。

寫單元測試在團隊裡其實很難推進,不知道大家怎麼看。

9.元件庫

對於很多第三方的工具,我堅持認為二次封裝成 vue 外掛並沒有多少開發成本,反而讓你在後續的開發中變得很靈活。

我對以下庫進行了 vue 外掛的封裝,並提交到 npm 私服:

  • 數字動畫
  • 程式碼高亮
  • 大檔案上傳(切片、斷點續傳、秒傳)需要與後端配合
  • 圖片預覽
  • Excel 匯入匯出
  • 富文字編輯器
  • Markdown 編輯器
  • 程式碼編輯器

大檔案上傳有興趣的可以留言,我後續單獨拎出來詳細的寫一下這塊。

10.Vuex

內建一些功能,主要是對以下這些功能做了一些封裝:

  • 使用者資訊管理(儲存資訊、對 token 進行操作等)

  • 登陸(調介面)

  • 選單管理(儲存路由資訊,生成選單,模糊查詢等功能)

  • UA資訊

  • 全屏操作

  • Loading

  • 日誌管理(訊息提醒、日誌留存、日誌上報)

11.過濾器

過濾器是 Vue 提供的一個很好用的功能,聽說 vue3 沒了?

{{message|capitalize}}

我寫了幾個常用的過濾器:

  • 日期時間
  • 剩餘時間
  • 區分環境的連結(主要針對本地靜態資源伺服器和 OSS )
  • 檔案大小
  • 數字金額
  • 浮點型精度

12.指令

自定義指令可以提供很好的幫助:

  • 元件許可權驗證
  • 文字複製
  • 快捷鍵繫結
  • 滾動至指定位置
  • 圖片懶載入
  • 焦點

13.開發規範

ESLint

不管是多人合作還是個人專案,程式碼規範都是很重要的。這樣做不僅可以很大程度地避免基本語法錯誤,也保證了程式碼的可讀性。

這裡我們採用了 Airbnb JavaScript Style Guide。

這套規範給我的感覺就是很嚴謹

CSS 規範

降低選擇器複雜性

瀏覽器讀取選擇器,遵循的原則是從選擇器的右邊到左邊讀取。

#block.textp{
color:red;
}

  • 查詢所有 P 元素。
  • 查詢結果 1 中的元素是否有類名為 text 的父元素
  • 查詢結果 2 中的元素是否有 id 為 block 的父元素

選擇器優先順序

內聯 > ID選擇器 > 類選擇器 > 標籤選擇器

  • 選擇器越短越好。
  • 儘量使用高優先順序的選擇器,例如 ID 和類選擇器。
  • 避免使用萬用字元 *。

使用 flexbox

在早期的 CSS 佈局方式中我們能對元素實行絕對定位、相對定位或浮動定位。而現在,我們有了新的佈局方式 flexbox,它比起早期的佈局方式來說有個優勢,那就是效能比較好。不過 flexbox 相容性還是有點問題,不是所有瀏覽器都支援它,所以要謹慎使用。各瀏覽器相容性:

  • Chrome 29+
  • Firefox 28+
  • Internet Explorer 11
  • Opera 17+
  • Safari 6.1+ (prefixed with -webkit-)
  • Android 4.4+
  • iOS 7.1+ (prefixed with -webkit-)

動畫效能優化

在 CSS 中,transforms 和 opacity 這兩個屬性更改不會觸發重排與重繪,它們是可以由合成器(composite)單獨處理的屬性。

屬性值

  • 當數值為 0 - 1 之間的小數時,建議省略整數部分的 0。
  • 當長度為 0 時建議省略單位。
  • 建議不使用命名色值。
  • 建議當元素需要撐起高度以包含內部的浮動元素時,通過對偽類設定 clear 或觸發 BFC 的方式進行 clearfix。儘量不使用增加空標籤的方式。
  • 除公共樣式之外,在業務程式碼中儘量不能使用 !important。
  • 建議將 z-index 進行分層,對文件流外絕對定位元素的視覺層級關係進行管理。

字型排版

  • 字號應不小於 12px(PC端)。
  • font-weight 屬性建議使用數值方式描述。
  • line-height 在定義文字段落時,應使用數值。

Vue 程式碼規範

常規

  • 當在元件中使用 data 屬性的時候 (除了 new Vue 外的任何地方),它的值必須是返回一個物件的函式data() { return {...} }

  • prop 的定義應該儘量詳細,至少需要指定其型別。

  • 布林型別的 attribute, 為 true 時直接寫屬性值。

  • 不要在computed中對vue變數進行操作。

  • 應該優先通過 prop 和事件進行父子元件之間的通訊,而不是 this.$parent 或改變 prop。

  • 在元件上總是必須用 key 配合 v-for,以便維護內部元件及其子樹的狀態。

  • v-if 和 v-for 不能同時使用

  • 公共方法儘量不要掛到原型上, 可以寫在 utils 檔案,也可以使用 mixin 檔案。不要將業務公共元件註冊到全域性。

  • 不要將任何第三方外掛掛載到 vue 原型上。

  • 具有高度通用性的方法,要封裝到 libs、全域性元件或指令集裡。

  • 為元件樣式設定作用域。

  • 儘量使用指令縮寫。

vuex

State (opens new window)為單一狀態樹,在 state 中需要定義我們所需要管理的陣列、物件、字串等等,只有在這裡定義了,在 vue 的元件中才能獲取你定義的這個物件的狀態。

  • 修改state中資料必須通過mutations
  • 每一個可能發生改變的state必須同步建立一條或多條用來改變它的mutations
  • 服務端獲取的資料存放在state中,作為原始資料保留,不可變動。

Getters (opens new window)有點類似 vue.js 的計算屬性,當我們需要從 store 的 state 中派生出一些狀態,那麼我們就需要使用 getters,getters 會接收 state 作為第一個引數,而且 getters 的返回值會根據它的依賴被快取起來,只有 getters 中的依賴值(state 中的某個需要派生狀態的值)發生改變的時候才會被重新計算。

  • 通過getters處理你需要得到的資料格式,而不是通過修改state原始資料。

  • 元件內不強制使用mapGetters,因為你可能需要使用gettersetter

  • 改變state的唯一方法就是提交 mutations (opens new window)。

  • 元件內使用mapMutations輔助函式將元件中的methods對映為store.commit呼叫。

  • 命名採用大寫字母+下劃線的規則。

  • 定義CLEAR,以確保路由切換時可以初始化資料。

Actions

  • 頁面重的資料介面儘量在 actions (opens new window)中呼叫。
  • 服務端返回的資料儘量不作處理,保留原始資料。
  • 獲取到的資料必須通過呼叫mutations改變state

Modules

  • 通常情況下按照頁面劃分 modules (opens new window)。
  • 預設內建了system保證了腳手架的基礎功能。
  • 每個頁面模組或頁面的子模組新增屬性namespaced: true

14.完成詳細的使用文件

不論是功能還是元件庫等等的工具,都需要完善的文件提供查閱,即使是輪子的構建者,也抵不住時間長了會忘記許多細節。

這裡我使用 vuepress 構建文件,方便快捷。

參考【拯救懶癌文件君 - VuePress + Travis CI + Github Pages 自動線上生成文件】

15.Git 多人協作流程

公司使用內部搭建的 GitLab 託管程式碼

Root 倉庫

專案啟動時,由專案管理者搭建起最原始的倉庫,稱為 Root 倉庫(源倉庫)。

源倉庫的有個作用 :

  • 彙總參與該專案的各個開發者的程式碼。
  • 存放趨於穩定和可釋出的程式碼。
  • 向 Master 分支提交 Merge Requests 可以觸發測試環境構建(CI/CD)。
  • 源倉庫是受保護的,開發者不可直接對其進行開發工作。

開發者倉庫

任何開發者都沒有許可權對 Root 倉庫進行直接的操作,源倉庫建立以後,每個開發者需要做的事情就是把源倉庫的 Fork 一份,作為自己日常開發的倉庫。

  • 每個開發者所Fork的倉庫是完全獨立的,互不干擾。
  • 每個開發者提交到程式碼到自己的倉庫中,開發工作完成以後,開發者可以向源倉庫傳送 Pull Request ,本地倉庫先合併源倉庫,解決衝突。
  • 發起 Merge Request 請求管理員把自己的程式碼合併到源倉庫中的 master 或 其他分支。

Git 流程

  • 前端專案會在Root倉庫下建立dev分支,用於程式碼的拉取和合並,如果有多個不同的測試環境,按照測試環境建立分支。
  • 在本地的倉庫中建立你的dev分支和其他功能性的分支。
  • 開發過程中不允許直接在master分支上開發,建立一個新的分支進行開發,git checkout –b {branch_name}
  • 規範且詳細的書寫commit,推薦使用git-cz工具進行提交。
  • 完成開發後將相應的分支合併到自己倉庫的master分支。
  • master分支push到自己的遠端倉庫(Fork倉庫)。
  • Root倉庫dev分支提交Merge Requests
  • 提醒前端負責人審查程式碼、解決衝突或測試環境上線。
  • 解決衝突後git pull upstream dev拉取解決後的最新程式碼。