Mert Özen Her Satırda Daha İleri
Frontend Browser API'leri ve PWA — #10

2020'den 2026'ya Tarayıcı API'lerinde ve Angular Service Worker'da Değişenler: Baseline'ı Okumak

Mert Özen 15 Kas 2026 10 dk 10 görüntülenme
2020'den 2026'ya Tarayıcı API'lerinde ve Angular Service Worker'da Değişenler: Baseline'ı Okumak

Baseline bir özelliğin bütün çekirdek tarayıcılarda olup olmadığını söyler; Angular 22'nin hedefi ise sabit bir tarihteki widely available tarayıcılar (Chrome 119, Firefox 119, Safari 17), bu yüzden Navigation API gibi newly available API'ler için feature detection hâlâ şart. Serinin kullandığı özelliklerin durumunu web-features'tan okuyan bir rapor, 2020-2026 dönüm noktaları, Angular Service Worker'daki API değişiklikleri ve eski bir Angular PWA'sı için denetleme listesi.

Sürüm notu: Bu yazıdaki örnekler Angular 22.2 (TypeScript 6.0), @angular/build 22.2.7, @angular/service-worker 22.2.6, web-features 3.46.0, Node.js 24 ve Playwright 1.65 ile denenmiştir. Destek bilgileri MDN'in (Mozilla'nın web platformu dokümantasyonu) browser-compat-data (BCD) 8.1.9 ve web-features 3.46 (Kasım 2026) verilerinden okunmuştur; eski Angular sürümlerinin API'leri npm'deki paketlerin tip tanımlarından karşılaştırılmıştır.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore'un (bir online kitapçı) Angular istemcisi Angular 22 ile derleniyor ve Angular CLI'ın varsayılan tarayıcı hedefi "Baseline widely available". Ekipten biri şöyle düşünüyor: "Angular zaten yalnız Baseline'daki tarayıcıları hedefliyor; Navigation API de Ocak 2026'da Baseline oldu. O zaman navigation.addEventListener'ı feature detection yapmadan kullanabiliriz." Haklı mı?

Bu yazıda geriye bakıyoruz. 2020'de bir Angular PWA'sı (Progressive Web App; tarayıcıdan kurulabilen web uygulaması) yazan biri için tarayıcı ve Angular tarafında neler değişti, Baseline etiketleri nasıl okunur ve eski bir Angular PWA'sını bugüne getirirken neye bakmak gerekir? Önceki dokuz yazıda kullandığımız her özelliği tek bir raporda topluyoruz.

Baseline Nedir ve Nasıl Okunur?

Baseline, W3C'deki (World Wide Web Consortium; web standartlarını yayınlayan kuruluş) WebDX Community Group'un 2023'te başlattığı bir etiket: bir web platformu özelliğinin "çekirdek tarayıcı setinin" hepsinde, yani Chrome, Edge, Firefox ve Safari'nin masaüstü ve mobil sürümlerinde, kararlı olarak desteklenip desteklenmediğini söylüyor. İki seviyesi var. Newly available, özelliğin bu setteki son tarayıcıya da geldiği gün; widely available, o günden 30 ay sonrası. 30 ay, kullanıcıların çoğunun o tarayıcı sürümüne güncellemiş olacağı varsayımı. Bir özellik bu ikisinin hiçbiri değilse "limited availability": en az bir tarayıcıda yok.

Etiketin kaynağı web-features paketi. Bu paket özellikleri geliştiricinin düşündüğü birimlerle tanımlıyor (ör. "cookie-store") ve her birini MDN'in browser-compat-data'sındaki (BCD) ayrıntılı anahtarlara bağlıyor (ör. api.CookieStore.get). Bu bağ önemli, çünkü bir özelliğin bütünü ile senin gerçekten kullandığın parça farklı durumda olabilir. Bu serinin storage yazısında cookieStore'un Firefox 140 ve Safari 18.4 ile bütün motorlara geldiğini yazmıştık; web-features ise "cookie-store" özelliğini Baseline saymıyor. Sebebi aşağıdaki raporda: özelliğin içinde service worker'dan cookie değişikliklerine abone olmayı sağlayan CookieStoreManager da var ve Safari'de yok. cookieStore.get ve set ise Haziran 2025'ten beri Baseline Newly Available. Baseline'ı okurken özelliğin adına değil, kullandığın anahtarlara bak.

