1. 程式人生 > >淺談自己知道的首屏載入時間的優化策略

淺談自己知道的首屏載入時間的優化策略

縮小webpack或者其他打包工具生成的包的大小

為了做到這一點,需要做到儘可能的減少生產環境下依賴的庫數量,儘可能的按需引用,減少無用程式碼佔的空間。
我剛開始優化的時候,就不知道從何處優化起,而且根本不知道生成的包中哪個依賴佔據著空間,我還一度挨個刪去庫引用,來看哪個庫佔用的空間最多。 後來才知道有名叫:webpack-bundle-analyzer的分析工具,接下來我順帶總結一下這個包的使用姿勢。
: 首先

npm install --save-dev webpack-bundle-analyzer

然後在webpack.prod.conf.js中配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin(
     {
          analyzerMode: 'server',
          analyzerHost: '127.0.0.1',
          analyzerPort: 8888, // 執行後的埠號
          reportFilename: 'report.html',
          defaultSizes: 'parsed',
          openAnalyzer: true,
          generateStatsFile: false,
          statsFilename: 'stats.json',
          statsOptions: null,
          logLevel: 'info'
        }
     ),
]

配置就完成了,正常npm run build 結束後,就會自動開啟一個打包生成檔案的模組組成圖在預設瀏覽器中,圖中面積大的就是佔據空間大的模組。
這裡寫圖片描述
例如上圖中,我打包後vue模組佔據的空間最大,可以根據這張圖去做優化,不會再感到優化無從下手了。

另外再記錄一個我在使用element-ui時遇到的包過大的坑,如果在開發時,將element-ui全域性引入,打包後的vendor包大小至少700kb以上,相當龐大,然後我就進行了區域性應用。
我的main.js檔案區域性程式碼如下

import {
  Autocomplete,
  Checkbox
  ……
} from 'element-ui'
Vue.
use(Autocomplete); Vue.use(Checkbox);

結果打包後包大小沒有發生任何變化,一直找不到問題。後來發現官方文件上還需要安裝babel-plugin-component外掛才能使區域性引用有效,以後看文件一定要細心才行。

使用服務端渲染的方式

這個服務端渲染不同於後端渲染,服務端渲染只是把當前的前端框架中的一部分js程式碼放到伺服器上渲染,載入到瀏覽器上的html就不是一個空頁面,這樣可以減少首頁的白屏時間,同時提高被搜尋引擎檢索的機會。
但是這個服務端渲染有不少的侷限,例如它的服務端必須依靠node伺服器,不進行服務端渲染方式的只需要一個普通的靜態伺服器就可以了。還有,vue官方的ssr配置異常的複雜,需要花不少的時間,踩不少的坑,如果開發時使用的vue-cli的話,改用服務端渲染會很麻煩。如果必須要使用服務端渲染的話,最好剛開始就使用基於vue的nuxt.js腳手架去開發,會減去繁瑣的配置過程。

使用預渲染的方式

這個預渲染的方式簡單來說就是在正常打包時,會預先執行一次js程式碼,將一部分靜態的頁面直接渲染成html寫在生成的index.html中,這種方式在載入完index.html後,就會有介面展示出來,無需等待載入js程式碼後再去渲染,所以這種方式也可以顯著的減少首屏載入時間,也可以提高被搜尋引擎檢索的機會,同時預渲染的配置很簡單,容易上手。
缺點是在需要預渲染的頁面較多時,build打包的時間會十分漫長。
預渲染的工具有這些:
prerender-spa-plugin
react-snap
snapshotify
presite

我比較喜歡預渲染這種優化方式,很簡單有效,幾乎不需要什麼配置。這幾種外掛的基本原理都是本地執行指定的js程式碼,然後將空頭瀏覽器渲染出的頁面寫入指定的h5檔案。
但是我自己在做專案的時候,出現了各種各樣的問題。在打包時報出各種各樣的錯誤,解決了一個又出一個,把這幾個外掛都試了一遍,依然沒有成功預編譯出一個滿意的頁面效果,當然這是我個人的問題,與這幾個輪子沒有關係。

