GatsbyJS Service Worker配置不尊重“ networkFirst”,一直在提供陈旧数据

问题描述 投票:1回答:1

我有一个GatsbyJS网站,我正在将其部署到Netlify。每当我导航到网站时,服务人员都会为我提供该网站的过时版本,并在后台发送请求,以便下次获得较新的版本。 我认为访问我的网站的用户看到的版本可能已经过了几天是不可接受的。我希望服务人员在网络可用的情况下获取新版本,并提供陈旧的服务。版本仅在离线模式下。我找不到有关如何实现此目标的任何文档。

基于this GatsbyJS docthis Workbox doc,我认为应该将策略从staleWhileRevalidate更改为networkFirst。他们没有在任何地方提供完整的示例,因此我不得不猜测语法,而且看来我的猜测是不正确的。 谁能提供一个完整的示例,说明如何配置gatsby-plugin-offline以实现合理的行为?

caching service-worker browser-cache gatsby workbox
1个回答
1
投票

这是一个很长的答案,所以我将其分为三部分。

问题

Gatsby的脱机插件在后台使用Google的工作箱来进行预缓存和运行时缓存。 runtime caching strategies提供了不同的workbox-strategies package。这些包括stale-while-revalidatecache first (cache falling back to network)network first (network falling back to cache)

gatsby-plugin-offline设置适当的caching strategies for different URLs。例如:

  • 静态目录中的CSS,JS和文件使用CacheFirst,因为它们具有哈希的唯一URL,可以从缓存中安全地对其进行服务。
  • page-data.json文件使用StaleWhileRevalidate,因为它们没有哈希的URL。

注意:Gatsby docs for gatsby-plugin-offline(截至2020年5月)表示page-data.json文件使用NetworkFirst,但使用they actually use StaleWhileRevalidate

没有在gatsby-plugin-offline中设置的特定处理程序的文件(例如,首次加载的HTML文件)StaleWhileRevalidate。该插件在后台使用use a cache first policy。注意:我实际上在文档中找不到对此的引用,只是我链接到的注释,但是我进行了实验,并且HTML页面确实由服务工作者缓存,尽管不在generateSW from workbox-build列表中。

所以,我认为用户看到陈旧页面的问题是因为首次加载的HTML和page-data.json文件都是由服务工作者从缓存中提供的。

您应修复它

使用runtimeCachingNetworkFirst(或CacheFirst)之间需要权衡取舍。 StaleWhileRevalidate已优化,可获取准确的数据并略微降低速度。 NetworkFirstCacheFirst直接从缓存中获取,因此针对性能进行了优化,但要以拥有最新数据为代价。两者都具有在网络中断的情况下具有弹性的优势。

因此,它可能取决于每个用例,取决于网站的类型,内容和受众。例如:

  • 一个内容经常不更新的博客可能可以安全地对单个帖子使用StaleWhileRevalidate甚至是StaleWhileRevalidate
  • 您知道大多数用途的网站都是通过快速,有线,可靠的互联网连接使用台式计算机,这意味着使用CacheFirst很合适。
  • 一个显示时间敏感内容的网站,在您希望看到最新内容的地方,可以使用NetworkFirst

如何修复

我认为有两种主要方法可以解决此问题:有可用更新时刷新页面,或将缓存策略更改为NetworkFirst

刷新页面

Gatsby为此提供了一个NetworkFirst挂钩。因此,您可以按原样保留默认的缓存优先行为,但可以使用此钩子刷新页面。

最简单的方法是在Service Worker中有更新时重新加载页面:

onServiceWorkerUpdateReady

但是,这可能是侵入性和无提示的,因此不一定有很好的用户体验。替代方法是提示用户进行更新。这就是onServiceWorkerUpdateReady

// gatsby-browser.js
export const onServiceWorkerUpdateReady = () => window.location.reload(true);

如果您不喜欢本机浏览器提示(我不喜欢!),那么第三种选择是通过某些自定义UI提示用户。类似于:

Gatsby docs suggests

注意:如果您沿着这条路线并实现为对话框,请// gatsby-browser.js export const onServiceWorkerUpdateReady = () => { const answer = window.confirm( `This application has been updated. ` + `Reload to display the latest version?` ) if (answer === true) { window.location.reload() } }

使用NetworkFirst

我认为这是您所追求的,因为它回答了“只要网络可用,我希望服务人员获取新版本”。

使用gatsby-plugin-offline覆盖// gatsby-browser.js import React from "react"; import ReactDOM from "react-dom"; export const onServiceWorkerUpdateReady = () => { const root = document.body.appendChild(document.createElement("div")); ReactDOM.render( <div> <p> Acme has been updated in the&nbsp;background. <br /> Refresh to see the latest&nbsp;version. </p> <button onClick={() => window.location.reload(true)}> Refresh </button> <button onClick={() => document.body.removeChild(root)}> Close </button> </div>, root ); }; ,以更改运行时缓存策略以适当地使用make sure it's accessible。使用the workbox config属性执行类似操作:

NetworkFirst

这是gatsby-plugin-offline使用的默认运行时缓存,并进行了两次关键更改:以下规则都使用runtimeCaching

  • page-data.json文件
  • HTML路由(以/结尾)-我假设您的HTML页面都以/结尾,如果没有,则可以使用// gatsby-config.js module.exports = { plugins: [ { resolve: `gatsby-plugin-offline`, options: { workboxConfig: { runtimeCaching: [ { urlPattern: /(\.js$|\.css$|static\/)/, handler: `CacheFirst`, }, { urlPattern: /^https?:.*\/page-data\/.*\/(page-data|app-data)\.json$/, handler: `NetworkFirst`, options: { networkTimeoutSeconds: 1, }, }, { urlPattern: /^https?:.*\.(png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/, handler: `StaleWhileRevalidate`, }, { urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/, handler: `StaleWhileRevalidate`, }, { urlPattern: /\/$/, handler: `NetworkFirst`, options: { networkTimeoutSeconds: 1, }, }, ], }, }, }, ] }; 之类的东西。
© www.soinside.com 2019 - 2024. All rights reserved.