Угловой работник службы находится в SAFE_MODE

У меня есть угловая PWA. Его сервисный работник работал безупречно, пока я не обновил Angular 5.0 до 7.2

После обновления я вижу следующую ошибку в /ngsw/state

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known
manifest initialize/<@https://{{domain}}.com/ngsw-worker.js:2227:27
[email protected]://{{domain}}.com/ngsw-worker.js:1772:52 ) Latest
manifest hash: none Last update check: never

Фон приложения

  • Угловая версия - 7.2.0
  • Версия рабочего сервиса - 7.2.0
  • Я проверяю обновления вручную, используя сервис SwUpdate.

Код для проверки обновлений

if (this.updates.isEnabled) {
      const appIsStable$ = this.appRef.isStable.pipe(first(isStable => isStable === true));
      const every21600Ms$ = interval(6 * 60 * 60);
      const every21600MsOnceAppIsStable$ = concat(appIsStable$, every21600Ms$);
      // poll the service worker to check for updates
      every21600MsOnceAppIsStable$.subscribe(() =>
        this.updates.checkForUpdate()
      );
    }

Мои шаги по исследованию и устранению неисправностей на данный момент:

В Chrome

  • Работник сервиса зарегистрирован без ошибок
  • Я заглянул во вкладку сети и обнаружил, что сервисный работник никогда не скачивает ngsw.json. Я видел загрузку ngsw.json, когда приложение было в Angular 5.0

Screenshot1

  • Я вижу, что та же проблема была зарегистрирована здесь. Я не вижу здесь правильного решения.
  • Я попытался выбрать "Обновить при перезагрузке", который временно устраняет проблему. Та же ошибка появляется снова после того, как я отменил выбор.

Screenshot2

В крае Microsoft

  • Удивительно, но после апгрейда все работает отлично.

Мои мысли и ожидания

  • Поскольку приложение отлично работает в MS edge, я сомневаюсь, что что-то не так с конфигурацией работника службы или с тем, как я запрашиваю обновления
  • Я ожидаю увидеть состояние диска как нормальное в /ngsw/state

Ответ 1

Кажется, это хорошо известная ошибка в сервис-сервисе Angular, и мы можем ожидать исправления/рабочей версии в какой-то момент. Большую информацию можно найти в выпуске 25611, поскольку шобхит вайш уже указан.

Однако, если вы ищете решение сейчас или собираетесь использовать более старую версию Angular 7/8, которая, возможно, не будет исправлена в ближайшее время, я постараюсь подытожить известные на данный момент обходные пути. (Также они не могут быть квалифицированы как "правильное решение"...)

Исправление ngsw-worker.js

Вы можете исправить ваш файл ngsw-worker.js либо после вашего ng run app:build:production, где он обычно будет находиться в папке www внутри вашего проекта (если вы не изменили Angular outputPath). Или вы можете установить его перед сборкой внутри node_modules/@angular/service-worker.

В зависимости от того, как часто вы создаете свое приложение, вы можете сделать это просто вручную (то есть с помощью текстового редактора на ваш выбор) или написать сценарий, например, с помощью sed.

Теперь у вас есть два варианта:

1. Исправление handleMessage()

Поиск по

        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {

И замените его на

        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {
                if (this.initialized === null) {
                    this.initialized = this.initialize();
                }
                try {
                    yield this.initialized;
                }
                catch (e) {
                    this.state = DriverReadyState.SAFE_MODE;
                    this.stateMessage = 'Initialization failed due to handleMessage() error: ${errorToString(e)}';
                }

В зависимости от вашей версии @angular/service-worker подпись handleMessage() может выглядеть для вас по-разному, и вы могли бы написать более сложный catch, но, надеюсь, в любом случае он никогда не достигнет блока catch.
Этот патч в основном соответствует тому, что предложено в комментарии gkalpak, и, скорее всего, официальное исправление также будет примерно таким.

2. Исправление initialize()

Поиск по

                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);

И замените его на

                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);
                    if (latest.latest === null) throw new Error('Error latest.latest is null for what ever reason...');

Тем самым вы убедитесь, что блок catch в initialize() действительно будет работать и не позволит работнику сервиса войти в SAFE_MODE. Однако это может быть не так надежно, как в первом патче, но также может работать для сервисных работников, которые уже находятся в SAFE_MODE из-за этой проблемы. Это было предложено в комментарии hsta.

Обойти проблему в приложении Angular

Если вы не хотите возиться с ngsw-worker.js, вы можете попытаться определить состояние работника сервиса, выбрав your-app.domain/ngsw/state из вашего приложения Angular и если он находится в SAFE_MODE (можно проверить, например, с помощью простой поиск regex) вы можете попытаться сбросить его, удалив все элементы из кеш-хранилища и затем отменив регистрацию работника сервиса. Идея этого была предложена в комментарии mattlewis92 и одобрена как вероятный рабочий взлом в комментарии gkalpak.

Временное решение проблемы вручную

Как shobhit vaish уже выяснилось, вы также можете решить проблему вручную. Помимо возможности, о которой уже говорилось в исходном сообщении, вы также можете сделать это в инструментах разработки браузера на основе Chrome в разделе "Приложение" → "Очистить хранилище", выбрав "Отменить регистрацию сервисных работников" и нажав "Очистить данные сайта". Очевидно, что проблема может и, вероятно, вернется в будущих обновлениях и не сильно поможет обычным пользователям. Но это может быть удобно, если вы, как разработчик, просто хотите быстро решить эту проблему.