Makale

Aşamalı Web Uygulamaları (PWA'lar)

Aşamalı Web Uygulamaları (PWA'lar)

Aşamalı Web Uygulaması (PWA), uygulamaya benzer bir deneyim sunmak için modern tarayıcı özelliklerini kullanan bir web uygulamasıdır. PWA'lar güvenilir, hızlı ve ilgi çekicidir; web erişimini yerel mobil uygulamaların yetenekleriyle birleştirir.

5 dk okumaDil: TR TürkçeÜcretsiz0 alkış0 yorum
TeknolojiMühendislik MakaleleriAppsProgressiveWeb DevelopmentTechnologyEngineering ArticlesPWAs
Okuma seçenekleri

Giriş

Aşamalı Web Uygulaması (PWA), uygulamaya benzer bir deneyim sunmak için modern tarayıcı özelliklerini kullanan bir web uygulamasıdır. PWA'lar güvenilir, hızlı ve ilgi çekicidir; web erişimini yerel mobil uygulamaların yetenekleriyle birleştirir.

PWA'lar temel bir sorunu çözüyor: Kullanıcılar web'in anında kullanılabilirliğini istiyor (kurulum yok, bağlantı kurulabilir, her zaman güncel) ancak yerel uygulamaların performansını ve özelliklerini (çevrimdışı destek, anında bildirimler, ana ekran varlığı) bekliyorlar. PWA'lar her ikisini de sağlar.


Temel Özellikler

"Progresif Web Uygulaması" terimi, 2015 yılında Google'dan Alex Russell ve Frances Berriman tarafından icat edildi. Bir PWA'nın şu 10 özelliği karşılaması gerekir:

# Prensip Neden Önemlidir?
1 Aşamalı — Herkes için işe yarar Eski tarayıcılarda zarif bozulma
2 Duyarlı — Her ekrana sığar Masaüstü, tablet, mobil
3 Bağlantıdan bağımsız — Çevrimdışı çalışır Hizmet çalışanının önbelleğe alınması
4 Uygulama benzeri — Yerel uygulama hissi Kabuk mimarisi, sorunsuz gezinme
5 Taze — Her zaman güncel Hizmet çalışanı güncelleme yaşam döngüsü
6 Güvenli — HTTPS üzerinden sunulur Servis çalışanları için gerekli olan kurcalamayı önler
7 Keşfedilebilir — SEO dostu Arama motorları PWA'ları dizine ekler
8 Yeniden etkinleştirilebilir — Anlık bildirimler Yerel uygulamalar gibi kullanıcılarla yeniden etkileşime geçin
9 Yüklenebilir — Ana ekrana ekle Web uygulaması bildirimi
10 Bağlanabilir — URL aracılığıyla paylaşın Uygulama mağazasına gerek yok

PWA'nın Üç Sütunu

1. Servis Çalışanı — Motor

Hizmet çalışanı, web sayfasından ayrı olarak arka planda çalışan bir JavaScript dosyasıdır. Programlanabilir bir ağ proxy'si görevi görerek istekleri yakalar ve çevrimdışı işlevsellik, anında bildirimler ve arka planda senkronizasyon sağlar.

Hizmet Çalışanı Yaşam Döngüsü

Installing → Installed → Activating → Activated → Idle → Terminated
                 │                                        │
                 └─── (new version detected) ──────────────┘
                 └─── Waiting (until all tabs close) ─────┘
// service-worker.js
const CACHE_NAME = 'my-pwa-v2';
const ASSETS_TO_CACHE = [
  '/',
  '/index.html',
  '/styles.css',
  '/app.js',
  '/offline.html',
  '/icons/icon-192.png'
];

// Install event — cache static assets
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      console.log('Caching app shell');
      return cache.addAll(ASSETS_TO_CACHE);
    })
  );
  // Force new service worker to activate immediately
  self.skipWaiting();
});

