我该如何更新service workers和缓存的PWA文件?

3
在我的当前系统中,每当我制作JavaScript包时,我都会为生产版本添加一个哈希值到文件名中。我的index.html没有CDN缓存,因此每当有新版本发布时,就会创建一个新的index.html指向新的哈希JavaScript文件名。这在使捆绑内容失效方面效果很好,每当部署新版本时(代价是我的非常小的index.html不被缓存)。
我正在研究如何使我的应用程序成为PWA,并想知道如何在部署新版本时使现有用户的缓存失效。以下是问题:
1. serviceworker.js需要具有固定的文件名(文件名中没有哈希值),这意味着我的CDN将长时间缓存该文件,而我不想在每次部署时手动使CDN缓存失效。我猜我可以像对待index.html一样删除serviceworker.js的缓存,因为那个文件只会下载一次。
2. 我的worker在用户的浏览器中注册,我不确定是否需要添加一些额外的代码来检查是否有新版本的worker可用。浏览器如何决定何时尝试更新已注册的serviceworker?我可以取消注册我的service worker以安装PWA的新版本吗?那不会破坏PWA吗?
3. 我的index.html由服务工作线程缓存,这意味着使用PWA的人永远不会获得我的主JS包的新版本(因为缓存的index.html将指向旧的哈希文件名中的旧包)。我猜我可以只删除serviceworker缓存上的index.html,但那样应用程序就无法离线工作了?
4. 如果想要在离线情况下使用我的应用程序,我需要让我的服务工作线程能够缓存我的哈希JS文件。我猜我需要对self.addEventListener('fetch', ...)中的文件名进行一些魔法操作,以便在可用时使用缓存版本,并定期检查新版本,通过创建一个未缓存的静态JSON文件或具有最新文件名的其他内容来获取哈希JS包文件名。虽然这似乎是一个hackish的解决方案。
我似乎找不到如何处理这些问题的好指南,感觉这需要很多工作,而浏览器应该能够根据某些选项(例如每X个时间重试)自动完成这些工作。是否有一些神奇的HTTP标头我不知道?
1个回答

3
我有同样的问题,今天我解决了。你的 index.html 应该由服务工作者缓存以实现离线工作。当用户打开你的 PWA 时,所有文件都将从缓存中加载,加载完成后,服务工作者将从网络中检索,如果有新的服务工作者,则会下载所有新文件并安装新的服务工作者,等待激活。你需要刷新你的 PWA 以激活新的服务工作者并使用更新后的应用程序。
我使用了这篇文章并创建了我的新服务工作者(而不是在create-react-app中的默认服务工作者)。这篇文章还解释了如何检测新的服务工作者的安装,因此你可以通知用户更新可用并刷新PWA。
希望这可以帮到你。

我想避免使用Workbox,因为我认为它太神奇了。我可以看到它保留了每个缓存文件的“修订版本”,就像我在第4个问题中所想的那样。 我希望有一种“标准”方式来使serviceworkers中的缓存失效,但显然没有这样的方式。这意味着我需要自己开发。 - Hoffmann
哦,顺便问一下,你知道window.location.reload(true)是否绕过了服务工作器缓存吗? - Hoffmann
我猜最简单的解决方案就是在未缓存的静态文件中有一个构建号,并将其与服务工作者中的构建号进行比较。每当它更改时,只需使整个缓存失效并注销工作者。更聪明的解决方案将能够保留未更改的文件,以便在缓存中保留它们。不过,如果图像文件名具有类似JS捆绑包的哈希,则至少可以将图像保存在缓存中。 - Hoffmann
1
在IOS上,当PWA被安装后,会应用另一层内存缓存,我使用window.location.reload(true)来清除它。我不确定服务工作者缓存。 - Ali SabziNezhad
@AliSabziNezhad,“reload(true)”已经被弃用了吗?它还能用吗?当我使用它时,我仍然有缓存文件。 - Farhad
@Hoffmann,你找到答案了吗?reload(true)有效吗?它是否绕过了服务工作器缓存? - Farhad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接