以前作了一個React項目和Vue的項目,在作完後不加任何優化的狀況下,這2個項目的首屏加載平均時間竟然達到了20+s,好一點能進10s,差一點快30s,徹底不能忍,優化勢在必行,本文章記錄下Vue項目的優化過程,React項目的優化後續補上。html
上圖是Vue項目的首頁,整個項目由vue-cli搭建,主要分爲4個模塊,見頁面左側導航欄,整體代碼量不算太大,組件的話總共50個左右吧,項目結構見下圖,不算特別大的項目,可是首屏加載時間竟然這麼慢。vue
首先得肯定究竟是哪裏致使了首屏渲染如此之慢?打開Chrome Network面板,勾上Disable cache選項,刷新頁面觀察資源加載狀況,發現罪魁禍首就是webpack打包生成的app.js和vendor.js,其中vendor.js大小達到了1.2M,下載時間超過20秒,app.js也快到1M,而manifest.js不是很大。vendor.js主要是把node_modules裏所用到的modules都合併成一個js了,因此比較大.而咱們也但願將業務代碼和第三方引用分開打包。manifest.js
包含webpack的runtime代碼和module manifest代碼,做用是防止修改了代碼可是沒有修改第三方庫文件致使第三方庫文件也打包的問題。
網上一番搜索,發現優化點主要在以下幾個方面:
node
gzip是GNUzip的縮寫,最先用於UNIX系統的文件壓縮。HTTP協議上的gzip編碼是一種用來改進web應用程序性能的技術,web服務器和客戶端(瀏覽器)必須共同支持gzip。目前主流的瀏覽器,Chrome,firefox,IE等都支持該協議。常見的服務器如Apache,Nginx,IIS一樣支持,gzip壓縮效率很是高,一般能夠達到70%的壓縮率,也就是說,若是你的網頁有30K,壓縮以後就變成了9K左右webpack
我後端是用的express,開啓gzip很是簡單,首先npm install compression安裝中間件,而後在app.js裏添加use使用便可:
web
var compression = require('compression');
var app = express();
app.use(compression())
複製代碼
重啓服務,觀察網絡面板裏面的response header,若是看到以下紅圈裏的字段則代表gzip開啓成功vue-router
CDN(內容分發網絡),是一種公共服務,他自己有不少臺位於不一樣地域、接入不一樣運營商的服務器,而所謂的使用CDN實質上就是讓CDN做爲網站的門面,用戶訪問到的是CDN服務器,而不是直接訪問到網站。因爲CDN內部對TCP的優化、對靜態資源的緩存、預取,加上用戶訪問CDN時,會被智能地分配到最近的節點,下降大量延遲,讓訪問速度能夠獲得很大提高vuex
一個原則是儘可能將比較大的第三方庫放到cdn上去以減小請求時間,在個人項目中,我將vue,vuex,vue-router,echarts都放到了cdn上,具體操做是打開BootCDN 而後搜索關鍵字並copy連接粘貼到index.html的body閉合標籤前,以下圖vue-cli
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'echarts': 'echarts'
},
複製代碼
cdn使用後優點是巨大的,觀察network面板,時間幾乎都在50ms如下express
路由懶加載也叫延遲加載,即在須要的時候進行加載,隨用隨載。像vue這種單頁面應用,若是沒有應用懶加載,運用webpack打包後的文件將會異常的大,形成進入首頁時,須要加載的內容過多,時間過長,會出現長時間的白屏,即便作了loading也是不利於用戶體驗,而運用懶加載則能夠將頁面進行劃分,須要的時候加載頁面,能夠有效的分擔首頁所承擔的加載壓力,減小首頁加載用時。
Vue官網的示例以下,採用異步組件和webpack的code-splitting結合npm
所以在項目中,進入router的index.js中,將原來的import Comp from '@/component/xxx'
改成以下,vue-router的配置項仍是保持不變
//異步組件,路由懶加載
const BookMark = resolve => require(['@/components/BookMark'],resolve);
const HotBookMark = resolve => require(['@/components/HotBookMark'],resolve);
const ImportBookMark = resolve => require(['@/components/ImportBookMark'],resolve);
const Default = resolve => require(['@/components/Default'],resolve);
複製代碼
打包後查看js文件夾下的文件,會多出上述文件,每一個進行懶加載的組件都會生成一個js,以下圖紅框內
好比本項目裏面使用的echarts,只用到了一個柱狀圖組件,其他的都沒有用到,可是這樣import後打包時卻會把整個echarts都打入包內,形成空間浪費
import echarts from 'echarts'
複製代碼
所以只須要import用到的組件便可,以下,這樣就能夠減小不少沒必要要的體積
import echarts from 'echarts/lib/echars'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
複製代碼
小圖片能夠轉爲base64字符串而後嵌入img的src中,節省http請求數量,webpack中用url-loader處理,limit控制了圖片轉base64的閾值,小於該值就轉base64
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
複製代碼
通過上述優化後,首頁打開時間迅速降低,DomContentLoaded用時不到1s,load徹底加載用時不到4s,耗時較多的是幾張背景大圖,原本體積就大,後續考慮放到cdn上
這是最初的優化策略,後續繼續會進行深度優化。
ps:webpack-bundle-analyzer是神器,可以有效分析出包占用的體積狀況~下圖是最終優化後的包組成結構圖,最初打包的結構圖比下圖大不少,主要多了echarts,vue,vue-router,vuex模塊
優化後的整個包gzip後大小喜人~