Bookstore'un Kullandığı Özellikler: Bir Baseline Raporu

Seri boyunca kullandığımız tarayıcı özelliklerinin durumunu elle tablolamak yerine web-features'tan okuyan küçük bir script yazdım. Paket kök projede bir devDependency (npm run baseline):

// 10: bu serinin kullandığı tarayıcı özelliklerinin Baseline durumu, web-features'tan okunur
// Çalıştırmak için: npm run baseline
import { features } from "web-features";

// [web-features id'si, yazı, gerçekten çağırdığımız compat anahtarları (özellik kullandığımızdan büyükse)]
const used: [string, string, string[]?][] = [
  ["abortsignal-any", "01"],
  ["fetch-request-streams", "01"],
  ["fetchlater", "01"],
  ["cookie-store", "02", ["api.Window.cookieStore", "api.CookieStore.get", "api.CookieStore.set"]],
  ["origin-private-file-system", "02"],
  ["storage-buckets", "02"],
  ["indexeddb", "03"],
  ["service-workers", "04"],
  ["manifest", "06"],
  ["beforeinstallprompt", "06"],
  ["navigator-install", "06"],
  ["badging", "06"],
  ["push", "07"],
  ["background-sync", "07"],
  ["scheduler", "08"],
  ["shared-workers", "08"],
  ["event-timing", "08"],
  ["web-locks", "09"],
  ["broadcast-channel", "09"],
  ["navigation", "09"],
];

type Status = { baseline: "high" | "low" | false; baseline_low_date?: string; baseline_high_date?: string; support: Record<string, string> };

function describe(status: Status): string {
  if (status.baseline === "high") return `widely available since ${status.baseline_high_date}`;
  if (status.baseline === "low") return `newly available since ${status.baseline_low_date}`;
  const engines = Object.keys(status.support).filter((b) => !b.endsWith("_android") && !b.endsWith("_ios"));
  return `limited: ${engines.join(", ") || "no stable browser"}`;
}

for (const [id, post, keys] of used) {
  const feature = features[id] as { kind: string; status: Status & { by_compat_key?: Record<string, Status> } };
  console.log(`${post} ${id.padEnd(27)} ${describe(feature.status)}`);
  for (const key of keys ?? []) console.log(`     ${key.padEnd(30)} ${describe(feature.status.by_compat_key![key])}`);
}
01 abortsignal-any             widely available since 2026-09-19
01 fetch-request-streams       limited: chrome, edge
01 fetchlater                  limited: chrome, edge
02 cookie-store                limited: chrome, edge, firefox
     api.Window.cookieStore         newly available since 2025-06-24
     api.CookieStore.get            newly available since 2025-06-24
     api.CookieStore.set            newly available since 2025-06-24
02 origin-private-file-system  widely available since 2025-09-27
02 storage-buckets             limited: chrome, edge
03 indexeddb                   widely available since 2024-03-20
04 service-workers             widely available since 2020-10-30
06 manifest                    limited: chrome, edge, safari
06 beforeinstallprompt         limited: chrome, edge
06 navigator-install           limited: no stable browser
06 badging                     limited: chrome, edge, safari
07 push                        widely available since 2025-09-27
07 background-sync             limited: chrome, edge
08 scheduler                   limited: chrome, edge, firefox
08 shared-workers              newly available since 2026-05-05
08 event-timing                newly available since 2025-12-12
09 web-locks                   widely available since 2024-09-14
09 broadcast-channel           widely available since 2024-09-14
09 navigation                  newly available since 2026-01-13