// Activate event — clean old caches
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames
          .filter(name => name !== CACHE_NAME)
          .map(name => caches.delete(name))
      );
    })
  );
  // Take control of all open pages immediately
  clients.claim();
});

// Fetch event — intercept network requests
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      // Return cached response if available
      if (cachedResponse) {
        return cachedResponse;
      }

      // Otherwise fetch from network
      return fetch(event.request).then(networkResponse => {
        // Don't cache non-GET or error responses
        if (!event.request.url.includes('/api/')) {
          return networkResponse;
        }

        // Cache API responses for offline use
        const responseClone = networkResponse.clone();
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, responseClone);
        });

        return networkResponse;
      }).catch(() => {
        // Network failed — return offline fallback
        if (event.request.mode === 'navigate') {
          return caches.match('/offline.html');
        }
        return new Response('Offline', { status: 503 });
      });
    })
  );
});

Önbelleğe Alma Stratejileri

Strateji Açıklama Kullanım Örneği
Önce Önbellek Önbelleği kontrol edin, ağa geri dönün Statik varlıklar (CSS, JS, resimler)
Önce Ağ Ağı deneyin, önbelleğe geri dönün API çağrıları, dinamik içerik
**Yeniden Doğrulama Sırasında Eski ** Önbelleği döndür, arka planda güncelle Haber akışları, blog gönderileri
Yalnızca Ağ Her zaman ağdan getir Hassas veriler (bankacılık)
Yalnızca Önbellek Hiçbir zaman ağdan getirme Uygulama kabuğu
// Stale-while-revalidate strategy
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      const fetchPromise = fetch(event.request).then(networkResponse => {
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, networkResponse.clone());
        });
        return networkResponse;
      }).catch(() => cachedResponse);

      return cachedResponse || fetchPromise;
    })
  );
});

2. Web Uygulaması Bildirimi — Kimlik

Bildiri, PWA'nın yüklendiğinde nasıl görüneceğini kontrol eden bir JSON dosyasıdır:

{
  "name": "My Progressive Web App",
  "short_name": "MyPWA",
  "description": "An amazing PWA that works offline",
  "start_url": "/?source=pwa",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#3367D6",
  "orientation": "portrait-primary",
  "scope": "/",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ],
  "categories": ["productivity", "utilities"],
  "lang": "en-US",
  "dir": "ltr",
  "prefer_related_applications": false
}

Açıklanan manifest özellikleri:

  • display: standalone — Tarayıcı kullanıcı arayüzü (adres çubuğu, sekmeler) olmadan açılır.
  • display: fullscreen — Tam ekran, tarayıcı kromu yok.
  • display: minimal-ui — Minimum tarayıcı kontrolü.
  • scope: "/" — Hangi URL'lerin PWA'nın parçası olduğu.
  • start_url — PWA başlatıldığında açılan sayfa.
  • Maskelenebilir simgeler — İşletim sistemi düzeyinde maskelemeyle çalışan uyarlanabilir simgeler (yuvarlak, sincap vb.).

3. HTTPS — Temel

Hizmet çalışanları güvenli bir bağlama ihtiyaç duyar. HTTPS aşağıdakiler için zorunludur:

  • Servis çalışanı kaydı.
  • Bildirimleri itin.
  • Yükleme istemi (unload olayından önce).
# Redirect HTTP to HTTPS
# Nginx
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

Bir PWA Oluşturmak — Adım Adım

1. Uygulama Kabuğunu Oluşturun

Uygulama kabuğu, kullanıcı arayüzünü oluşturmak için gereken minimum HTML, CSS ve JavaScript'tir. İlk yüklemede önbelleğe alınır ve PWA'nın temeli olarak hizmet eder.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="theme-color" content="#3367D6">
  <link rel="manifest" href="/manifest.json">
  <link rel="icon" href="/icons/icon-192.png" sizes="192x192">
  <link rel="apple-touch-icon" href="/icons/icon-192.png">
  <title>My PWA</title>
  <link rel="stylesheet" href="/styles.css">
