藉助 workbox 將網站升級成 PWA

PWA(Progressive Web Apps)是谷歌近幾年一向在推動的 web 運用新模子。PWA 藉助 Service Worker 緩存網站的靜態資本,以至是收集要求,使網站在離線時也能接見。而且我們可以為網站指定一個圖標增加在手機桌面,完成點擊桌面圖標即可接見網站。

Web App Manifest

Web App Manifest 是一個 JSON 文件,它用來定義網站增加到桌面的圖標以及從桌面圖標進入網站時的一系列行動,如:啟動款式,全屏主題等。

先建立 manifest.json

{
  "name": "blog-pwa",
  "short_name": "blog-pwa",
  "icons": [
    {
      "src": "/img/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/img/icons/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#000000",
  "theme_color": "#4DBA87"
}

將文件引入:

<link rel=manifest href=/manifest.json>

我們可以從開發者東西上看我們的設置:

《藉助 workbox 將網站升級成 PWA》

icons 屬性定義了增加到桌面的圖標, display: standalone 示意我們要從桌面全屏啟動,theme_color": "#4DBA87 是全屏啟動時手機頂部狀態欄的背景色,background_color": "#000000 是啟動頁的背景色,啟動頁如今不能定製,默許由 background_coloriconname 組合而成。

Web App Manifest很簡樸,只需照着文檔每一個屬性看一遍就行。

Service Worker

Service Worker 是瀏覽器在後台獨立於網頁運轉的劇本。是它讓 PWA 具有極快的接見速率和離線運轉才。

那它是怎樣做到的呢?我們一步步來看。

註冊 Service Worker

if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/service-worker.js')
    .then(registration => {
      console.log(
        'ServiceWorker registration successful with scope: ',
        registration.scope
      )
    })
    .catch(err => {
      console.log('ServiceWorker registration failed: ', err)
    })
}

須要注重的是,Service Worker 劇本除了域名為 localhost 時能運轉在 http 協定下之外,只能運轉 https 協定下。

裝置

const CACHE_NAME = 'cache-v1'
const DATA_CACHE_NAME = 'data-cache-v1'

const PRE_CACHE = ['/index.html', '/css/app.css', '/js/app.js']

self.addEventListener('install', e => {
  console.log('[ServiceWorker] Install')
  e.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll(PRE_CACHE)
    })
  )
})

在裝置的時刻預緩存網站的靜態資本,任何資本途徑失足都邑形成 Service Worker 裝置失利。

代辦要求

self.addEventListener('fetch', e => {
  e.respondWith(
    caches.match(e.request).then(response => {
      if (response) {
        return response
      }

      const fetchRequest = e.request.clone()

      return fetch(fetchRequest).then(response => {
        // Check if we received a valid response
        if (!response || response.status !== 200) {
          return response
        }

        const responseToCache = response.clone()

        caches.open(DATA_CACHE_NAME).then(cache => {
          cache.put(e.request, responseToCache)
        })

        return response
      })
    })
  )
})

裝置勝利后,Service Worker 就可以監聽網站的一切要求,婚配到緩存時直接返回,未婚配到時要求效勞器,效勞器勝利返回時增加到緩存。

更新

如今網站的 Service Worker 已可以一般事情了,那怎樣更新它呢?

我們只須要修正 Service Worker 文件就可以更新它。當我們每次接見網站時都邑去下載這個文件,當發明文件不一致時,就會裝置這個新 Service Worker ,裝置勝利后,它將進入守候階段。當我們封閉窗口從新導航到網站時(革新網頁不可),新 Service Worker 將最先掌握網站。舊 Service Worker 停止事情並觸發 activate 事宜:

self.addEventListener('activate', e => {
  e.waitUntil(
    caches.keys().then(keyList => {
      return Promise.all(
        keyList.map(key => {
          if (key !== CACHE_NAME && key !== DATA_CACHE_NAME) {
            console.log('[ServiceWorker] Removing old cache', key)
            return caches.delete(key)
          }
        })
      )
    })
  )
})

在其卸載時一定要刪除舊緩存,不然我們的網站永久沒法更新。

上面只簡樸講了 Service Worker 怎樣事情。我們會發明有許多題目須要我們進一步處理:

  1. 預緩存的靜態資本修正後鄙人一次發版本時的文件名都不一樣,手動寫死太低效,最好每次都自動天生資本文件名。
  2. 緩存資本是以硬編碼字符串推斷是不是有用,如許每次發版本都須要手動修正,才更新緩存。而且每次都是全量更新。可否以文件的粒度舉行資本緩存呢?
  3. 要求代辦沒有辨別靜態資本和動態接口。已緩存的動態接口也會一向返回緩存,沒法要求新數據。

上面只列出了三個顯著的題目,另有許多題目是沒有考慮到的。假如讓我們本身來處理這些題目,不僅是事情量很大,而且也很難寫出臨盆環境可用的 Service Worker

workbox

既然如此,我們最好是站在偉人的肩膀上,這個偉人就是谷歌。workbox 是由谷歌瀏覽器團隊宣布,用來輔佐建立 PWA 運用的 JavaScript 庫。固然直接用 workbox 照樣太龐雜了,谷歌還很知心的宣布了一個 webpack 插件,可以自動天生 Service Worker 和 靜態資本列表 – workbox-webpack-plugin

只需簡樸一步就可以天生臨盆環境可用的 Service Worker

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

new GenerateSW()

打包一下:

《藉助 workbox 將網站升級成 PWA》

還能說什麼呢?谷歌大法好!固然這隻是最簡樸的可用版本,實在這裡有一個最嚴峻的題目不知道有沒人發明,那就是 importScripts 援用的是谷歌域名下的 cdn ,這讓我們牆內的網站怎樣用,所以我們須要把這個題目處理並自定義一些設置加強 Service Worker 的才:

new GenerateSW({
  importWorkboxFrom: 'local',
  skipWaiting: true,
  clientsClaim: true,
  runtimeCaching: [
    {
      // To match cross-origin requests, use a RegExp that matches
      // the start of the origin:
      urlPattern: new RegExp('^https://api'),
      handler: 'staleWhileRevalidate',
      options: {
        // Configure which responses are considered cacheable.
        cacheableResponse: {
          statuses: [200]
        }
      }
    },
    {
      urlPattern: new RegExp('^https://cdn'),
      // Apply a network-first strategy.
      handler: 'networkFirst',
      options: {
        // Fall back to the cache after 2 seconds.
        networkTimeoutSeconds: 2,
        cacheableResponse: {
          statuses: [200]
        }
      }
    }
  ]
})

起首 importWorkboxFrom 我們指定從當地引入,如許插件就會將 workbox 一切源文件下載到當地,牆內開發者的福音。上面提到過新 Service Worker 裝置勝利后須要進入守候階段,skipWaiting: true 將使其跳過守候,裝置勝利后馬上接受網站,注重這個要和 clientsClaim 一同設置為 trueruntimeCaching 望文生義是設置運轉時怎樣緩存要求的,這裏只說一點,緩存跨域要求時 urlPattern 的值必需為 ^ 開首的正則表達式,別的的設置看文檔都能獲得細緻的引見。

再打包一次:

《藉助 workbox 將網站升級成 PWA》

如今我們就可以將打包好的代碼布置到網站上了,源碼在這,末了再上幾張圖:

《藉助 workbox 將網站升級成 PWA》

《藉助 workbox 將網站升級成 PWA》

參考

Web App Manifest

效勞事情線程:簡介

效勞事情線程生命周期

workbox-webpack-plugin

    原文作者:hugo_seth
    原文地址: https://segmentfault.com/a/1190000015050724
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