Genişletilmiş Ekosistem
Service Worker'lar ve PWA'lar

Service Worker ile İletişim

Service worker desteğini etkinleştirmek, yalnızca service worker'ı kaydetmekten fazlasını yapar; aynı zamanda service worker ile etkileşim kurmak ve uygulamanızın önbelleklemesini kontrol etmek için kullanabileceğiniz servisler sağlar.

SwUpdate service

SwUpdate servisi, service worker'ın uygulamanız için mevcut bir güncelleme keşfettiğini ve yüklediğini belirten olaylara erişmenizi sağlar.

SwUpdate servisi üç ayrı işlemi destekler:

  • Güncellenmiş bir sürümün sunucuda tespit edildiğinde, yüklenip yerel olarak kullanıma hazır olduğunda veya bir yükleme başarısız olduğunda bildirim alma.
  • Service worker'dan sunucuda yeni güncellemeler olup olmadığını kontrol etmesini isteme.
  • Service worker'dan mevcut sekme için uygulamanın en son sürümünü etkinleştirmesini isteme.

Sürüm güncellemeleri

versionUpdates, SwUpdate'in bir Observable özelliğidir ve beş olay türü yayar:

Olay türleri Ayrıntılar
VersionDetectedEvent Service worker, sunucuda uygulamanın yeni bir sürümünü tespit ettiğinde ve indirmeye başlamak üzere olduğunda yayılır.
NoNewVersionDetectedEvent Service worker, sunucudaki uygulama sürümünü kontrol ettiğinde ve yeni bir sürüm bulamadığında yayılır.
VersionReadyEvent Uygulamanın yeni bir sürümü istemciler tarafından etkinleştirilmeye hazır olduğunda yayılır. Kullanıcıyı mevcut bir güncelleme hakkında bilgilendirmek veya sayfayı yenilemesini istemek için kullanılabilir.
VersionInstallationFailedEvent Yeni bir sürümün yüklemesi başarısız olduğunda yayılır. Günlükleme/izleme amaçlarıyla kullanılabilir.
VersionFailedEvent Bir sürüm, o sürümü kullanan tüm istemcileri etkileyen kritik bir hatayla (bozuk hash hataları gibi) karşılaştığında yayılır. Hata ayıklama ve şeffaflık için hata ayrıntıları sağlar.

log-update.service.ts

@Injectable({providedIn: 'root'})
export class LogUpdateService {
  private updates = inject(SwUpdate);
  constructor() {
    this.updates.versionUpdates.subscribe((evt) => {
      switch (evt.type) {
        case 'VERSION_DETECTED':
          console.log(`Downloading new app version: ${evt.version.hash}`);
          break;
        case 'VERSION_READY':
          console.log(`Current app version: ${evt.currentVersion.hash}`);
          console.log(`New app version ready for use: ${evt.latestVersion.hash}`);
          break;
        case 'VERSION_INSTALLATION_FAILED':
          console.log(`Failed to install app version '${evt.version.hash}': ${evt.error}`);
          break;
        case 'VERSION_FAILED':
          console.log(`Version '${evt.version.hash}' failed with error: ${evt.error}`);
          break;
      }
    });
  }
}

Güncellemeleri kontrol etme

Service worker'dan sunucuya herhangi bir güncelleme dağıtılıp dağıtılmadığını kontrol etmesini istemek mümkündür. Service worker, başlatma sırasında ve her navigasyon isteğinde — yani kullanıcı farklı bir adresten uygulamanıza gittiğinde — güncellemeleri kontrol eder. Ancak, sık sık değişen bir siteniz varsa veya güncellemelerin bir programa göre yapılmasını istiyorsanız, güncellemeleri manuel olarak kontrol etmeyi seçebilirsiniz.

Bunu checkForUpdate() metoduyla yapın:

check-for-update.service.ts

import {ApplicationRef, inject, Injectable} from '@angular/core';
import {SwUpdate} from '@angular/service-worker';
import {concat, interval} from 'rxjs';
import {first} from 'rxjs/operators';

@Injectable({providedIn: 'root'})
export class CheckForUpdateService {
  private appRef = inject(ApplicationRef);
  private updates = inject(SwUpdate);

  constructor() {
    // Allow the app to stabilize first, before starting
    // polling for updates with `interval()`.
    const appIsStable$ = this.appRef.isStable.pipe(first((isStable) => isStable === true));
    const everySixHours$ = interval(6 * 60 * 60 * 1000);
    const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);

    everySixHoursOnceAppIsStable$.subscribe(async () => {
      try {
        const updateFound = await this.updates.checkForUpdate();
        console.log(updateFound ? 'A new version is available.' : 'Already on the latest version.');
      } catch (err) {
        console.error('Failed to check for updates:', err);
      }
    });
  }
}

Bu metot, etkinleştirme için bir güncellemenin mevcut olup olmadığını belirten bir Promise<boolean> döndürür. Kontrol başarısız olabilir ve bu durumda Promise reddedilir.

Stabilization and service worker registration

Sayfanın ilk oluşturulmasını olumsuz etkilememek için, varsayılan olarak Angular service worker servisi, ServiceWorker betiğini kaydetmeden önce uygulamanın kararlı hale gelmesi için 30 saniyeye kadar bekler.

