PWA之 workbox 学习

前言:
咱们的应用能够分为两部分,一部分是属于主进程的(包括js(同步,异步),以及dom渲染等等),在一个时刻点,只能执行一个,要么先去渲染dom,完了再去执行js;要么执行完js,在去渲染dom,而不能同时执行js和dom渲染。 另外一部分属于worker进程,它从新在后台起了一个进程,它和应用的主进程互不影响,能够同时执行。css

常见的worker有,web worker, service worker, shared worker等等。html

其中service worker通常做为web应用程序、浏览器和网络(若是可用)之间的代理服务。他们旨在建立有效的离线体验,拦截网络请求,以及根据网络是否可用采起合适的行动,更新驻留在服务器上的资源。他们还将容许访问推送通知和后台同步API。用来构建PWA 应用

使用service-worker前,咱们必需要先在主进程中注册它,而后才能在service-worker进程中编写逻辑。vue

主进程react

//index.js
if ("serviceWorker" in navigator) {
    // Use the window load event to keep the page load performant
    window.addEventListener("load", () => {
      navigator.serviceWorker.register("/service-worker.js").then(registration=>{
        console.log("register succces...")
      }, err=>{
        console.log("register error...",err)
      });
    });
  }

service-worker进程jquery

//service-worker.js
console.log('Hello from service-worker.js');
service-worker的语法简介

在service-worker.js中,self/this 表示 ServiceWorkerGlobalScope, 即全局的serviceworker工做环境,至关于在主进程中的window。在此文件中,js的其余api没法使用,如DOM,BOM操做等,可是大部分的js api可用,同时ES6也可使用。webpack

在service-worker中能够定义监听事件,而后在对应事件中进行逻辑处理。web

具体api可查看 service worker MDNchrome

service-worker进程的执行流程npm

  1. 首先在主进程中开始注册,调用register方法,进入sw进程,在sw进程中判断若是尚未安装service worker.js,则触发install事件。开始安装
  2. 一旦sw进程安装完成,会通知主进程register成功。
  3. 接着在sw进程 触发到activate事件。
  4. 若是已经安装过service-worker.js文件,则在注册时会发现并跳过install事件,直接进入注册成功,而后触发activate事件。
  5. 而后开始在sw进程中经过fetch事件,来监听http请求,并对请求和响应进行缓存。
//在service worker中监听install
this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});

除了 install以外,还有 activate,message,fetch,sync,push等事件。json

打开chrome浏览器的application->service workers,会看到
image
能够看到status为 actived and is running,代表service-worker已经安装成功了。

在service-worker中经过监听事件,而后编写对应的逻辑并非一件容易的事,尤为对于文件缓存,可能npm run build后,名称随时会变。

因此chrome官方推出了wokbox框架

clipboard.png

wokbox 是用于向web应用程序添加离线支持的JavaScript库。

要使用wokbox,只需在service-worker.js文件中引入workbox-sw.js便可,而后会自动的在service-worker.js中建立workbox对象,

importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');

if (workbox) {
  console.log(`Yay! Workbox is loaded 🎉`);
} else {
  console.log(`Boo! Workbox didn't load 😬`);
}

在wokbox对象中,包含不少模块,好比 workbox.routing模块,workbox.precaching模块,workbox.strategies模块,workbox.expiration模块等等,它们分别负责处理不一样的逻辑。

一、workbox缓存/预缓存

//缓存文件
workbox.routing.registerRoute(
  /\.css$/,   //经过正则匹配须要缓存哪些文件
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: 'css-cache',  //缓存名,可在application-> Cache storage下找到
  })
);

workbox.routing.registerRoute(
  /\.(?:js)$/,
  new workbox.strategies.CacheFirst({
    cacheName: 'js-cache',
    plugins: [
      //设置过时时间和最大数量
      new workbox.expiration.Plugin({
        maxEntries: 20,
        maxAgeSeconds: 7 * 24 * 60 * 60,
      })
    ],
  })
);

workbox.routing.registerRoute代表 当service-worker在安装以后,当页面有发送对应http请求时,开始缓存。

而下面的workbox.precaching.precacheAndRoute能够在service-worker在安装以前,就把对应文件预先缓存下来。

workbox.precaching.precacheAndRoute([
  "/app.0.css",
  "/app.bundle.js",
  { url: "/start.html", revision: "dd75b1ef1ac2d4726b03fe46e90423f1" }
]);

此时咱们在chrome下的 application->cache storage,会看到
image

缓存的名称,和缓存的文件列表

二、workbox路由

首先了解下处理路由的workbox的策略

  • StaleWhileRevalidate, 此策略将对请求使用缓存响应,并在后台使用网络响应更新缓存。若是没有缓存,它将等待网络响应并使用它),这是一种至关安全的策略,由于这意味着用户会按期更新其缓存。
  • NetworkFirst,这将首先尝试从网络获取请求。若是收到响应,它会将其传递给浏览器并将其保存到缓存中。若是网络请求失败,将使用最后一个缓存的响应。
  • CacheFirst,此策略将首先检查缓存中的响应,若是有可用则使用该策略。若是请求不在缓存中,则将使用网络,而且在传递给浏览器以前,任何有效响应都将添加到缓存中。
  • NetworkOnly,强制从网络获取。
  • CacheOnly,,强制从缓存获取。
