2

在 Angular (8) 应用程序中,我想添加一个自定义离线页面(只是一个简单的 html 文件开始)。我已将我的应用程序设置为 PWA(使用@angular/pwa和配置所有内容,以便它至少在在线时能够顺利运行)。

但是,我很难为 PWA 用户提供更新。因此,经过数小时的尝试和错误,我决定index.htmlngsw-config.json. 这当然具有index.html每次加载的效果(还不错,因为它太小了)。如果有任何更新index.html链接指向不同的 JS 文件,这些文件会立即加载。所以,正如我之前所说,PWA 就像我喜欢的那样工作。

现在我想offline.html在用户启动 PWA 脱机时显示。因此,我添加offline.htmlngsw-config.json创建了一个自定义 Service Worker,包括官方ngsw-worker.js

importScripts('./ngsw-worker.js');

我也在使用这个自定义服务工作者而不是官方的:

ServiceWorkerModule.register('./custom-worker.js', { enabled: true, registrationStrategy: registrationStrategy })

到目前为止,一切仍然按预期工作。行为和以前一样。现在我想在我的自定义工作者中包含离线行为:

importScripts('./ngsw-worker.js');
self.addEventListener('fetch', function(event) {
    return event.respondWith(
      caches.match(event.request)
      .then(function(response) {
        let requestToCache = event.request.clone();

        return fetch(requestToCache).then().catch(error => {
          // Check if the user is offline first and is trying to navigate to a web page
          if (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html')) {
            // Return the offline page
            return caches.match("offline.html");
          }
        });
      })
    );
  });

该脚本来自:https ://stackoverflow.com/a/56738140/4653997 不幸的是,这部分根本不起作用。现在我几乎被困住了。我不知道下一步该怎么做。我认为无论是否index.html可以加载服​​务人员都会被执行。

任何帮助,将不胜感激。

4

2 回答 2

3

我已经成功了!

最后,它是一个相对简单的fetch事件监听器,我必须添加到我的自定义服务工作者中:

// listen to every fetch event
self.addEventListener('fetch', function (event) {
    const request = event.request;
    
    // filter for html document fetches (should only result in one single fetch) --> index.html
    if (request.method === "GET" && request.destination === "document") {

        // only intercept if there was a problem fetching index.html
        event.respondWith(
            fetch(request).catch(function (error) {
                console.error("[onfetch] Failed. Serving cached offline fallback", error);

                // return offline page from cache instead
                return caches.match("/assets/offline.html");
            }));
    }
});

// use all the magic of the Angular Service Worker
importScripts('./ngsw-worker.js');

于 2019-09-30T12:58:38.973 回答
0

index.html 和 .js 将被服务工作者缓存。@angular/pwa 将为您执行此操作,因此即使在离线时它也会初始化 angular。您可以利用它作为优势在启动应用程序之前检查用户是否在线,以便您可以使用 APP_INITIALIZER 。

将在应用程序初始化时调用的第一个注册函数如下:

import { NgModule, APP_INITIALIZER } from '@angular/core'; 
import { AppLoadService } from './app-load.service';

export function init_app(appLoadService: AppLoadService) {
    return () => appLoadService.initializeApp();
}

@NgModule({
  imports: [HttpClientModule],
  providers: [
    AppLoadService,
    { provide: APP_INITIALIZER, useFactory: init_app, deps: [AppLoadService], multi: true },
  ]
})

此服务是最初调用的服务,将包含响应应用程序初始化的方法。我只是在这里添加了 window.location.href 作为示例,但是如果它检查浏览器是否在线,您可以在其中执行任何操作。

export class AppLoadModule { }

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class AppLoadService {

  constructor(private httpClient: HttpClient) { }

  initializeApp(): Promise<any> {
    return new Promise((resolve, reject) => {
                if (!window.navigator.onLine) {
                  window.location.href = offlineURL; // this would probably be something like 'yourURL/assets/offline-page.html'
                }
                resolve();
    });
  }
}

请注意,您仍然需要在资源 ng-sw.config 中有离线页面,以便在 sw 缓存它时可以访问它

"resources": {
    "files": [
        ...
        "/assets/offline-page.html"  
    ],
于 2019-09-30T08:25:34.877 回答