頁面加載性能是一個老生常談的問題,但是卻異常重要,尤其在訪問量大的商業軟件中。但是有很多開發者在開發過程中壓根就沒有考慮過這個問題。大家在開發業務代碼的過程中,也就忽略了這個增加工作量,也不會帶來什麼直觀的工作內容。
寫在前面,這裏以vue框架爲例,基於vue-cli3的開發方式
首先,使用webpack分析工具,查看當前項目的依賴,分析依賴及打包情況,對症下藥
安裝插件
npm i webpack-bundle-analyzer -D
在vue.config.js中,添加如下配置:
chainWebpack: (config)=>{
/* 添加分析工具*/
if (process.env.NODE_ENV === 'production') {
if (process.env.npm_config_report) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
.end()
config.plugins.delete('prefetch')
}
}
...
}
執行命令
npm run build --report
執行成功後,瀏覽器會打開一個窗口,顯示當前依賴的大小及各打包文件情況
結合自己的項目情況,分析依賴的引入及打包情況,有以下幾點優化方式
第一,路由懶加載。
查看打包目錄中,js文件夾下的chunk-哈希值的文件爲採用懶加載形式時生成的文件,一個路由會生成一個文件。
const home= () => import('@/pages/home/index.vue')
第二,使用CDN引入第三方依賴。
比如,直接引入ehcarts會發現佔打包文件較大的空間,如果項目沒有特殊要求,可以採用CDN的方式引入;其他諸如axios、vue、lodash等都可以採用這種方式。
- 在index.html中引入CDN資源
...
<body>
<div id="app">
</div>
<!-- built files will be auto injected -->
<script src="//cdn.bootcss.com/echarts/4.2.1/echarts.simple.min.js"></script>
</body>
...
- 修改vue.config.js配置文件
module.exports = {
configureWebpack: {
externals: {
'echarts': 'echarts' // 配置使用CDN
}
}
}
externals中的key是用於import,value表示的在全局中訪問到該對象,就是window.echarts
在vue中使用echarts的時候無需 import echarts,可直接使用
第三,按需加載第三方類庫
比如,項目中使用了 lodash 庫,如果不是大量使用裏面的方法的話,可以這樣引入
import _cloneDeep from 'lodash/difference' // 或者 const _cloneDeep = require('lodash/difference')
const o = _cloneDeep ({a: 1, b: 2})
也可以藉助第三方插件的形式,lodash-webpack-plugin和babel-plugin-lodash。
在使用中還是採用原有的 import _ from 'lodash'方式,只是藉助插件,在打包時webpack會根據使用的方法按需打包
先安裝依賴
npm install lodash-webpack-plugin babel-plugin-lodash -D
上述插件可能部分已經存在於項目中,可以根據實際刪除
接着修改 vue.config.js
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
return{
plugins: [
new LodashModuleReplacementPlugin(), //優化lodash
]
}
}
}
};
附:使用 IgnorePlugin 插件優化 moment.js
const webpack = require('webpack');
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
return{
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // 忽略/moment/locale下的所有文件
]
}
}
}
};
按需引入 element-ui,參見官方文檔即可,其他組件庫類似
注:如果是按需一次性在main.js中引入,雖然比全部引入要小一些,但是也會一定程度上影響首次加載,這個看項目而行吧。
按需引入後element-ui
小了很多,不過看到文章開頭的圖上顯眼的 table.js
後想到, table
組件只有後臺管理頁面用到了,不需要全局註冊,所以我們刪除 main.js
中 Table
和 TablColumn
的引用,並在後臺組件中局部註冊。
這裏處理的思路就是,將按需引入處理到極致。如果是對首屏要求很高,可以採用這種方式,哪裏用到哪裏才引用,這其實也是平時開發中的一種良好習慣。
chunk.venders.js
。如果是文件爲第三方依賴的打包後文件,在做完這些優化之後,會發現這個文件有顯現的減小。
第四,打包時去掉sourceMap文件
修改 vue.config.js 配置
module.exports = {
productionSourceMap: false
}
第五,將靜態資源使用cdn加載
將項目中的靜態資源js css等放在oss服務器或者其他地方,減小服務器壓力
第六,開啓 gzip壓縮
我在項目中啓用壓縮後,文件大小減少了70%以上,優化效果十分明顯。
下圖是在簡單做了部分優化之後的加載過程(優化開始時忘了截圖),耗時8s以上。服務器端配置以 nginx 爲例
如果 Nginx 服務器開啓 gzip,會將靜態資源在服務端進行壓縮,壓縮包傳輸給瀏覽器後,瀏覽器再進行解壓使用,這大大提高了網絡傳輸的效率,尤其對 js,css 這類文本的壓縮,效果很明顯。
客戶端
安裝依賴
npm i -D compression-webpack-plugin
修改 vue.config.js 配置
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')
module.exports = {
...
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new CompressionPlugin({
test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png/, // 需要壓縮的文件類型
threshold: 10240, // 歸檔需要進行壓縮的文件大小最小值,這裏是10K以上的進行壓縮
deleteOriginalAssets: false // 是否刪除原文件
})
]
}
}
}
}
打包後,查看js文件
可以看到所有文件都被壓縮了三分之二以上
在服務器我們也要做相應的配置
# 開啓|關閉 gzip。
gzip on|off;
# 文件大於指定 size 才壓縮,以 kb 爲單位。
gzip_min_length 10;
# 壓縮級別,1-9,值越大壓縮比越大,但更加佔用 CPU,且壓縮效率越來越低。
gzip_comp_level 2;
# 壓縮的文件類型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
# 開啓後如果能找到 .gz 文件,直接返回該文件,不會啓用服務端壓縮。
gzip_static on|off
# 是否添加響應頭 Vary: Accept-Encoding 建議開啓。
gzip_vary on;
# 請求壓縮的緩衝區數量和大小,以 4k 爲單位,32 爲倍數。
gzip_buffers 32 4K;
注:遇到服務端開啓gzip後,並沒有生效的問題,發現是nginx配置壓縮文件類型時 application/x-javascript,如果是這樣的寫法則並不會生效。
JavaScript的MIME類型通常爲“application/x-javascript”, 非IE的瀏覽器認“application/javascript”,
所以在上述配置中 application/javascript 和 application/x-javascript 並用,可以解決該問題。
然後重啓nginx服務
systemctl restart nginx.service
當在請求中出現如下標識,即開啓成功
再對比一下資源加載時間
前者爲啓用壓縮前,後者爲壓縮後,時間從8.33s減少到了2.44s,效率提高了70%以上
第七,冗餘代碼
打包文件 app.哈希.js 中爲所有vue文件打包的集合。
基於此,把項目中的冗餘代碼,註釋的多餘代碼刪除一通後,你會發現文件會變小。
可能人就是這樣,在項目中覺得多幾行css 多幾個標籤覺得不會對頁面產生什麼影響,但是如果做一通優化之後看到了‘數字性’的減少,纔會思考編寫高性能代碼對加載性能的影響。
第八,瀏覽器緩存
瀏覽器緩存可以分爲強緩存和協商緩存,根據實際應用場景來選擇緩存方式或者結合使用。一般來講一些基本不會變化的靜態資源文件可以設置強緩存,更新頻繁的文件不要設置緩存。而啓用緩存的好處在於,在某個時間段內可以減少發送請求的數量,從而使頁面響應更快,也就有更好的頁面體驗。
基本原理:瀏覽器緩存分強緩存和協商緩存,他們是將網絡資源存儲在本地,等待下次請求該資源時,如果命中就不需要到服務器重新請求該資源,直接在本地讀取該資源。
- 強緩存:在web服務器返回的響應中添加Expires和Cache-Control Header
- 協商緩存:通過【Last-Modified, If-Modified-Since】和【ETag, If-None-Match】兩對Header分別管理
關於緩存的詳細介紹,推薦一篇文章,時空隧道
好啦,文章提到的優化方式基本就是這些,當然優化也不至於此,還有網絡加載優化、頁面渲染優化(動畫、重排、重繪等)、瀏覽器文件緩存等等。如果有更好的優化方式歡迎評論。
寫在最後,頁面優化本身是一件很抽象的工作,但是我們卻可以通過平時的編碼規範來促成更可靠的頁面。優化的過程也是一個見仁見智的過程,要結合實際項目實際分析。優化的過程也會引發我們對於編碼時的一些思考,原來這樣寫對頁面加載會更友好,不知不覺中也能促進編寫高可用的能力。