</head>
<body>
  <header id="app-header">My PWA</header>
  <main id="app-content"></main>
  <footer id="app-footer">© 2026</footer>

  <!-- Register service worker -->
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
          .then(reg => console.log('SW registered:', reg.scope))
          .catch(err => console.error('SW registration failed:', err));
      });
    }
  </script>
  <script src="/app.js"></script>
</body>
</html>

2. Çevrimdışı Desteği Uygulayın

// app.js — Fetch content with offline support
const CACHE_KEY = 'content-cache';

async function loadContent(url) {
  try {
    const response = await fetch(url);
    const data = await response.json();

    // Cache for offline
    const cache = await caches.open(CACHE_KEY);
    cache.put(url, new Response(JSON.stringify(data)));

    renderContent(data);
  } catch (error) {
    // Offline — load from cache
    const cached = await caches.match(url);
    if (cached) {
      const data = await cached.json();
      renderContent(data);
      showOfflineIndicator();
    } else {
      showOfflineMessage();
    }
  }
}

3. Anlık Bildirimler Ekleyin

// Request permission
async function requestNotificationPermission() {
  const permission = await Notification.requestPermission();
  if (permission === 'granted') {
    // Get push subscription
    const registration = await navigator.serviceWorker.ready;
    const subscription = await registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(publicKey)
    });

    // Send subscription to server
    await fetch('/api/push/subscribe', {
      method: 'POST',
      body: JSON.stringify(subscription)
    });
  }
}
// service-worker.js — Handle push events
self.addEventListener('push', event => {
  const data = event.data.json();

  const options = {
    body: data.body,
    icon: '/icons/icon-192.png',
    badge: '/icons/badge-72.png',
    vibrate: [100, 50, 100],
    data: { url: data.url },
    actions: [
      { action: 'open', title: 'Open' },
      { action: 'close', title: 'Dismiss' }
    ]
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();

  if (event.action === 'open' || !event.action) {
    clients.openWindow(event.notification.data.url);
  }
});

PWA ve Yerel Uygulama

Özellik PWA Yerel Uygulama
Dağıtım URL (mağaza gerekmez) App Store, Google Play
Sürtünmeyi kurun Tek dokunuşla (tarayıcı istemi) İndirme, yükleme, izinler
Dosya boyutu KB'den MB'ye 10MB - 500MB+
Güncellemeler Anında (hizmet çalışanı) Uygulama mağazası incelemesi yoluyla
Çevrimdışı Evet (hizmet çalışanı) Evet (yerleşik)
Anlık bildirimler Evet Evet
Cihaz API'leri Kamera, GPS, ivmeölçer, ödeme Tüm cihaz API'lerine tam erişim
Bluetooth Web Bluetooth (sınırlı) Tam Bluetooth API'si
Arka plan görevleri Arka planda senkronizasyon (sınırlı) Tam arka planda yürütme
Performans Yerele yakın (JavaScript/WebAssembly) Yerel (derlenmiş kod)
SEO Arama motorları tarafından indekslenebilir Dizine eklenemez
Geliştirme maliyeti Tek kod tabanı iOS + Android (veya platformlar arası)
Kullanıcıyı elde tutma Daha düşük (ayrılması daha kolay) Daha yüksek (kurulu = kararlı)

Yerel Yerine PWA'yı Ne Zaman Seçmelisiniz?

  • İçerik odaklı uygulamalar — Haberler, bloglar, dergiler.
  • E-ticaret — Alışveriş siteleri (Pinterest PWA: %40 daha fazla zaman harcandı).
  • Yardımcı uygulamalar — Hesap makineleri, dönüştürücüler, hava durumu.
  • Düşük etkileşimli uygulamalar — Kullanıcıların nadiren ziyaret ettiği uygulamalar.
  • Gelişen pazarlar — Sınırlı depolama alanına ve verilere sahip kullanıcılar.
  • Aşamalı geliştirme — Modern cihazlarda tam deneyim, eski cihazlarda işlevsel.

Yerel Uygulama Daha İyi Olduğunda

  • Yüksek performanslı oyun — 60+ FPS, karmaşık 3D oluşturma.
  • Derin donanım entegrasyonu — Bluetooth çevre birimleri, NFC, ARKit/ARCore.
  • Arka planda işleme — Müzik akışı, fitness takibi.
  • Yüksek kullanıcı etkileşimi gerekiyor — Sosyal medya, mesajlaşma.

Performans Karşılaştırmaları

Metrik PWA'dan önce PWA'dan sonra İyileştirme
İlk yükleme 5'ler 1,2 saniye %76 daha hızlı
Sonraki yükler 3'ler 0,3s %90 daha hızlı
Hemen çıkma oranı 45% 20% %55 azalma
Dönüşüm oranı 2% 3.5% %75 artış
Oturum başına sayfa sayısı 3 5 %66 artış

Gerçek dünya sonuçları:

Şirket Anahtar Metrik İyileştirme
Twitter (X) Lite Oturum başına gönderilen Tweetler %75 artış
Pinterest'te Harcanan zaman %40 artış
Über Rezervasyonun tamamlanması 2G'de bile sorunsuz
Starbucks Günlük aktif kullanıcılar 2 kat artış
Alibaba'nın Dönüşüm oranı %76 artış

PWA Testi ve Denetimi

Lighthouse PWA Denetimi

# Run Lighthouse from CLI
npx lighthouse https://example.com --view --preset=desktop

# PWA-specific checks:
# - ✅ Registers a service worker
# - ✅ Responds with 200 when offline
# - ✅ Web app manifest exists
# - ✅ Manifest has display: standalone
# - ✅ Served over HTTPS
# - ✅ Redirects HTTP to HTTPS
# - ✅ Configurable start URL
# - ✅ Icons provided (192px and 512px)

Manuel Test Kontrol Listesi

## PWA Pre-Flight Checklist
- [ ] HTTPS enabled
- [ ] Service worker registered and active
- [ ] Pages load offline (test with airplane mode)
- [ ] Manifest configured with correct icons
- [ ] "Add to Home Screen" prompt appears
- [ ] PWA opens in standalone mode with no address bar
- [ ] Splash screen displays correctly
- [ ] Push notifications work
- [ ] All pages are responsive (mobile, tablet, desktop)
- [ ] Performance budget met (Lighthouse score > 90)
- [ ] Cross-browser tested (Chrome, Firefox, Safari, Edge)
- [ ] Accessibility audit passes

Gelişmiş PWA Özellikleri

Arka Plan Senkronizasyonu

// Register a sync event
async function scheduleSync() {
  const registration = await navigator.serviceWorker.ready;
  await registration.sync.register('sync-pending-data');
}

// Service worker handles sync
self.addEventListener('sync', event => {
  if (event.tag === 'sync-pending-data') {
    event.waitUntil(syncPendingData());
  }
});

Periyodik Arka Plan Senkronizasyonu

// Request periodic sync (requires user engagement)
const registration = await navigator.serviceWorker.ready;
await registration.periodicSync.register('update-content', {
  minInterval: 24 * 60 * 60 * 1000 // Once per day
});

Web Paylaşımı API'si

// Share content using native share sheet
async function shareContent(title, text, url) {
  if (navigator.share) {
    await navigator.share({ title, text, url });
  } else {
    // Fallback to custom share UI
    copyToClipboard(url);
  }
}

Kimlik Kartı API'si

// Set app icon badge
if (navigator.setAppBadge) {
  await navigator.setAppBadge(5); // Show "5" on icon
} else if (navigator.clearAppBadge) {
  await navigator.clearAppBadge();
}

Yaygın Tuzaklar

Tuzak Sorun Çözüm
Aşırı önbelleğe alma Uygulama eski içerik sunuyor Sürüm önbellekleri, kabuk için önbelleği öncelikli, içerik için öncelikli ağı uygulayın
Çevrimdışı geri dönüş yok Beyaz ekran çevrimdışı /offline.html'yi her zaman anlamlı bir mesajla önbelleğe alın
Önbellek bozma hataları Eski servis çalışanı ısrar ediyor skipWaiting() ve client.claim()'i kullanın
Açılış ekranı sorunları Yanlış tema rengi veya simgesi Bildiriyi doğru şekilde yapılandırın, maskelenebilir simgeler kullanın
Safari uyumluluğu Bazı özellikler sınırlıdır (itme, periyodik senkronizasyon) Aşamalı iyileştirme — zarif bir şekilde bozulma
Büyük önbellek boyutu Depolama kotası aşıldı (kaynak başına 50 MB) Eski önbellekleri budayın, önbellek boyutunu sınırlayın
Başlangıç_url'si eksik Ana ekran yanlış sayfayı açıyor Bildirimde her zaman start_url'yi belirtin

Sonuç

Progresif Web Uygulamaları her iki dünyanın da en iyi yönlerini temsil eder; web'in erişimi ve erişilebilirliği ile yerel uygulamaların yetenekleri ve kullanıcı deneyimi bir araya gelir.

PWA Ne Zaman Oluşturulmalı?

  1. Maksimum erişim istiyorsunuz — Tüm platformlar için tek uygulama.
  2. Kullanıcının çevrimdışı erişime ihtiyacı var — Hizmet çalışanının önbelleğe alınması.
  3. Anında yükleme istiyorsunuz — Uygulama kabuğu mimarisi.
  4. Yeniden etkileşime geçmek istiyorsunuz — Uygulama mağazası olmadan anlık bildirimler.
  5. İçerik odaklı bir uygulamanız var - Haberler, e-ticaret, yardımcı programlar.

Başlarken

  1. Bir manifest.json ve simgeler ekleyin.
  2. Çevrimdışı geri dönüşe sahip bir hizmet çalışanı oluşturun.
  3. Lighthouse denetimi çalıştırın ve kritik sorunları düzeltin.
  4. Gerçek cihazlarda (Android, iOS, masaüstü) test edin.
  5. Kullanıcı etkileşimini dağıtın ve ölçün.

PWA'lar her senaryoda yerel uygulamaların yerini almaz; ancak içerik odaklı ve yardımcı program uygulamalarının çoğu için, geliştirme maliyetinin çok küçük bir kısmıyla üstün bir kullanıcı deneyimi sağlarlar.

Öne Çıkan Makaleler

2026’da Oluşturmaya Değer 50 Claude Skill
EditoryalTR
8 dkÜcretsiz

2026’da Oluşturmaya Değer 50 Claude Skill

Claude Skills, tekrarlanan promptları yeniden kullanılabilir workflow’lara dönüştürebilir. İşte yazma, kodlama, araştırma, iş, üretkenlik, tasarım, analiz ve destek için 50 pratik Claude Skill.

TeknolojiAIAi GuidesAI Agents
0 alkış
Oku
Senior Engineer’lardan Öğrendiğim 6 Kodlama Pattern’i
EditoryalTR
8 dkÜcretsiz

Senior Engineer’lardan Öğrendiğim 6 Kodlama Pattern’i

TeknolojiCodeProgrammingCoding
0 alkış
Oku
Özel Bir Yapay Zeka Not Asistanı Kurun
Öne çıkanTR
9 dkÜcretsiz

Özel Bir Yapay Zeka Not Asistanı Kurun

Markdown notlarını özel taslakları açığa çıkarmadan aranabilir bir asistana dönüştürün.

TeknolojiPlatform RehberleriYapay Zeka YazımıAIAutomationData
0 alkış
Oku

Yorumlar

0 yorum

Henüz onaylı yorum yok. Yeni yanıtlar moderasyon bekleyebilir.