React如何經過Webpack優雅的接入serviceWorker的成熟方案workBox && Google Analytics

  • 背景介紹:

爲了提升React應用的啓動速度、離線訪問能力, 作到頁面能離線啓動、service worker能在後臺默默更新本地緩存的頁面、數據的版本,而且作到監控版本更新能力的靠譜性。html

終極方案:採用serviceWorker的成熟方案workBox經過Webpack的workbox官方插件workbox-webpack-plugin作到頁面能離線啓動、service worker能在後臺默默更新本地緩存的頁面、數據的版本, 經過Google Analytics作到監控版本更新能力的靠譜性(上報應用版本)。react

簡單來講就是: workbox-webpack-plugin 和 Google Analytics 的故事。webpack

進入正題以前, 先來一些開胃菜:web

  • PWA(Progressive Web Apps)npm

    • 藉助 Service Worker 緩存網站的靜態資源,甚至是網絡請求,使網站在離線時也能訪問。而且咱們可以爲網站指定一個圖標添加在手機桌面,實現點擊桌面圖標便可訪問網站。
  • serviceWorkerapi

    • serviceWorker僅支持本地(localhost/127.0.0.x)的http協議和帶有安全證書的https協議瀏覽器

    • Service Worker 是瀏覽器在後臺獨立於網頁運行的腳本。是它讓 PWA 擁有極快的訪問速度和離線運行能力。緩存

  • workBox安全

    • 其實能夠把 Workbox 理解爲 Google 官方的 PWA 框架,它解決的就是用底層 API 寫 PWA 太過複雜的問題。這裏說的底層 API,指的就是去監聽 SW 的 install、active、 fetch 事件作相應邏輯處理等。
  • workbox-webpack-plugin網絡

    • webpack經過配置插件(緩存策略), 簡易接入workBox。

目錄

workbox-webpack-plugin

  • 安裝
  • 配置接入 (重點踩坑)
  • 解析配置

React如何接入Google Analytics, 作到監控離線的應用版本

  • 封裝GA組件
  • 配置GA, 上報數據及版本
  • 後臺查看上報的數據 (重點採坑)

甜品一: workbox-webpack-plugin

官方文檔: developers.google.com/web/tools/w…

  • 安裝: npm install workbox-webpack-plugin -D

  • 配置: webpack插件中使用~

webpack配置中引入插件

const { GenerateSW } = require('workbox-webpack-plugin')

exports.override = (webpackConfig, options) => {

  webpackConfig.plugins.push(new GenerateSW({
    swDest: 'workboxServiceWorker.js', // 注意點1: 不寫這個名字, 插件默認會生成 service-worker.js 這個文件,而後不知道WHO又生成了一次service-worker.js這個文件(內容不是workbox預期), 因此webpack生成的workbox的腳本就這樣被替換了! 致使插件配置好的文件其實沒被寫出!!!
    
    // 當咱們每次訪問網站時都會去下載這個文件,當發現文件不一致時,就會安裝這個新 Service Worker ,安裝成功後,它將進入等待階段。

    importWorkboxFrom: 'disabled', // 可填`cdn`,`local`,`disabled`, 區別下面整理
    importScripts: 'https://fds.api.x.net/workbox-cdn/workbox-sw.js', // 我從本身的cdn引入了workbox,這樣就不用每一個項目都上傳

    // 這三個都寫true
    skipWaiting: true, // 新 Service Worker 安裝成功後須要進入等待階段,skipWaiting: true 將使其跳過等待,安裝成功後當即接管網站。
    clientsClaim: true, // 當即接管
    offlineGoogleAnalytics: true, // 離線也記錄ga數據, 有網了再上報的意思。
    cleanupOutdatedCaches: true,  // 嘗試刪除老版本緩存
    // 緩存規則, 具體下面記錄, 更詳細的請查閱文檔。 目前只緩存api
    runtimeCaching: [
      {
        urlPattern: /^https:\/\/easy-mock\.com\//,
        handler: 'NetworkFirst',
        options: {
          cacheName: 'cached-api',
          networkTimeoutSeconds: 2,
          expiration: {
            maxEntries: 50,
            maxAgeSeconds: 1 * 24 * 60 * 60, // 1 day
          },
          cacheableResponse: {
            statuses: [0, 200],
          },
        },
      },
    ],
  }))
  
  return webpackConfig
}

