联机时如何使用SSR页面,脱机时如何回退到缓存的index.html

时间:2019-06-04 22:55:18

标签: angular progressive-web-apps angular-universal angular-pwa

我同时使用Angular PWA和Angular Universal,并且正在使用离线导航。

我要为导航请求实现的行为是:

  • 在线时,以最大的第一次绘制速度(然后由客户端接管)投放服务器端渲染的页面
  • 离线时,回退到缓存的index.html以便使用缓存的客户端应用

问题是ngsw-worker.js及其配置文件ngsw-config.json没有提供足够高的粒度级别来实现这一目标。

这是我当前的ngsw-config.json,它提供的行为接近我想要实现的行为,但是当我以离线模式刷新应用程序时,它仅在刷新页面(因此已缓存)时才起作用。之前的在线模式。

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
        ]
      }
    }
  ],
  "dataGroups": [
    {
      "name": "backend",
      "urls": [
        "/backend/**"
      ],
      "cacheConfig": {
        "maxSize": 100,
        "maxAge": "3d",
        "strategy": "freshness"
      }
    },
    {
      "name": "serverSideRenderedPages",
      "urls": [
        "/**"
      ],
      "cacheConfig": {
        "maxSize": 100,
        "maxAge": "3d",
        "strategy": "freshness"
      }
    }
  ],
  "navigationUrls": [
    "!/**"
  ]
}

我认为服务工作者应该“通用”,但是有没有干净的解决方案或解决方法?

2 个答案:

答案 0 :(得分:1)

由于该框架未提供此功能,因此我将其作为功能请求提交,并且一个团队成员(简而言之)告诉我,客户端在线这一事实并不能保证SSR页面的渲染速度比加载更快缓存中的客户端应用程序,并且由于SSR页面引用了最新的客户端应用程序,因此这可能破坏更新机制。

有关更多详细信息,请参见GitHub issue

答案 1 :(得分:0)

您需要在没有互联网连接的情况下使用Service Worker为用户提供离线页面

const cacheName = 'cache-v1';
const offlineUrl = 'offline-page.html';

// Cache our known resources during install
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(cacheName)
    .then(cache => cache.addAll([
      './index.html',
      offlineUrl
    ]))
  );
});

// Cache any new resources as they are fetched
self.addEventListener('fetch', function(event) {
    event.respondWith(
      caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        }
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function(response) {
            if(!response || response.status !== 200) {
              return response;
            }

            var responseToCache = response.clone();
            caches.open(cacheName)
            .then(function(cache) {
              cache.put(event.request, responseToCache);
            });

            return response;
          }
        ).catch(error => {
          // Check if the user is offline first and is trying to navigate to a web page. If user navigate to another page the website will serve them the offline page
          if (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html')) {
          // Return the offline page
          return caches.match(offlineUrl);
        }
        });
      })
    );
});

然后将此脚本放入您的index.html

  <script>
  // Register the service worker
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js').then(function(registration) {
      // Registration was successful
    });
  }
  </script>