workbox.routing.registerRoute(
  '/logo.png',    //匹配字符串路由
  new workbox.strategies.NetworkFirst()    //采用NetworkFirst策略
);
workbox.routing.registerRoute(
  /\.js$/,   // 配置 正则 路由,
  new workbox.strategies.StaleWhileRevalidate(),  //采用StaleWhileRevalidate策略
);
//缓存第三方,好比jquery, 则策略最好使用NetworkFirst或者StaleWhileRevalidate, 不要使用CacheFirst
workbox.routing.registerRoute(
  'https://cdn.bootcss.com/jquery/3.4.1/jquery.js',
  new workbox.strategies.StaleWhileRevalidate(),
  //new workbox.strategies.NetworkFirst(),
); 

//若是非要使用CacheFirst策略,则使用workbox.cacheableResponse.Plugin限定
workbox.routing.registerRoute(
  'https://cdn.bootcss.com/jquery/3.4.1/jquery.js',
  new workbox.strategies.CacheFirst({
    plugins: [
      new workbox.cacheableResponse.Plugin({
        statuses: [0, 200]
      })
    ]
  }),
);
//还能够自定义策略的名称,过时时间等等
workbox.routing.registerRoute(
  /\.(?:js)$/,
  new workbox.strategies.CacheFirst({
    cacheName: 'js-cache',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 20,
        maxAgeSeconds: 7 * 24 * 60 * 60,
      })
    ],
  })
);

在前面咱们看到 cache的名称为 workbox-precache-v2-http://127.0.0.1:8081/,下面咱们修改下

//最好写在紧贴着importScripts workbox-sw.js的下面,若是写在文件最后,则不生效。
workbox.core.setCacheNameDetails({
  prefix: "my-app",
  suffix: "v1",
  precache: "custom-precache-name",
  runtime: "custom-runtime-name"
});

image

三、workbox插件

  • workbox.backgroundSync.Plugin:若是网络请求失败,请将其添加到后台同步队列,并在触发下一个同步事件时重试该请求。
  • workbox.broadcastUpdate.Plugin:每当缓存更新调度时,广播频道上的消息或经过 postMessage()。
  • workbox.cacheableResponse.Plugin:仅缓存符合特定条件的缓存请求。
  • workbox.expiration.Plugin:管理缓存中项目的数量和最长期限。
  • workbox.rangeRequests.Plugin:响应包含Range:标头的请求,其中包含来自缓存的部份内容。

四、workbox debug

importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts("precache-manifest.7df9e91fe595ae52486747ebe221a710.js");

//强制在service worker中使用debug。这样service worker中的log也能打印到chrome console上
workbox.setConfig({
  debug: true
});

image

四、在webpack中 集成 workbox,来自动的生成service worker

yarn add workbox-webpack-plugin
//webpack.config.js:
const WorkboxPlugin = require('workbox-webpack-plugin');

module.exports = {
  // Other webpack config...

  plugins: [
    // Other plugins...
    
    new WorkboxPlugin.GenerateSW()
  ]
};

而后执行

npm run build

此时在dist目录下会自动生成precache-manifest.<revision>.js 和 service-worker.js文件(为何名字是这个,不是sw.js,由于在注册时register("/service-worker.js")写的这个名字),如图:

image

在precache-manifest.<revision>.js文件中,将预缓存列表经过全局变量self.__precacheManifest公开,以便在service-worker.js中调用。
默认会预缓存一切资源。
image

在service-worker.js中,则自动加载workbox cdn和 precache-manifest.<revision>.js文件,如图:
image

瞬间感受方便了不少........

由于默认会预缓存一切资源,若是你不喜欢预缓存某些文件,如图片,而在运行时缓存,则能够在runtimeCaching中定制它们

// 这些选项帮助 ServiceWorkers 快速启用
new WorkboxPlugin.GenerateSW({
      // 在预缓存中排除 图片
      exclude: [/\.(?:png|jpg|jpeg|svg)$/],

      //定义运行时缓存(可接受多个json对象)
      runtimeCaching: [
        {
          urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
          // 在缓存时使用 StaleWhileRevalidate 策略.
          handler: "StaleWhileRevalidate",
          options: {
            // 定义缓存这些图片的 cache名称
            cacheName: "my-images-cache",

            //配置 expiration
            expiration: {
              maxEntries: 10,
              maxAgeSeconds: 60
            },

            // 配置 background sync.
            backgroundSync: {
              name: "my-queue-name",
              options: {
                maxRetentionTime: 60 * 60
              }
            },

            //配置哪些响应被认为是可缓存的
            cacheableResponse: {
              statuses: [0, 200],
              headers: { "x-test": "true" }
            },

            //配置广播缓存更新插件。
            broadcastUpdate: {
              channelName: "my-update-channel"
            },

            //matchOptions和fetchOptions用于配置handler
            fetchOptions: {
              mode: "no-cors"
            },
            matchOptions: {
              ignoreSearch: true
            }
          }
        }
      ],

      importWorkboxFrom: "cdn", //经过cdn加载workbox, 还可经过‘local’加载,这样会将整个workbox下载到本地,再从本地引用
      skipWaiting: false, // service worker是否应该跳过等待生命周期阶段
      clientsClaim: false, //service worker是否应该在任何现有客户端激活后当即开始控制它

      cacheId: "my-app-test",
      offlineGoogleAnalytics: true
    })

运行npm run build后,会看到自动生成以下的service-worker.js
image

若是没出现,则只须要清空cache和service-worker文件便可,在clear storage中勾选unregister service workers和 cache storage,而后点击clear site data便可清理,而后刷新页面就会看到最新的service worker和cache storage。
image

咱们会发现无论vue仍是react,构建后,点开service-worker.js文件发现都和咱们刚才自动生成的service-worker.js很是类似,不一样的是,vue和react都把new WorkboxPlugin.GenerateSW部分封装了起来,除非npm run eject才能看到和修改。

相关文章
相关标签/搜索