Güncellemeler için sürekli yoklama yapmak, örneğin setInterval() veya RxJS'in interval() fonksiyonu ile, uygulamanın kararlı hale gelmesini engeller ve ServiceWorker betiği 30 saniyelik üst sınıra ulaşılana kadar tarayıcıya kaydedilmez.

Bu, uygulamanız tarafından yapılan her türlü yoklama için geçerlidir. Daha fazla bilgi için isStable belgelerine bakın.

Bu gecikmeden kaçınmak için, önceki örnekte gösterildiği gibi, güncelleme yoklamasına başlamadan önce uygulamanın kararlı hale gelmesini bekleyin. Alternatif olarak, ServiceWorker için farklı bir kayıt stratejisi tanımlamak isteyebilirsiniz.

En son sürüme güncelleme

Mevcut bir sekmeyi, yeni bir sürüm hazır olur olmaz sayfayı yenileyerek en son sürüme güncelleyebilirsiniz. Kullanıcının ilerlemesini kesintiye uğratmamak için, genellikle kullanıcıya sormak ve sayfayı yenileyip en son sürüme güncellemenin uygun olduğunu onaylamasını sağlamak iyi bir fikirdir:

prompt-update.service.ts

@Injectable({providedIn: 'root'})
export class PromptUpdateService {
  constructor() {
    const swUpdate = inject(SwUpdate);
    swUpdate.versionUpdates
      .pipe(filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'))
      .subscribe((evt) => {
        if (promptUser(evt)) {
          // Reload the page to update to the latest version.
          document.location.reload();
        }
      });
  }
}

Safety of updating without reloading

activateUpdate() çağrısı, bir sekmeyi sayfayı yeniden yüklemeden en son sürüme günceller, ancak bu uygulamayı bozabilir.

Yeniden yüklemeden güncelleme, uygulama kabuğu ile tembel yüklenen parçalar gibi diğer sayfa kaynakları arasında bir sürüm uyumsuzluğu yaratabilir; bu dosyaların isimleri sürümler arasında değişebilir.

activateUpdate()'i yalnızca belirli kullanım durumunuz için güvenli olduğundan eminseniz kullanmalısınız.

Kurtarılamaz bir durumu işleme

Bazı durumlarda, service worker'ın bir istemciye hizmet vermek için kullandığı uygulamanın sürümü, tam bir sayfa yeniden yüklemesi olmadan kurtarılamayan bozuk bir durumda olabilir.

Örneğin, aşağıdaki senaryoyu düşünün:

  1. Bir kullanıcı uygulamayı ilk kez açar ve service worker uygulamanın en son sürümünü önbelleğe alır. Uygulamanın önbelleğe alınmış varlıklarının index.html, main.<main-hash-1>.js ve lazy-chunk.<lazy-hash-1>.js içerdiğini varsayın.

  2. Kullanıcı uygulamayı kapatır ve bir süre açmaz.

  3. Bir süre sonra uygulamanın yeni bir sürümü sunucuya dağıtılır. Bu daha yeni sürüm index.html, main.<main-hash-2>.js ve lazy-chunk.<lazy-hash-2>.js dosyalarını içerir.

IMPORTANT: Dosyaların içeriği değiştiği için hash'ler artık farklıdır. Eski sürüm artık sunucuda mevcut değildir.

  1. Bu arada kullanıcının tarayıcısı lazy-chunk.<lazy-hash-1>.js dosyasını önbelleğinden çıkarmaya karar verir. Tarayıcılar disk alanı geri kazanmak için belirli (veya tüm) kaynakları önbellekten çıkarmaya karar verebilir.

  2. Kullanıcı uygulamayı tekrar açar. Service worker, bu noktada bildiği en son sürümü, yani eski sürümü (index.html ve main.<main-hash-1>.js) sunar.

  3. Daha sonraki bir noktada uygulama tembel paketi lazy-chunk.<lazy-hash-1>.js'yi ister.

  4. Service worker, varlığı önbellekte bulamaz (tarayıcının onu çıkardığını unutmayın). Sunucudan da alamaz (çünkü sunucuda artık yalnızca daha yeni sürümdeki lazy-chunk.<lazy-hash-2>.js vardır).

Önceki senaryoda, service worker normalde önbelleğe alınacak bir varlığı sunamaz. Bu belirli uygulama sürümü bozuktur ve istemcinin durumunu sayfayı yeniden yüklemeden düzeltmenin bir yolu yoktur. Bu gibi durumlarda service worker, istemciyi bir UnrecoverableStateEvent olayı göndererek bilgilendirir. Bu hataları bildirim almak ve işlemek için SwUpdate#unrecoverable'a abone olun.

handle-unrecoverable-state.service.ts

@Injectable({providedIn: 'root'})
export class HandleUnrecoverableStateService {
  private updates = inject(SwUpdate);
  constructor() {
    this.updates.unrecoverable.subscribe((event) => {
      notifyUser(
        'An error occurred that we cannot recover from:\n' +
          event.reason +
          '\n\nPlease reload the page.',
      );
    });
  }
}

Angular service worker'lar hakkında daha fazlası

Aşağıdakiler de ilginizi çekebilir: