PWA Nedir? Adım Adım PWA İskeleti Kurulumu

## PWA Nedir, Hangi Problemi Çözer? Progressive Web App (PWA), tarayıcıda çalışan bir web uygulamasına, kurulabilirlik, çevrimdışı çalışma ve arka pl...

PWA Nedir? Adım Adım PWA İskeleti Kurulumu

PWA Nedir, Hangi Problemi Çözer?

Progressive Web App (PWA), tarayıcıda çalışan bir web uygulamasına, kurulabilirlik, çevrimdışı çalışma ve arka plan yetenekleri kazandıran bir yaklaşımdır. Ayrı bir teknoloji değil; mevcut web platformunun belirli API'lerini ve tarayıcı sözleşmelerini bir arada kullanmaktır.

Temel yapı taşları şunlardır:

  • HTTPS (veya localhost): Servis çalışanı ve diğer güçlü API'ler yalnızca güvenli bağlamda çalışır.
  • Web App Manifest: Uygulamanın adı, ikonları, başlangıç URL'i ve görüntüleme modu gibi meta veriler.
  • Service Worker: Ağ isteklerini yakalayan, önbellekleme ve çevrimdışı davranışı yöneten arka plan betiği.

Bu rehber, orta seviye bir geliştiricinin sıfırdan çalışan bir PWA iskeleti kurmasını hedefler. Örnekler framework bağımsızdır; vanilla JavaScript ve standart tarayıcı API'leri kullanılır. Belirli bir tarayıcı sürümüne bağlı davranışlardan kaçınılır, çünkü PWA API'leri tarayıcılar arasında farklı hızlarda olgunlaşır.

Önkoşullar

  • HTML, CSS ve JavaScript'e hâkimiyet.
  • Uygulamanın https:// üzerinden (geliştirmede http://localhost) sunulması.
  • Basit bir statik sunucu veya mevcut bir web uygulaması.
  • Tarayıcı geliştirici araçlarında Application sekmesini kullanabilme.

Adım 1: Web App Manifest Ekle

Manifest, tarayıcıya uygulamanın nasıl kurulacağını anlatır. Kök dizine manifest.webmanifest adında bir dosya koy:

{
  "name": "Örnek PWA",
  "short_name": "Örnek",
  "start_url": "/",
  "scope": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0d6efd",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512-maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

HTML <head> içinde manifest'i bağla:

<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0d6efd">

Beklenen davranış: Tarayıcı manifest'i ayrıştırır; kurulum koşulları sağlandığında adres çubuğunda veya menüde "Yükle" seçeneği görünür. display: "standalone" seçildiğinde kurulu uygulama tarayıcı arayüzü olmadan açılır.

Dikkat: start_url ve scope değerlerinin uygulamanın gerçek yollarıyla uyumlu olması gerekir. scope dışına çıkan bağlantılar PWA penceresinden çıkar.

Adım 2: Service Worker'ı Kaydet

Service worker, ana sayfadan ayrı bir dosyadır ve kendi kapsamı (scope) içindeki istekleri kontrol eder. Kök dizinde sw.js oluştur ve sayfada kaydettir:

<script>
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
      navigator.serviceWorker.register('/sw.js')
        .then((reg) => {
          console.log('Service worker kayıtlı, kapsam:', reg.scope);
        })
        .catch((err) => {
          console.error('Kayıt başarısız:', err);
        });
    });
  }
</script>

Beklenen davranış: İlk yüklemede service worker kurulur ve etkinleşir. DevTools'un Application → Service Workers bölümünde durumu görünür. İlk ziyarette sayfa henüz service worker tarafından kontrol edilmez; kontrol bir sonraki yüklemede veya clients.claim() çağrısıyla devreye girer.

Yaygın hata: sw.js dosyasını /js/sw.js gibi bir alt dizine koymak, kapsamı o dizinle sınırlar. Kök kapsam istiyorsan dosya kökte olmalı ya da Service-Worker-Allowed başlığı ayarlanmalıdır.

Adım 3: Önbellekleme Stratejisi Kur

Service worker'ın install ve fetch olaylarını ele alarak temel bir "önce önbellek, sonra ağ" stratejisi kurabilirsin:

const CACHE = 'app-v1';
const PRECACHE = [
  '/',
  '/index.html',
  '/styles.css',
  '/app.js',
  '/manifest.webmanifest'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE).then((cache) => cache.addAll(PRECACHE))
  );
});

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))
      )
    )
  );
});

self.addEventListener('fetch', (event) => {
  if (event.request.method !== 'GET') return;

  event.respondWith(
    caches.match(event.request).then((cached) => {
      return cached || fetch(event.request);
    })
  );
});

Beklenen davranış: İlk kurulumda listedeki dosyalar önbelleğe alınır. Sonraki ziyaretlerde bu dosyalar ağdan değil önbellekten gelir; çevrimdışıyken de açılır.

