cisen / blog

Time waits for no one.
135 stars 20 forks source link

wokbox 相关 #649

Open cisen opened 5 years ago

cisen commented 5 years ago

使用

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模块等等,它们分别负责处理不同的逻辑。

1、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

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

2、workbox路由

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

//如果非要使用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] }) ] }), );

```js
//还可以自定义策略的名称,过期时间等等
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

3、workbox插件

4、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

4、在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..js 和 service-worker.js文件(为什么名字是这个,不是sw.js,因为在注册时register("/service-worker.js")写的这个名字),如图:

image

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

在service-worker.js中,则自动加载workbox cdn和 precache-manifest..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才能看到和修改。

四. 使用workerbox后的效果

在我们的项目中,我们以DomContentLoaded的时间作为参考点,对比有加service worker 和未加的service worker情况。

测试条件

以首页为例,在不同的网络环境下,发起10次网络请求,然后取平均值,作为它们的最终结果,测试结果如下: 991408402-5cb476b201e19_articlex

图片描述

通过上面的数据可以得出几个结论:

五. 几个注意点

在使用workbox的过程中,会遇到一些问题,下面列出几点,也算是做个总结:

1. service worker 注册文件放置的位置

在页面注册service worker的时候,尽量注册到项目的根目录下,这样才能最大的发挥service worker的作用

// build.sw.js最好放在项目的根目录下,才能发挥最大的缓存效果
navigator.serviceWorker.register(`./build.sw.js`)

// 如果这样配置的话,就只有path目录下面的文件才能实现缓存,其他目录,包括根目录的都不能缓存
navigator.serviceWorker.register(`./path/build.sw.js`)

2.使用workbox 命令行生成预缓存列表的注意点

我们先预设一下应用场景:假设你的项目在目录 /app 下,必须保证在你的项目根目录下有一个 app/sw.js 包含以下内容:

// 通常项目中的 sw.js 源文件都是通过这样预留一个空数组的方式来预缓存内容列表的
workbox.precaching.precacheAndRoute([]);

这样才能保证能将生成的预缓存内容列表内容注入到 Service Worker 文件中。

3.缓存策略设置

在经过一段时间的使用和思考以后,给出认为较为合理的缓存策略:

如果大家在使用过程中有更友好的策略,麻烦也贡献你们的策略,大家共同学习,共同进步。

还有,要牢记,对于不在同一域下的任何资源,绝对不能使用 Cache only 和 Cache first。

4.service worker的运行环境

需要注意的是,Service Worker 脚本除了域名为 localhost 时能运行在 http 协议下以外,只能运行 https 协议下。

5. 使用Service Worker缓存请求时,POST请求无法缓存

Google对web的标准化还是遵循的,SW认为POST请求就是象服务器提交资源,不存在缓存需求

helloyxw commented 2 years ago

缓存第三方,比如jquery, 则策略最好使用NetworkFirst或者StaleWhileRevalidate, 不要使用CacheFirst 。 如何理解呢? 因为第三方资源变动的频率高,缓存没有意义吗?

jayyoonn commented 1 year ago

缓存第三方,比如jquery, 则策略最好使用NetworkFirst或者StaleWhileRevalidate, 不要使用CacheFirst 。 如何理解呢? 因为第三方资源变动的频率高,缓存没有意义吗?

因为第三方资源,存在跨域的问题。一但服务端没有返回CORS标头,浏览器就无法获取到响应的内容信息,这种属于不透明的响应。这种缓存存在可能是错误的响应,而且之后这个响应也永远不会更新。