当资源未缓存和脱机时,Workbox重定向客户端页面

时间:2019-10-07 20:24:39

标签: service-worker progressive-web-apps workbox

通常,每当我阅读有关PWA的博客文章时,该教程似乎都只是预缓存了每个资产。但这似乎有点违背了应用程序外壳模式,据我所知是:缓存所有必需品(仅应用程序外壳),并随需运行时缓存。 (如果我理解不正确,请纠正我)

想象一下我有这个单页应用程序,它是一个简单的index.html,带有一个Web组件:<my-app>。该<my-app>组件设置了一些看起来像这样的路由,我使用的是Vaadin路由器和Web组件,但我想使用React with React Router或类似的东西会出现相同的问题。

router.setRoutes([
    {
        path: '/',
        component: 'app-main', // statically loaded
    },
    {
    path: '/posts',
        component: 'app-posts',
        action: () => { import('./app-posts.js');} // dynamically loaded
    },
    /* many, many, many more routes */
    {
        path: '/offline', // redirect here when a resource is not cached and failed to get from network
        component: 'app-offline', // also statically loaded
    }
]);

我的应用程序可能有很多路线,并且可能会变得很大。我不想立即预缓存所有这些资源,而只缓存我绝对需要的东西,因此在这种情况下:我的index.htmlmy-app.jsapp-main.js和{{1 }}。我想在运行时按要求缓存app-offline.js

设置运行时缓存非常简单,但是当我的用户访问可能尚未缓存的许多路由之一时,就会出现我的问题(因为也许用户之前没有访问过该路由,所以{{1} }文件可能尚未加载/缓存),并且用户没有互联网连接。

在这种情况下(当尚未缓存路由并且没有网络时),我想发生的事情是将用户重定向到app-posts.js路由,该路由由我的客户端处理路由器。我可以轻松地执行以下操作:js,但是我想知道是否有一种方法可以通过工作箱本身来实现。

因此简而言之: 如果尚未缓存/offline文件,并且用户没有网络,因此对该文件的请求失败:让工作箱将页面重定向到import('./app-posts.js').catch(() => /* redirect user to /offline */)路由。

1 个答案:

答案 0 :(得分:1)

选项1(并非总是有用): 据this answer所知,您无法在服务工作者中打开新窗口或更改浏览器的URL。但是,如果从clients.openWindow()事件内部调用了notificationclick函数,则只能打开新窗口。

Option 2(最困难): 您可以在服务工作者的WindowClient.navigate事件中使用activate方法,但是有点麻烦,因为您仍然需要检查请求的文件是否在缓存中。

选项3(最简单,最hackest): 否则,您可以使用一个新的Request对象响应离线页面:

const cacheOnly = new workbox.strategies.CacheOnly();
const networkFirst = new workbox.strategies.NetworkFirst();

workbox.routing.registerRoute(
  /\/posts.|\/articles/, 
  async args => {
    const offlineRequest = new Request('/offline.html');

    try {
      const response = await networkFirst.handle(args);
      return response || await cacheOnly.handle({request: offlineRequest});

    } catch (error) {
      return await cacheOnly.handle({request: offlineRequest})

    }
  }
);

,然后在offline.html文件中重写浏览器的URL:

 <head>
    <script>
        window.history.replaceState({}, 'You are offline', '/offline');
    </script>
 </head>

选项3 中的上述逻辑将首先通过使用网络来响应所请求的URL。如果网络不可用,将回退到缓存,即使在缓存中未找到请求,也将取回offline.html文件。解析offline.html文件后,浏览器URL将替换为/offline