Rapor serinin özeti gibi. Service worker, IndexedDB, Push, OPFS (Origin Private File System; origin'e özel dosya sistemi), Web Locks ve BroadcastChannel widely available: bugün feature detection olmadan kullanılabilir. Navigation API, Event Timing ve SharedWorker newly available: son sürümlerde var ama eski bir iPhone'da olmayabilir. Upload streaming, fetchLater, Storage Buckets, Background Sync ve beforeinstallprompt yalnız Chromium'da. navigator.install web-features'ta henüz kararlı hiçbir tarayıcıda görünmüyor; BCD'ye göre Chrome 154'te flag arkasında, Kurulabilir PWA yazısında Playwright'ın Chromium 158'inde flag'siz tanımlı olduğunu görmüştük. Manifest ve Badging "limited": Firefox masaüstünde manifest tabanlı kurulum yok, Badging ise Firefox'ta ve Chrome Android'de yok. Bu rapor web-features sürümüne bağlı: paket her ay güncelleniyor ve aynı script'i yeni sürümle çalıştırınca durumlar değişir.

Angular'ın Tarayıcı Hedefi: "baseline widely available on"

Angular CLI'ın build paketinin kaynağında varsayılan browserslist sorgusu sabit bir tarihle yazılmış: @angular/build 22.2.7'de baseline widely available on 2026-05-07. Projede bir .browserslistrc yoksa build bu sorguyu kullanıyor. Sorgunun karşılığını browserslist 4.29 ile çıkardım:

and_chr  157 ... 157 (1 versions)
and_ff   160 ... 160 (1 versions)
chrome   119 ... 157 (39 versions)
edge     119 ... 156 (38 versions)
firefox  119 ... 160 (42 versions)
ios_saf  17.0 ... 27.0 (21 versions)
safari   17.0 ... 27.2 (23 versions)

Tahminin cevabı burada: hayır. Angular'ın hedefi, 7 Mayıs 2026 itibarıyla widely available olan özellikleri destekleyen tarayıcılar; en alt sınır Chrome ve Edge 119, Firefox 119, Safari ve iOS 17.0. Navigation API ise Safari 26.2'de geldi ve Ocak 2026'da yalnız newly available oldu. Angular'ın hedeflediği bir iPhone'da (iOS 17 ya da 18) navigation yok. Ayrıca bu hedef yalnız Angular'ın derlediği JavaScript syntax'ını ve CSS'i belirliyor; tarayıcı API'leri için polyfill eklemiyor. Kendi kodunda kullandığın her API için durumu ayrıca kontrol etmen gerekiyor: widely available değilse feature detection şart.

2020'den 2026'ya Tarayıcı Tarafındaki Dönüm Noktaları

2020'de service worker zaten widely available olmuştu (web-features'a göre Ekim 2020); Angular Service Worker ile offline çalışan bir uygulama bütün büyük tarayıcılarda mümkündü. Eksik olan, iOS'ta uygulamanın bir "uygulama" gibi davranmasıydı. En büyük değişiklik Mart 2023'te iOS 16.4 ile geldi: ana ekrana eklenmiş web app'lerde Web Push, Badging API ve manifest'teki id. Aynı dönemde OPFS ve OffscreenCanvas Safari 16.4 ile, Compression Streams ise Mayıs 2023'te Firefox 113 ile Baseline oldu. Push böylece Mart 2023'te newly, Eylül 2025'te widely available.

2024'te AbortSignal.any (Mart 2024, Fetch yazısındaki kullanıcı iptali ile timeout'u birleştirme) geldi ve IndexedDB widely available oldu. 2025'te cookieStore'un temel API'si Firefox 140 ile (Haziran 2025) bütün motorlara ulaştı, Event Timing Safari 26.2 ile (Aralık 2025) Baseline oldu. 2026'da Navigation API Firefox 147 ve Safari 26.2 ile Ocak'ta, SharedWorker Chrome Android 148 ile Mayıs'ta Baseline oldu; Chrome 155 ile unload event'inin kaldırılması tamamlandı (Sekmeler yazısında Chromium 158'de hiç çalışmadığını gördük). Aynı dönemde Chromium tek başına ilerledi: fetchLater ve native Observable Chrome 135'te, navigator.install Chrome 154'te flag arkasında geldi. Background Sync, Periodic Background Sync, Storage Buckets ve beforeinstallprompt hâlâ yalnız Chromium'da.

Angular Service Worker'da Değişenler

Angular tarafındaki değişiklikleri ezberden yazmak yerine npm'deki @angular/service-worker paketlerinin tip tanımlarını sürüm sürüm karşılaştırdım (12.2'den 22.0'a kadar; router için 22.2'nin tiplerine baktım):

