1. 程式人生 > >Service worker (@nuxtjs/workbox) 採坑記

Service worker (@nuxtjs/workbox) 採坑記

PWA(Progressive Web App)是前端的大趨勢,它能極大的加快前端頁面的載入速度,得到近乎原生 app 的展示效果(其實難說)。PWA 其實是多種前端技術的組合,其中最重要的一個技術就是 service worker。

Service workers 本質上充當Web應用程式與瀏覽器之間的代理伺服器,也可以在網路可用時作為瀏覽器和網路間的代理。它們旨在(除其他之外)使得能夠建立有效的離線體驗,攔截網路請求並基於網路是否可用以及更新的資源是否駐留在伺服器上來採取適當的動作。他們還允許訪問推送通知和後臺同步API。

其實不用太糾結,簡單起見我們就把它當成更高階更先進的 AppCache 就好了。

在 nuxt(Vue) 網站中啟用 Service worker

借近期公司官網升級之機,我也給公司官網上了 Service worker 做離線快取。

大前提:Service worker 只可在 https(或 localhost)下使用,首先確保你的網站上了 https

在 nuxt 程式中啟用 Service worker 非常方便。nuxt 提供了官方 module——pwa-module 用於支援 PWA 網站,其中就包含了用於實現 Service worker 的 workbox moduleworkbox 實際上是指的 google 為簡化 Service worker 開發而開源的第三方庫。

首先安裝依賴

$ yarn add @nuxtjs/pwa @nuxtjs/workbox

然後再配置檔案中啟用

// modules
module.exports = {
  [ '@nuxtjs/pwa' ]
}

就完成了

SW 使用採坑

官網上線後發現,啟用 Service worker 後 Safari 不能播放視訊了。但是直接輸入視訊連結卻可以播放。經過各種 google 搜尋查資料後找到了官方 issue:

狀態始終是 new,沒有人解決。但 issue 中詳細說明了 Safari 的行為以及產生問題的原因

問題的原因在於對於視訊檔案請求,瀏覽器會發出帶有 Range 頭的請求部分獲取檔案內容。Safari 比較奇葩,對於視訊檔案請求,它一開始就會發一個 Range: 0-1

的請求,但是 Service worker 中處理請求的邏輯不能識別 Range 請求,把 Range 請求當成普通請求處理,返回了 200。Safari 把 200 當成了失敗請求,導致請求視訊檔案失敗。

然後經過各種嘗試(中間過程略),說一下可行方案:

首先新增 js plugin:

// workbox-range-request.js
workbox.routing.registerRoute(
  /.*\.(mp4|webm)/,
  workbox.strategies.cacheFirst({
    plugins: [
      new workbox.rangeRequests.Plugin(),
    ],
  }),
  'GET'
);

這個檔案給 workbox 註冊一個路由,指定對於視訊檔案(以 .mp4 或 .webm 結尾的檔案。如果你的網站有音訊檔案也要一併處理)處理程式新增 rangeRequests 外掛

然後在配置檔案中註冊外掛:

// modules:
[ '@nuxtjs/pwa', {
  workbox: {
    cachingExtensions: '@/plugins/workbox-range-request.js',
  }
} ],

注意必須使用 cachingExtensions 而不能用 routingExtensions,雖然註冊的是路由配置

這樣 Service worker 就可以處理帶 Range 頭的請求了,但是還不算完。workbox 會請求 googlecdn 動態載入 js 指令碼,如果你身在兲朝,由於眾所周知的原因載入指令碼會失敗。

解決方案:

  1. 解壓後放在你專案的 static 資料夾下,筆者是 static/workbox-v3.5.0
  2. 修改配置
// modules:
[ '@nuxtjs/pwa', {
  meta: false,
  workbox: {
    config: { modulePathPrefix: '/workbox-v3.5.0' },
    cachingExtensions: '@/plugins/workbox-range-request.js',
  }
} ],

配置中指定 workbox 從 /workbox-v3.5.0 這個路徑載入 js 指令碼,而不走 googlecdn。

注意配置中使用的 config 當前版本(2018-09-20)還不支援,筆者給官方倉庫開了 Pull request 還在稽核中,筆者是直接修改了 node_modules 裡的檔案。

在上 Service worker 之前最好想清楚。這玩意和 AppCache 一樣,上線簡單,想要下線就難了