React 出海應用 首屏載入時間從20S降到10S以下 血淚史

文叔叔發表於2019-02-19

最近在做一個基於mobile app的漫畫的專案,面向印尼市場。

網址是www.mangaya.mobi

上線後,基本測試沒有問題,開啟也挺順暢。但是google analytics卻反饋載入平均19s

React 出海應用 首屏載入時間從20S降到10S以下 血淚史

OMG~~於是開展了一系列的探索。。

首先說說技術棧,用的是create-react-app,redux,react-router,webpack4,babel7.

我們知道網頁的載入流程大致如下:

React 出海應用 首屏載入時間從20S降到10S以下 血淚史

那麼優化網頁的載入速度,最本質的方式就是,1.減少請求數量 2.縮小請求體積大小。

減少請求數量

  1. 用base64減少不必要的網路請求,實際上create-react-app已經自動幫我們做了。

React 出海應用 首屏載入時間從20S降到10S以下 血淚史

  1. 引入檔案使用React.Lazy

React 出海應用 首屏載入時間從20S降到10S以下 血淚史

  1. 圖片延遲載入,使用react-lazyload,非常方便。
    React 出海應用 首屏載入時間從20S降到10S以下 血淚史
    React 出海應用 首屏載入時間從20S降到10S以下 血淚史

縮小請求體積大小

  1. 後臺返回的圖片使用webp格式,縮小體積。但是由於webp目前只被安卓支援,所以我們目前的方案是後端獲取請求的user-agent資訊,判斷如果是ios的話,就返回jpg格式的圖片,如果是安卓的話,就返回webp格式。這主要使用在banner圖。

  2. webpack 處理

  • 2.1 build的時候去掉map檔案,減少不必要的檔案以及防止被檢視原始碼

    React 出海應用 首屏載入時間從20S降到10S以下 血淚史

  • 2.2 壓縮css和js,實際上create-react-app已經自動幫我們做了。uglifyjs-webpack-plugin使用的uglify-es已經不再被維護,取而代之的是一個名為terser的分支。

    React 出海應用 首屏載入時間從20S降到10S以下 血淚史

  • 2.3 預設splitChunk是chunks: 'all',但是這樣會導致生成一個很大的vendor檔案,可以改一下,將node檔案抽離出來。

 splitChunks: {
        // chunks: 'all',
        chunks: "all",
        maxInitialRequests: Infinity,
        minSize: 0,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name(module) {
              // get the name. E.g. node_modules/packageName/not/this/part.js
              // or node_modules/packageName
              const packageName = module.context.match(
                /[\\/]node_modules[\\/](.*?)([\\/]|$)/
              )[1];

              // npm package names are URL-safe, but some servers don't like @ symbols
              return `npm.${packageName.replace("@", "")}`;
            }
          }
        },
        name: false
      },
複製程式碼

這樣雖然總的專案大小變大了,但是由於vendor檔案被拆分成多個檔案,根據http1.1或者http2的協議,瀏覽器資源獲取是可以多個並行的,配合cdn,這樣請求資源,反而更快。

  • 2.4 Babel polyfill的按需載入,直接在package.json配置就好了,由於需要支援的機子比較低端,所以設定為支援>0.02%的機型。可參考
"browserslist": [
    ">0.02%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
複製程式碼
  1. gzip壓縮 如果瀏覽器支援gzip壓縮,在傳送請求的時候,請求頭中會帶有Accept-Encoding:gzip。然後伺服器會將原始的response進行gzip壓縮,並將gzip壓縮後的response傳輸到瀏覽器,緊接著瀏覽器進行gzip解壓縮,並最終反饋到網頁上。

React 出海應用 首屏載入時間從20S降到10S以下 血淚史

資源cdn加速

將靜態伺服器改成印尼的伺服器,明顯dns以及靜態資源的傳輸加快。最後就是cdn加速靜態資源了,我把npm包的js都放到cdn上了,之後還可以配置多路cdn等策略。

4.靜態資源快取 加入pwa的service worker

5.字型 由於字型一般比較大,使用 font-display: swap;可以先讓使用者看到本地字型顯示出內容來先,等字型載入下來了,再進行替換。

@font-face {
  font-family: 'Arvo';
  font-display: swap;
  src: local('Arvo'), url(https://fonts.gstatic.com/s/arvo/v9/rC7kKhY-eUDY-ucISTIf5PesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
}
複製程式碼

詳細可檢視font-display

總結

經過一段時間的努力,成功將首次載入時間從19秒變成10秒以下!仍需要繼續。。。

React 出海應用 首屏載入時間從20S降到10S以下 血淚史
同時我們還招募了志願者幫我們測試嘻嘻嘻
React 出海應用 首屏載入時間從20S降到10S以下 血淚史
當然這只是首次的載入的時間問題,後續還有觀看漫畫的優化工作,以及支援http2.0,然後將vendor檔案拆分成多個js檔案加速載入等。

相關文章