SürümDeğişiklik
13.0SwUpdate.versionUpdates geldi; available ve activated deprecated; checkForUpdate() ve activateUpdate() artık Promise<boolean> dönüyor
16.0Standalone uygulamalar için provideServiceWorker()
17.0SwUpdate.available ve SwUpdate.activated kaldırıldı
20.1SwPush.notificationCloses ve SwPush.pushSubscriptionChanges
21.1Router'da deneysel withExperimentalPlatformNavigation() (Navigation API)
22.0HttpClient varsayılan olarak Fetch kullanıyor, withFetch() deprecated

2020-2021'de yazılmış tipik bir güncelleme kontrolünü Angular 22'de derlemeyi denedim:

// Angular 12 döneminden bir güncelleme kontrolü, Angular 22 ile derleniyor
import { inject } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';

export function legacyUpdates() {
  const updates = inject(SwUpdate);
  updates.available.subscribe(() => updates.activateUpdate().then(() => document.location.reload()));
  updates.activated.subscribe((event) => console.log(event.previous, event.current));
}
✘ [ERROR] TS2339: Property 'available' does not exist on type 'SwUpdate'. [plugin angular-compiler]
    src/app/legacy-check.ts:7:10:
✘ [ERROR] TS2339: Property 'activated' does not exist on type 'SwUpdate'. [plugin angular-compiler]
    src/app/legacy-check.ts:8:10:
✘ [ERROR] TS7006: Parameter 'event' implicitly has an 'any' type. [plugin angular-compiler]
    src/app/legacy-check.ts:8:31:

Karşılığı Angular Service Worker yazısındaki AppUpdates: versionUpdates'te VERSION_READY event'ini beklemek, kullanıcıya bir banner göstermek ve yenilemeyi ona bırakmak. Eski koddaki "yeni sürüm gelir gelmez activateUpdate() ve reload()" alışkanlığı da sorunlu: kullanıcının yazdığı formu bir anda silebilir. ServiceWorkerModule.register() ise 22'de hâlâ var ve çalışıyor; standalone bir uygulamada provideServiceWorker() aynı işi yapıyor.

Eski Bir Angular PWA'sını Denetleme Listesi

Bu serideki her yazıdan çıkan kontrolleri bir listede topladım. 2020-2022 arasında yazılmış bir Angular PWA'sını devraldığında sırayla bunlara bak:

  • Güncelleme kontrolü: available/activated yerine versionUpdates ve unrecoverable dinleniyor mu, yenilemeye kullanıcı mı karar veriyor? (05)
  • Deploy header'ları: ngsw.json, index.html, ngsw-worker.js ve manifest no-cache, hash'li dosyalar immutable mı; eski hash'li dosyalar birkaç sürüm tutuluyor mu? (05)
  • dataGroups: kişiye özel endpoint'ler (sipariş, sepet, profil) hiçbir gruba girmiyor mu? NGSW (Angular Service Worker) Vary'i yok sayıyor. (05)
  • Kill switch: safety-worker.js'i yayınlama prosedürü yazılı mı? (04, 05)
  • Manifest: id yazılı mı, any ve maskable icon'lar ayrı mı, screenshots ve description var mı? (06)
  • Install teklifi ve izinler: sayfa açılır açılmaz install ya da bildirim izni istenmiyor mu? (06, 07)
  • Web Push: VAPID (sunucunun push service'e kendini imzalı bir token'la tanıtması) private key'i secret store'da mı, 404/410 dönen subscription'lar siliniyor mu, endpoint'ler bir allow-list ile kontrol ediliyor mu? (07)
  • Storage: QuotaExceededError yakalanıyor mu, kalıcı olması gereken veri için persist() isteniyor mu, büyük JSON localStorage'da mı tutuluyor? (02, 03)
  • Sekmeler: paylaşılan işler (outbox, poll, token yenileme) Web Locks ile tek sekmeye verilmiş mi, kapanışta unload kullanılıyor mu? (09)
  • Main thread: ağır hesaplar worker'da mı, INP (Interaction to Next Paint; etkileşimlerin ekrana yansıma süresi) sahadan ölçülüyor mu? (08)
  • Feature detection: widely available olmayan her API (navigation, scheduler.yield, setAppBadge, fetchLater) için bir kontrol ve fallback var mı? (10)