複製代碼
  • 在react入口js的代碼裏註冊代碼, 你也能夠選擇在public下的index.html模板裏的script標籤裏寫(別說我教大家的)
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    // 敲黑板, 這裏的/workbox/workboxServiceWorker.js須要根據實際狀況變化, 由於我項目沒部署到根域名, 因此加了workbox的路徑名...
    // 注意: 這裏有個坑 workboxServiceWorker 會被緩存, 解決方案在下面的坑點介紹
    navigator.serviceWorker.register('/workbox/workboxServiceWorker.js').then(registration => {
      console.log('SW registered: ', registration)
    }).catch(registrationError => {
      console.log('SW registration failed: ', registrationError)
    })
  })
}
複製代碼

坑點:

  1. swDest: 'workboxServiceWorker.js'

官方文檔中, 這個選項是可選填, 默認值爲: service-worker.js。我遇到的問題是, 若是不寫這個從新寫出一個文件, 不知道是哪一個"B", 也寫出了一個叫service-worker.js的文件, workBox的先寫出來了, 而後又被一個同名文件寫出覆蓋了! 而後你自認爲接入了workbox, 實際上你不知道你接入的是啥。(有可能這個文件也是workbox寫出的,可是的確不是我想要的,雖然能實現緩存,但怎麼實現的,以及實現的徹底不是你想要的效果, 它徹底沒有引入workbox, 對, 故事就是這樣。)

  1. importWorkboxFromimportScripts

    importWorkboxFrom能夠選填三個值: cdn,local,disabled

    • cdn: 引入google的官方cdn, 後果是國內用戶打開網站, 一臉懵逼的被牆 (因此確定不能用這個默認值!!!)
    • local: workbox人性化的在本地寫出了workbox的代碼, 而後和項目代碼一塊兒上傳部署就ok, 但每一個項目都要這樣, 就很麻煩。
    • disabled: 傲嬌的不從谷歌引入, 也不導出的本地。但若是你不配置: importScripts 的引入地址, 那將一臉懵逼。

    因此我最終的方案:

    importWorkboxFrom: 'disabled',
    importScripts: 'https://fds.api.x.net/workbox-cdn/workbox-sw.js', // 把local模式導出的文件, 先部署獲取到cdn連接, 在寫死就ok
    複製代碼
  2. runtimeCaching: 具體的運行時緩存策略經過這個選項配置, 具體的須要實戰或者根據本身的業務調整, 注意下面第四點, runtimeCaching中無需放置代碼頁面的緩存

  3. 緩存分爲precacherunningCache, 打包以後的代碼, 會本身加入到precache中, 因此無需再運行時配置緩存資源, 好比:

具體預緩存的文件能夠看precache-manifest.xxxxxx.js

在文檔中搜索precache, 有更多能夠配置的, 好比: include/exclude || chunks/excludeChunks

// 不必!!!
runtimeCaching: [{
  // cdn資源,這個本來想緩存的是代碼,實則已經被預緩存了
  urlPattern: new RegExp('^https://cdn.net'),
  handler: 'staleWhileRevalidate',
  options: {
    cacheableResponse: {
      statuses: [200],
    },
  },
},]
複製代碼
  1. 瀏覽器兼容坑點:

測試了PC端: 谷歌, 火狐, QQ瀏覽器, UC瀏覽器 || 移動端: QQ瀏覽器, miui瀏覽器

  • 谷歌, 火狐正常, 能更新最新版本緩存以及更新頁面 (當發現代碼有變化的時候)
  • QQ瀏覽器 || UC瀏覽器: 這兩個傻蛋, 把最主要的workboxServiceWorke.js這個文件竟然自動硬盤緩存了!!! 致使讀取不到最新的代碼版本, 去獲取最新版的代碼!

