我把网站的 service worker 从 sw-precache 迁移到了 Workbox ,记录一下过程。

sw-precache 是 Google 的一个实验性项目,也是 Workbox 的前身之一,之前一直用的它来生成网站的 service worker 文件,可即使对于我这个挺简单的站点,用它现在也有点不够用,比如之前我是缓存我的所有指定页面,以备离线使用,但是我现在我觉得不妥,只缓存访问页更好;再比如以前每次访问的时候都是先获取的离线内容,再尝试更新在线内容,我现在也觉得不好,应该根据内容的不同来判定先访问哪里的内容,而达成这些需要做很多的工作才能满足,就直接换了。

下面说说过程..

对于未系统化了解过 JS 项目管理工具的我来说,看 Workbox 的简介我是懵的,什么支持通过 Javascript 模块来使用,但是 service worker 不支持模块,所以需要使用 bunlder 工具来统合成一个文件.. 在一开始,就被这个 bunlder 工具的选择和使用难到了。

介绍里列出了三种工具 webpack , Rollup 以及 Parcel 。我先耐着性子基本浏览了一遍 Workbox 的介绍,全文没说推荐的工具。。于是我根据 tooling.report 上的通过率选择了 Parcel ,跟着其文档操作了一遍后发现。。 没把模块都整合进去啊,还是会需要导入外部的 js 文件,这就对 service worker 不适用了。后来又试了一下 Github 星多的 webpack .. 很满意,一下子就生成了我需要的文件。

在这个过程中,还了解到了 node.js 的项目管理文件 package.json 里的一点基本内容,比如 devDependencies 是用来放开发用工具的, dependencies 则是用来放实际的项目依赖的,它好像会根据 Git 项目的环境来查找当前的项目根目录,自此,我就可以把这个项目环境当作一个独立的系统环境来对待了,然后就对其工具和依赖有了一个比较清晰的认知。

接下来就是一个比较重头的如何编写原始的 service worker 文件,我尝试复制了其 Routing and Caching Strategies 的示例直接使用,发现基本上满足了我的需求,这时候自己还需要额外添加的内容是离线访问未缓存页面时的 fallback 页,也根据示例直接添加了预缓存的并在缓存未获取时 fallback 到指定页的代码,也直接成功了。这时候我感叹,实在太方便了.. 我的要求好像全部达到了。

后来简单测试了一下后发现,就这样的代码是不会自动跳过新的 service worker 的 waiting 阶段的,虽然对于一些复制的 web 应用来说,它的 waiting 阶段是应该需要用户来选择是否跳过的,但对于我这个个人博客而言,不存在在访问时需要保留的内容,所以应设定为自动跳过。

参考自己以前写的 service worker 文件,把 self.skipWaiting() 添加到 server worker 的 install 事件下后可用。考虑到需要删除之前缓存的本地数据库,同样把删除数据库的任务添加到了这个事件下。

这时候我在想,当阅读离线页面的时候,如果有一个简单的提示信息就更好了。因为 service worker 是无法获取 DOM 的,只能靠消息与其客户端(页面)进行通讯,于是我开始去找 Workbox 有没有提供类似的在抓缓存时用来和客户端通讯的功能。一开始没找到,后来发现了它可以自定义插件,而自定义插件的里面提供了一个 handlerDidComplete 方法,介绍说它可以获取到缓存命中的状态,我经过实验后发现,给出的变量都抓不到返回的 Response 是从缓存拿到的还是网络拿到的(也可能是我没找到,不管).. 后来我就又用了它另一个方法 fetchDidFail (顾名思义就是从网络获取失败了后会触发的),两个一结合,前者用于提供 Resonse 的状态码(比如 200),后者用于告知客户端从网络获取失败了,这样一组合客户端就可以知道是不是从缓存获取的内容了。

但是在这个过程中,我又发现了一个问题。我的博客是静态的,不通过接收参数来获取到不同内容的,所以之前设定了获取缓存时会忽略掉任何参数,但 Workbox 会根据访问的完整 URL 来保存缓存,这样就导致了获取缓存可能获取到更旧的缓存,所以我得想办法在每次缓存保存完之后,删除我认为相同的更旧的缓存。这里就又有一个方法可以使用了, cacheDidUpdate 同样是在自定义的插件里面,会在每次缓存被保存时触发,我在里面通过 Request 抓取了所有缓存,然后获取缓存头的 date 消息来判断并删除更旧的缓存。

自此,切换 service worker 到 Workbox 实现完成。

后来发现一个问题, Chrome 下测试没问题的离线页面信息提示在 Firefox 下无效.. 暂时不管了..

显示 Disqus 评论(需自备梯子)