Üretimde Dikkat

Feature detection ile progressive enhancement aynı şeyin iki yüzü. Detection, API'nin var olup olmadığını kontrol eder ('setAppBadge' in navigator, 'scheduler' in globalThis); enhancement, API yoksa da uygulamanın temel işini yapmasını sağlar. Bu serideki örneklerin hepsi bu kalıba uyuyor: badge yoksa sayı header'da görünüyor, scheduler.yield yoksa setTimeout, Background Sync yoksa online event'i, beforeinstallprompt yoksa Safari için talimat. User agent string'inden tarayıcı tahmin etmek yerine her zaman özelliğin kendisini kontrol et; TypeScript'in lib.dom.d.ts'inin bir API'yi her yerde var sayabileceğini Web Worker yazısında gördük.

Baseline verisini güncel tut. web-features ve BCD sık güncelleniyor; bu yazıdaki rapor 3.46 sürümüyle alındı ve birkaç ay sonra farklı sonuç verecek. Raporu CI'da ayda bir çalıştırıp değişiklikleri gözden geçirmek, "artık feature detection'a gerek yok" kararlarını veriyle vermeni sağlar. Kullanıcıların gerçek tarayıcı dağılımı da önemli: kurumsal müşterileri eski bir Windows ve eski bir Edge ile çalışan Bookstore için widely available bile her zaman yeterli olmayabilir; analytics'teki tarayıcı sürümlerine bak.

Sık Düşülen Tuzaklar

  • "Angular hedefi Baseline, o zaman her Baseline API'yi kullanabilirim" demek. Angular'ın hedefi widely available ve sabit bir tarihe bağlı; newly available API'ler için feature detection gerekir.
  • Bir özelliğin Baseline durumunu adından okumak. Kullandığın BCD anahtarlarına bak; cookieStore örneğindeki gibi parça ile bütün farklı olabilir.
  • Angular sürümünü yükseltirken service worker kodunu derleyiciye bırakmak. available derleme hatası verir, ama "gelir gelmez yenile" davranışı derlenir ve sorun olmaya devam eder.
  • Chromium'a özel API'leri (beforeinstallprompt, Background Sync, fetchLater) tek yol olarak kullanmak. Safari ve Firefox kullanıcıları için bir fallback olmalı.
  • Eski bir test cihazına ya da emülatöre güvenip gerçek kullanıcıların tarayıcı dağılımına bakmamak.

Küçük Bir Deneme

★☆☆ baseline-report.ts'e serinin kullandığı iki özellik daha ekle: view-transitions ve compression-streams. Hangi durumda olduklarını ve hangi tarihten beri bu durumda olduklarını yaz.

★★☆ Bookstore'a bir .browserslistrc ekleyip hedefi baseline widely available yerine baseline 2024 yap ve ng build'in verdiği uyarıyı oku. Angular'ın desteklediği aralığın dışına çıkınca ne söylüyor?

★★★ baseline-report.ts'i, kaynak kodda geçen API adlarını (navigator.locks, navigation., scheduler.yield, setAppBadge…) arayıp her biri için durum ve "bu dosyada feature detection var mı" bilgisini yazan bir denetim aracına çevir. Bookstore'da widely available olmayan ve feature detection'ı olmayan bir kullanım bulursan düzelt.

Bookstore'un Angular istemcisi Fetch ile veriyi akış hâlinde okuyor, doğru storage'ı seçiyor, IndexedDB'de offline outbox tutuyor, Angular Service Worker ile offline açılıyor, kurulabiliyor, bildirim alıyor, ağır işi worker'da yapıyor ve sekmeleri koordine ediyor. Serinin son yazısı, uygulamanın cihazla konuştuğu API'leri (pano, paylaşım, ekranın uyumaması, tam ekran, izinler ve konum) uygulamalı olarak ele alıyor. Bu yeteneklerin performansa etkisini ölçmek ve iyileştirmek Web Performansı serisinin konusu.