QQ和UC緩存失敗的緣由

解決方案

方法一:

`/workbox/workboxServiceWorker.js?${Date.now()}` // 在workboxServiceWorker.js 後加上時間戳, 禁止被緩存!!!
複製代碼

方法二: FDS上配置workboxServiceWorker.js的響應頭, 禁止緩存

解析配置

主要解析runtimeCaching中的緩存策略 (只在demo中測試, 沒接正式項目, 不知道有沒有更多的坑點)

  • Stale While Revalidate (主要)

    這種策略的意思是當請求的路由有對應的 Cache 緩存結果就直接返回,在返回 Cache 緩存結果的同時會在後臺發起網絡請求拿到請求結果並更新 Cache 緩存,若是原本就沒有 Cache 緩存的話,直接就發起網絡請求並返回結果,這對用戶來講是一種很是安全的策略,能保證用戶最快速的拿到請求的結果,可是也有必定的缺點,就是仍是會有網絡請求佔用了用戶的網絡帶寬。

    用來作CSS,JS,PNG等資源的策略, 以爲蠻好。

    Stale While Revalidate

  • Network First (次主要)

    這種策略就是當請求路由是被匹配的,就採用網絡優先的策略,也就是優先嚐試拿到網絡請求的返回結果,若是拿到網絡請求的結果,就將結果返回給客戶端而且寫入 Cache 緩存,若是網絡請求失敗,那就讀取Cache中的數據,這種策略通常適用於返回結果不太固定或對實時性有要求的請求,爲網絡請求失敗進行兜底。

    用來作API接口的,也許就是這樣。

    Network First

  • Cache First

    這個策略的意思就是當匹配到請求以後直接從 Cache 緩存中取得結果,若是 Cache 緩存中沒有結果,那就會發起網絡請求,拿到網絡請求結果並將結果更新至 Cache 緩存,並將結果返回給客戶端。這種策略比較適合結果不怎麼變更且對實時性要求不高的請求。

    Cache First

  • Network Only

    比較直接的策略,直接強制使用正常的網絡請求,並將結果返回給客戶端,這種策略比較適合對實時性要求很是高的請求。

    Network Only

  • Cache Only

    這個策略也比較直接,直接使用 Cache 緩存的結果,並將結果返回給客戶端,這種策略比較適合一上線就不會變的靜態資源請求。( - - 你敢肯定不會變嗎...)

    Cache Only

甜品二: React如何接入Google Analytics, 作到監控離線的應用版本

React項目接入GA, 封裝GA, 使用了react-ga

GA官方上報的字段及含義: developers.google.com/analytics/d…

import React from 'react'
import ReactGA from 'react-ga'

// eslint-disable-next-line
export default function withTracker(WrappedComponent, option = {}) {
  const trackingId = 'UA-xxxxxxx-x'
  const trackPage = page => {
    ReactGA.initialize(trackingId, {
      gaOptions: {
        siteSpeedSampleRate: 100, // 上報網站速度的比例, 默認10%, 若是網站量比較大, 那就不用設置100%了。
      },
    })
    const app = {
      appName: 'workBoxDemo',
      appVersion: '1.3',
    } // 上報版本
    console.log(app)
    ReactGA.set(app)
    ReactGA.pageview(page)
  }
  // eslint-disable-next-line
  const HOC = class extends React.Component {
    componentDidMount() {
      const page = this.props.location.pathname
      trackPage(page)
    }

    componentWillReceiveProps(nextProps) {
      const currentPage = this.props.location.pathname
      const nextPage = nextProps.location.pathname

      if (currentPage !== nextPage) {
        trackPage(nextPage)
      }
    }
    render() {
      return <WrappedComponent {...this.props} /> } } return HOC } 複製代碼

而後在須要引入GA的頁面的react加上withTracker修飾器便可~

withTracker

後臺查看上報的數據

添加方法: ( 自定義->自定義報告 )

後臺查看上報的數據

效果
相關文章
相關標籤/搜索