Угловой PWA с настраиваемой оффлайн-страницей - PullRequest
0 голосов
/ 30 сентября 2019

В приложении Angular (8) я хотел бы добавить пользовательскую офлайн-страницу (для начала просто простой html-файл). Я настроил свое приложение как PWA (используя @angular/pwa и настроил все так, чтобы оно работало хотя бы без сбоев при подключении к Интернету).

Однако мне было трудно сделать обновления доступными для пользователей PWA,Итак, после многих часов попыток и ошибок я решил исключить index.html из ngsw-config.json. Это, конечно, приводит к тому, что index.html загружается каждый раз (не так уж плохо, потому что он такой маленький). Если есть какие-либо обновления index.html ссылки на разные JS-файлы и эти файлы загружаются немедленно. Итак, как я уже говорил, PWA работает так, как мне нравится.

Теперь я хочу отобразить offline.html, когда пользователь запускает PWA в автономном режиме. Поэтому я добавил offline.html к ngsw-config.json и создал пользовательский сервисный работник, включая официальный 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 быть загружен или нет.

Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

У меня все работает!

В конце концов, это был относительно простой 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');
0 голосов
/ 30 сентября 2019

index.html и .js будут кэшироваться с работниками сервиса. @ angular / pwa сделает это за вас, поэтому он будет работать под углом даже в автономном режиме. Вы можете использовать это в качестве преимущества, чтобы проверить, находится ли пользователь в сети, прежде чем оно загрузит приложение, поэтому вы можете использовать для него 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 },
  ]
})

Эта служба является той, которая первоначально вызывается и будет содержать метод, который отвечает на приложение init. Я просто добавил в качестве примера 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"  
    ],
...