最後,我想出了一種“土”辦法,就用自己的瀏覽器去預渲染頁面。
在瀏覽器上開啟需要預渲染的頁面,然後點選右鍵選擇另存為,將檔案儲存下來,就得到了“預渲染”的html檔案。
如果覺得裡面的css程式碼量太大,推薦使用chrome的一個外掛 css used, 下載安裝之後,在開發者工具中的element中,與style選項並排的就有一個css used選項,點選後就會加載出這個頁面用到的css介面,過濾掉了沒有用到的css程式碼,將有用的css程式碼替換掉原本html裡面的css程式碼即可。
最後,需要將打包生成的js和css程式碼的路徑新增到html裡面(就像打包生成的index.html一樣),這樣,在這個html載入完成後,就可以顯示一個預渲染的頁面了,等到依賴的js和css載入完成後,會有新的程式碼覆蓋掉預渲染的頁面。
我的這種“土”辦法實屬無奈,但依舊有效,成功的將首屏載入時間縮短了50%。用這種方法也可以自己製作一個骨架預渲染介面,在等待載入js和css時,介面上只顯示一個頁面的大體框架,比全白屏的互動體驗要好的多。

使用gzip減小網路傳輸的流量大小

gzip是GNUzip的縮寫,最早用於UNIX系統的檔案壓縮。HTTP協議上的gzip編碼是一種用來改進web應用程式效能的技術,web伺服器和客戶端(瀏覽器)必須共同支援gzip。目前主流的瀏覽器,Chrome,firefox,IE等都支援該協議。常見的伺服器如Apache,Nginx,IIS同樣支援gzip。使用gzip可以將原靜態檔案壓縮到30%,效果很明顯,對於優化首屏載入時間非常適合。
這種優化實現特別簡單,只需要配置一下自己使用的伺服器就可以了。
以我使用的nginx伺服器的配置為例:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    proxy_buffering on;
    # 開啟gzip
	gzip on;
	# 啟用gzip壓縮的最小檔案,小於設定值的檔案將不會壓縮
	gzip_min_length 1k;
	# gzip 壓縮級別,1-10,數字越大壓縮的越好,也越佔用CPU時間
	gzip_comp_level 2;
	# 進行壓縮的檔案型別。javascript有多種形式。其中的值可以在 mime.types 檔案中找到。
	gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml;
	# 是否在http header中新增Vary: Accept-Encoding,建議開啟
	gzip_vary on;
	# 禁用IE 6 gzip
	gzip_disable "MSIE [1-6]\.";
	server {
        listen       80;
        server_name  localhost;
        location /{
            alias /;
            proxy_connect_timeout 1; 
            proxy_send_timeout 30; 
            proxy_read_timeout 60;
            # 這裡反向代理到本地的開發伺服器上
            proxy_pass http://localhost:8080/;
         }
    }
}

這樣就開啟了gzip。

按照頁面或者元件分塊懶載入

這種優化,就是將每個元件的js程式碼獨立出來,在使用到這個元件時,才向伺服器請求檔案,並且請求過一次後就會快取下來,再次使用到這個元件時,就會使用快取,不再發送請求。
配置很簡單,只需要在vue-router中新增一些簡單的配置即可。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router);

export default new Router({
  mode: 'history',
  linkActiveClass: 'router-link-active',
  routes: [
    {
      path: '/',
      // 這裡只需要把原來從外部引入的元件換成以下的語句就可以了
      component: resolve => require(['../components/(你的元件)'], resolve)
    },
  ]
})

其他地方不需要進行任何修改,打包後就會發現js檔案數量比原來不分塊載入的多了不少。

以上就是我知道或者用過的針對單頁面應用的首屏載入時間優化方法,如果還有別的方法,歡迎指出和討論。

寫作和分享不易,我只求一個贊~