Vue SPA 首屏載入優化實踐

寫在前面

本文記錄筆者在Vue SPA項目首屏載入優化過程中遇到的一些坑及優化方案!

我們以 vue-cli 工具為例,使用 vue-router 搭建SPA應用,UI框架選用 element-ui , ajax方案選用 axios, 並引入 vuex ,使用 vuex-router-sync 將 router 同步到 store ,伺服器使用本地Nginx服務。

構建項目

vue-init webpack vue-spa-starter-kit

cd vue-spa-starter-kit

npm install

npm install vuex element-ui axios -S

npm run dev

vue-cli會自動打開瀏覽器,可以看到效果。我們在入口文件中引入vue-routerelement-uiaxios

// src/main.js

import babel-polyfill

import Vue from vue

import App from ./App

import axios from axios

import store from ./store

import router from ./router

import {sync} from vuex-router-sync

import ElementUI from element-ui

import element-ui/lib/theme-chalk/index.css

Vue.config.productionTip = false

Vue.use(ElementUI)

Vue.prototype.$http = axios

sync(store, router)

/* eslint-disable no-new */

new Vue({

el: #app,

store,

router,

template: <App/>,

components: { App }

})

接下來我們不做任何修改,使用默認的配置進行打包,Nginx採用默認配置,部署到Nginx,啟動Nginx服務,查看效果:

可以看出,在沒有開發任何頁面及功能的情況下,vendor.js 有788kb。如果我們再依賴一些其他的庫,比如 echarts 等,vendor.js 能到 1M 以上。

使用CDN資源

我們要將 vuevue-routervuexelement-uivendor.js 中分離出來,使用CDN資源引入。國內的CDN服務推薦使用 BootCDN。國外不是很好用。。。

首先在模板文件index.html中添加以下內容:

...

<head>

<link rel="stylesheet" href="cdn.bootcss.com/element">

</head>

<body>

<div id="app"></div>

<script src="cdn.bootcss.com/vue/2.5"></script>

<script src="cdn.bootcss.com/vuex/3."></script>

<script src="cdn.bootcss.com/vue-rou"></script>

<script src="cdn.bootcss.com/element"></script>

<!-- built files will be auto injected -->

</body>

修改 build/webpack.base.conf.js。關於 externals 配置項請自行查閱相關資料。

module.exports = {

...

externals: {

vue: Vue,

vuex: Vuex,

vue-router: VueRouter,

element-ui: ELEMENT

}

...

}

修改 src/router/index.js

// import Vue from vue

import VueRouter from vue-router

// 注釋掉

// Vue.use(VueRouter)

...

修改 src/store/index.js

...

// 注釋掉

// Vue.use(Vuex)

...

修改 src/main.js

import babel-polyfill

import Vue from vue

import App from ./App

import axios from axios

import store from ./store

import router from ./router

import {sync} from vuex-router-sync

import ELEMENT from element-ui

// import element-ui/lib/theme-chalk/index.css

Vue.config.productionTip = false

Vue.use(ELEMENT)

Vue.prototype.$http = axios

sync(store, router)

/* eslint-disable no-new */

new Vue({

el: #app,

store,

router,

template: <App/>,

components: { App }

})

注意!這裡 element-ui 變數名要使用 ELEMENT,因為element-ui的 umd 模塊名是 ELEMENT

再次打包,部署到Nginx服務,可以看到:

vendor.js 減少到了 112kb,提升85.5%!

再看CDN資源:

可以看出,5個請求共216kb,耗時619ms!

Nginx 開啟 gzip

vendor.js 我們優化完了,接下來我們優化伺服器上的資源。先看看沒有開啟 gzip 的效果:

可以看到有 13.5kb

Nginx開啟gzip,修改nginx配置文件 nginx.conf:

...

http {

...

gzip on;

gzip_min_length 1k;

gzip_buffers 4 16k;

#gzip_http_version 1.1;

gzip_comp_level 2; # 壓縮級別

# 要壓縮的mine類型

gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss image/jpeg image/gif image/png image/svg+xml;

gzip_vary off;

gzip_proxied expired no-cache no-store private auth;

gzip_disable "MSIE [1-6]."; # IE6不支持gzip

...

}

關於 nginx gzip,請自行查閱相關資料

重啟nginx服務,再看效果:

可以看到伺服器上的資源經過gzip壓縮之後有 9kb,壓縮比 13.3%。

development 和 production

上文中我們修改的是 build/webpack.base.conf.js,這樣一來,本地開發的時候我們就不能使用 vue-devtools Chrome調試工具了,為了方便調試,我們需要將development和production 配置分開。

  1. 首先將 build/webpack.base.conf.jsexternals 配置項挪到 build/webpack.prod.conf.js 中:

    // build/webpack.prod.conf.js

    module.exports = {

    ...

    externals: {

    vue: Vue,

    vuex: Vuex,

    vue-router: VueRouter,

    element-ui: ELEMENT

    }

    ...

    }
  2. 拷貝 index.html 模板文件,並命名為 index.prod.html; 將原來的 index.html 重命名為 index.dev.html,並刪除 CDN 資源:

<!-- index.dev.html -->

<head>

...

<!-- <link rel="stylesheet" href="cdn.bootcss.com/element"> -->

</head>

<body>

<div id="app"></div>

<!-- <script src="cdn.bootcss.com/vue/2.5"></script>

<script src="cdn.bootcss.com/vuex/3."></script>

<script src="cdn.bootcss.com/vue-rou"></script>

<script src="cdn.bootcss.com/element"></script> -->

<!-- built files will be auto injected -->

</body>

<!-- index.prod.html -->

<head>

<link rel="stylesheet" href="cdn.bootcss.com/element">

</head>

<body>

<div id="app"></div>

<script src="cdn.bootcss.com/vue/2.5"></script>

<script src="cdn.bootcss.com/vuex/3."></script>

<script src="cdn.bootcss.com/vue-rou"></script>

<script src="cdn.bootcss.com/element"></script>

<!-- built files will be auto injected -->

</body>

  1. 修改 build/webpack.dev.conf.js:

    plugins: [

    ...

    new HtmlWebpackPlugin({

    filename: index.html,

    template: index.dev.html,

    inject: true

    })

    ]
  2. 修改 build/webpack.prod.conf.js:

    plugins: [

    ...

    new HtmlWebpackPlugin({

    filename: index.html,

    template: index.prod.html,

    inject: true,

    ...

    })

    ]
  3. 修改 vue-routervuexelement-ui 的引用:

    // src/main.js

    ...

    if (process.env.NODE_ENV === development) {

    require(element-ui/lib/theme-chalk/index.css)

    }

    ...

    // src/router/index.js

    import Vue from vue

    import VueRouter from vue-router

    if (process.env.NODE_ENV === development) {

    Vue.use(VueRouter)

    }

    ...

    // src/store/index.js

    import Vue from vue

    import Vuex from vuex

    if (process.env.NODE_ENV === development) {

    Vue.use(Vuex)

    }

    ...

    這樣我們就可以愉快的在開發環境使用 vue-devtools Chrome調試工具了!

    總結

    至此,我們初步的優化就完成了。我實際的項目首屏載入加上一些第三方客服,第三方校驗等優化到近4s 左右。由於是演示項目,並沒有開發其他的頁面和功能,效果不是很明顯,大家可以自行踩坑。大家有更好的方案,可以共同學習!

推薦閱讀:

TAG:Vue.js實戰(書籍) | React | AngularJS | 前端框架 |