天天看點

PWA 漸進式實踐 (2) - Service Worker添加 Service Worker離線依然傳回 200What’s next

作為 PWA 的象征之一,我們首先做的,就是加上 Service Worker。

添加 Service Worker

注冊

我們的項目是使用 ejs 在 webpack 階段注入幾個變量生成最後的 index.html 的,是以直接拿 index.ejs 動刀即可:

<body>
  <div id="container"></div>
  <script src="<%= bundle %>"></script>
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/service-worker.js', {
        scope: './'
      }).then(function(registration) {
        registration.onupdatefound = function() {
          if (navigator.serviceWorker.controller) {
            const installingWorker = registration.installing;
            installingWorker.onstatechange = function() {
              switch (installingWorker.state) {
                case 'installed':
                  break;
                case 'redundant':
                  throw new Error('The installing ' +
                    'service worker became redundant.');
                default:
                // Ignore
              }
            };
          }
        };
      }).catch(function(e) {
        console.error('Error during service worker registration:', e);
      });
    } else {
      console.log('service worker is not supported');
    }
  </script>
           

即 body 中,第二個 script 标簽的内容,其參數 service-worker.js,是與 index.html 在同一個目錄的空檔案:

// This file is intentionally without code.
// It's present so that service worker registration
// will work when serving from the 'public' directory.
           

實際上打包後會生成真正的 service-worker.js,是以現在隻是用來占個位子。

納尼?這樣就好了?

确實,這樣,我們就已經完成了注冊,這也是 PWA 和微信小程式這種二流方案不同的地方,其更注重于如何提高現有設計實作下的體驗,使用開放的标準并進行推進。

Cache 政策

下一步就是增加我們的緩存政策了,我們需要安裝 2 個小工具:

npm install sw-precache --save
npm install sw-toolbox --save
           

然後在 package.json 裡面更新一下我們的 script:

"scripts": {
  "build": "npm run copy && node run build && npm run precache",
  "build:debug": "npm run copy && node run build --debug && npm run precache",
  "copy": "cp node_modules/sw-toolbox/sw-toolbox.js public/sw-toolbox.js",
  "precache": "./node_modules/sw-precache/cli.js --root=public --config=sw-precache-config.json"
}
           

如上,增加 copy 和 precache 任務,并更新 build,在 build 前後插入新的 task。

然後就是配置檔案了,在項目目錄下,增加

sw-precache-config.json

檔案:

{
  "staticFileGlobs": [
    "public/dist/**.css",
    "public/dist/**.png",
    "public/dist/**.js"
  ],
  "importScripts": [
    "sw-toolbox.js",
    "runtime-caching.js"
  ],
  "stripPrefix": "public/",
  "verbose": true
}
           

在 public 目錄下,增加

runtime-caching.js

檔案:

// global.toolbox is defined in a different script, sw-toolbox.js, which is part of the
// https://github.com/GoogleChrome/sw-toolbox project.
// That sw-toolbox.js script must be executed first, so it needs to be listed before this in the
// importScripts() call that the parent service worker makes.
(function (global) {
  // See https://github.com/GoogleChrome/sw-toolbox/blob/dc328d1f1cfba624269653724b26fa94f1/README.md#toolboxroutergeturlpattern-handler-options
  // and https://github.com/GoogleChrome/sw-toolbox/blob/dc328d1f1cfba624269653724b26fa94f1/README.md#toolboxfastest
  // for more details on how this handler is defined and what the toolbox.fastest strategy does.
  global.toolbox.router.get('/(.*)', global.toolbox.fastest, {
    origin: /\.(?:googleapis|gstatic|firebaseio|appspot)\.com$/,
  });
  global.toolbox.router.get('/(.+)', global.toolbox.fastest, {
    origin: 'https://api.pai.bigins.cn/',
  });
  global.toolbox.router.get('/(.+)', global.toolbox.fastest, {
    origin: 'https://qa.api.pai.bigins.cn/',
  });
  global.toolbox.router.get('/*', global.toolbox.fastest);
}(self));
           

運作一下 npm run build,發現

service-worker.js

被更新了,裡面是生成的政策腳本。

評測

再次運作 Lighthouse 後,發現我們的評分已經嗖嗖嗖上去了:

PWA 漸進式實踐 (2) - Service Worker添加 Service Worker離線依然傳回 200What’s next

離線依然傳回 200

這裡的秘密就在 runtime-caching.js 檔案裡,我們更新一下:

// global.toolbox is defined in a different script, sw-toolbox.js, which is part of the
// https://github.com/GoogleChrome/sw-toolbox project.
// That sw-toolbox.js script must be executed first, so it needs to be listed before this in the
// importScripts() call that the parent service worker makes.
(function (global) {
  // See https://github.com/GoogleChrome/sw-toolbox/blob/dc328d1f1cfba624269653724b26fa94f1/README.md#toolboxroutergeturlpattern-handler-options
  // and https://github.com/GoogleChrome/sw-toolbox/blob/dc328d1f1cfba624269653724b26fa94f1/README.md#toolboxfastest
  // for more details on how this handler is defined and what the toolbox.fastest strategy does.
  global.toolbox.router.get('/(.*)', global.toolbox.fastest, {
    origin: /\.(?:googleapis|gstatic|firebaseio|appspot)\.com$/,
  });
  global.toolbox.router.get('/(.+)', global.toolbox.fastest, {
    origin: 'https://api.pai.bigins.cn/',
  });
  global.toolbox.router.get('/(.+)', global.toolbox.fastest, {
    origin: 'https://qa.api.pai.bigins.cn/',
  });
  global.toolbox.router.get('/(.+)', global.toolbox.fastest, {
    origin: 'https://pai.bigins.cn/',
  });
  global.toolbox.router.get('/*', global.toolbox.fastest);
  global.toolbox.precache(['/index.html', '/index.css', '/img/logo.png']);
}(self));
           

然後再送出建構一下,在 Chrome 的 Network Panel 中,勾選 Offline,然後重新整理頁面,哇,依然可以用诶。

評測

PWA 漸進式實踐 (2) - Service Worker添加 Service Worker離線依然傳回 200What’s next

通過完善 Service Worker,我們的評分已經嗖嗖嗖上了80,達到了83分。

What’s next

PWA 漸進式實踐 (2) - Service Worker添加 Service Worker離線依然傳回 200What’s next

剩下的就是一些比較棘手的性能和體驗問題了,我們下回見。

繼續閱讀