Önemli noktalar:

  • CACHE adını içerik değiştiğinde artır (örneğin app-v2). activate adımı eski önbellekleri temizler.
  • cache.addAll içindeki herhangi bir dosya 404 dönerse install başarısız olur ve service worker etkinleşmez. Listeyi gerçekten var olan dosyalarla sınırlı tut.
  • Yalnızca GET isteklerini ele almak, form gönderimi gibi isteklerin yanlışlıkla önbelleğe alınmasını önler.

Adım 4: Güncelleme Akışını Yönet

Service worker dosyası bayt düzeyinde değiştiğinde tarayıcı yeni bir sürüm kurar. Ancak yeni sürüm, eski sekmeler kapanana kadar "beklemede" kalabilir. Kullanıcıya güncelleme bildirimi göstermek için:

navigator.serviceWorker.register('/sw.js').then((reg) => {
  reg.addEventListener('updatefound', () => {
    const yeni = reg.installing;
    if (!yeni) return;
    yeni.addEventListener('statechange', () => {
      if (yeni.state === 'installed' && navigator.serviceWorker.controller) {
        // Yeni sürüm hazır; kullanıcıya bildir ve sayfayı yenile
        console.log('Yeni sürüm hazır. Yeniden yükleyin.');
      }
    });
  });
});

Beklenen davranış: Yeni service worker kurulduğunda updatefound tetiklenir; installed durumuna geldiğinde ve sayfa hâlihazırda bir service worker tarafından kontrol ediliyorsa güncelleme mevcuttur.

Yaygın hata: Service worker'ı skipWaiting ile koşulsuz etkinleştirmek, açık sekmelerdeki önbellek ile yeni kod arasında tutarsızlığa yol açabilir. Bunu kullanıcı onayına bağlamak daha güvenlidir.

Adım 5: Çevrimdışı Deneyimi Doğrula

DevTools'ta:

  1. Application → Service Workers altında "Offline" kutusunu işaretle.
  2. Sayfayı yenile.
  3. Önceden önbelleğe alınmış kaynaklar yüklenmeli; önbellekte olmayan istekler başarısız olmalı.

Önbellekte olmayan bir rota için kullanıcıya özel bir çevrimdışı sayfası göstermek istersen, fetch işleyicisinde hata yakalayabilirsin:

event.respondWith(
  caches.match(event.request).then((cached) => {
    if (cached) return cached;
    return fetch(event.request).catch(() => caches.match('/offline.html'));
  })
);

/offline.html dosyasını PRECACHE listesine eklemeyi unutma.

Güvenlik ve Gizlilik Etkileri

  • HTTPS zorunluluğu tesadüfi değildir: Service worker, ağ trafiğini programatik olarak ele alabildiği için araya giren bir aktörün tüm istekleri ele geçirmesini engellemek amacıyla yalnızca güvenli bağlamda çalışır.
  • Önbellek kapsamı: Önbelleğe alınan yanıtlar kullanıcının diskinde kalır. Kişisel veri içeren yanıtları önbelleğe almaktan kaçın; oturum belirteci içeren istekleri fetch işleyicisinde hariç tut.
  • Kapsam sınırı: Service worker yalnızca kayıtlı olduğu kapsam içindeki istekleri görebilir. Kapsamı gereğinden geniş tutmak saldırı yüzeyini artırır.
  • Güncelleme güveni: Service worker dosyası, kaynağından sunulduğu sürece tarayıcı tarafından önbelleğe alınmaz (varsayılan olarak no-cache benzeri davranış). Sunucu tarafında bu dosyaya uzun ömürlü Cache-Control başlığı eklemek güncellemeleri geciktirir.

Yaygın Hatalar Özeti

Hata Sonuç
sw.js dosyasını alt dizine koymak Kapsam daralır, kök istekler kontrol edilmez
PRECACHE listesinde olmayan dosya install başarısız olur, service worker etkinleşmez
CACHE adını hiç değiştirmemek Eski içerik sonsuza kadar önbellekte kalır
Tüm istekleri önbelleğe almak Dinamik/kimlik doğrulamalı yanıtlar yanlış sunulur
skipWaiting'i koşulsuz kullanmak Açık sekmelerde tutarsız durum

Sonraki Adımlar

Temel iskelet çalıştıktan sonra bakılacak başlıklar:

  • Push bildirimleri: PushManager ve notificationclick olayı.
  • Background Sync: Çevrimdışıyken başarısız olan istekleri bağlantı gelince yeniden denemek.
  • Workbox gibi kütüphanelerle önbellekleme stratejilerini (stale-while-revalidate, network-first) hazır şablonlarla kurmak.
  • Lighthouse ile kurulabilirlik ve performans denetimi.

PWA'lar tek seferde mükemmel olmaz; önbellek stratejisini uygulamanın gerçek trafik desenine göre ayarlamak gerekir. Küçük başla, her adımı DevTools üzerinden doğrula, önbellek sürümünü disiplinli biçimde yönet.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz