1. Service Worker: Yaşam Döngüsü ve Kritik Anti-Patterns
Service Worker (SW), PWA’nın kalbidir. Ancak yanlış kullanıldığında, uygulamanızı bir "zombie state"’e sokabilir: kullanıcılar eski verilerle çalışırken, güncellemeler hiçbir zaman yüklenmez. Bu bölümde, SW yaşam döngüsünü SVG diyagramıyla görselleştiriyor ve sık yapılan hataları detaylıca inceliyoruz.
1.1. Yaşam Döngüsü: Register → Install → Activate → Fetch
Aşağıdaki SVG diyagramı, SW yaşam döngüsünü ve kritik geçiş noktalarını gösteriyor:
1.2. Anti-Pattern: skipWaiting() ve clientsClaim() Kullanımı
SW’in güncellenmesi sırasında, eski SW’in hala kontrol ettiği istemciler nedeniyle versiyon çakışmaları yaşanabilir. Bu durumu çözmek için skipWaiting() ve clientsClaim() kullanılır, ancak yanlış kullanım race condition’lara yol açar.
Yanlış Kullanım:
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/styles.css',
'/app.js'
]);
})
);
self.skipWaiting(); // ❌ Yanlış: Install aşamasında çağrılmamalı!
});
Doğru Kullanım:
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/styles.css',
'/app.js'
]);
})
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
self.clients.claim().then(() => {
return self.skipWaiting(); // ✅ Doğru: Activate aşamasında çağrılmalı
})
);
});
2. Offline Caching Stratejileri: Cache First vs. Network First
PWA’larda caching stratejileri, uygulamanın performansı ve kullanıcı deneyimi üzerinde doğrudan etkilidir. Bu bölümde, Cache First, Network First ve Stale-While-Revalidate stratejilerini derinlemesine inceliyoruz.
2.1. Cache First Stratejisi: Hız mı, Güncellik mi?
Cache First stratejisi, öncelikle cache’deki veriyi kullanır ve yalnızca cache’de veri yoksa ağa başvurur. Bu strateji, hızlı yükleme süreleri sağlar, ancak güncel olmayan verilerle çalışma riski taşır.
Örnek Kod:
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request).then((networkResponse) => {
return caches.open('dynamic').then((cache) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
);
});
2.2. Network First Stratejisi: Güncel Veri, Yavaş Yükleme
Network First stratejisi, öncelikle ağdan veri almayı dener ve başarısız olursa cache’e başvurur. Bu strateji, güncel veriler sağlar, ancak ağ bağlantısı yavaş veya kesikse yükleme süreleri uzar.
Örnek Kod:
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(event.request);
})
);
});
2.3. Stale-While-Revalidate: Denge Stratejisi
Stale-While-Revalidate (SWR), cache’deki veriyi hemen döndürürken, arka planda ağdan güncel veriyi alır ve cache’i günceller. Bu strateji, hız ve güncellik arasında denge sağlar.
Örnek Kod:
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
caches.open('dynamic').then((cache) => {
cache.put(event.request, networkResponse.clone());
});
return networkResponse;
});
return cachedResponse || fetchPromise;
})
);
});
3. Cache Yönetimi: Dinamik ve Statik Varlıkların Ayrımı
Cache yönetimi, PWA’nın performansı ve ölçeklenebilirliği için kritik öneme sahiptir. Bu bölümde, dinamik ve statik varlıkların ayrımı ve cache yönetimi için en iyi uygulamaları inceliyoruz.
3.1. Statik Varlıklar: Uzun Süreli Cacheleme
Statik varlıklar (CSS, JS, fontlar, görseller), genellikle uzun süre değişmez. Bu varlıklar için agresif cacheleme stratejileri kullanılmalıdır.
Örnek Kod:
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('static-v1').then((cache) => {
return cache.addAll([
'/styles.css',
'/app.js',
'/logo.png'
]);
})
);
});
3.2. Dinamik Varlıklar: Kısa Süreli Cacheleme
Dinamik varlıklar (API yanıtları, kullanıcı verileri), sık sık değişir. Bu varlıklar için kısa süreli cacheleme veya SWR stratejisi kullanılmalıdır.
Örnek Kod:
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/api/')) {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
caches.open('dynamic').then((cache) => {
cache.put(event.request, networkResponse.clone());
});
return networkResponse;
});
return cachedResponse || fetchPromise;
})
);
}
});
4. Offline Mod: Kullanıcı Deneyimini Koruma Stratejileri
Offline mod, PWA’ların en güçlü özelliklerinden biridir. Ancak, offline modda kullanıcı deneyimini korumak için özel stratejiler geliştirilmelidir.
4.1. Offline Sayfası: Kullanıcıyı Bilgilendirme
Kullanıcı offline olduğunda, uygulamanın offline sayfası göstermesi önemlidir. Bu sayfa, kullanıcıya durum hakkında bilgi verir ve ne yapması gerektiğini açıklar.
Örnek Kod:
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => {
if (event.request.mode === 'navigate') {
return caches.match('/offline.html');
}
return caches.match(event.request);
})
);
});
4.2. Offline Veri Senkronizasyonu: Background Sync
Kullanıcı offline olduğunda yapılan işlemler, bağlantı yeniden sağlandığında senkronize edilmelidir. Background Sync API, bu senkronizasyonu otomatik olarak gerçekleştirir.
Örnek Kod:
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-orders') {
event.waitUntil(
fetch('/api/orders', {
method: 'POST',
body: JSON.stringify({ orders: getPendingOrders() }),
headers: {
'Content-Type': 'application/json'
}
}).then(() => {
return clearPendingOrders();
})
);
}
});
5. Performans ve Güvenlik: Kritik Mühendislik Kararları
PWA’ların performansı ve güvenliği, uygulamanın başarısı için kritik öneme sahiptir. Bu bölümde, performans optimizasyonları ve güvenlik en iyi uygulamaları inceleniyor.
5.1. Performans: Cache Boyutu ve Temizlik Stratejileri
Cache boyutu, uygulamanın performansını doğrudan etkiler. Cache boyutunu sınırlamak ve eski verileri temizlemek önemlidir.
Örnek Kod:
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== 'static-v1' && cacheName !== 'dynamic') {
return caches.delete(cacheName);
}
})
);
})
);
});
5.2. Güvenlik: HTTPS ve Content Security Policy (CSP)
PWA’lar, HTTPS üzerinde çalışmalıdır. Ayrıca, Content Security Policy (CSP) kullanarak güvenlik açıklarını önlemek önemlidir.
Örnek CSP Başlığı:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com;
Sonuç: PWA Mimarisi için Kritik Çıkarımlar
Bu makalede, PWA geliştirmenin derinliklerine indik ve Service Worker yaşam döngüsü, offline caching stratejileri, cache yönetimi, offline mod ve performans/güvenlik konularında kritik mühendislik kararlarını inceledik. İşte öne çıkan çıkarımlar:
- Service Worker yaşam döngüsünü doğru yönetin:
skipWaiting()veclientsClaim()fonksiyonlarını doğru aşamalarda kullanın. - Cache stratejilerini dikkatle seçin: Cache First, Network First veya Stale-While-Revalidate stratejilerini, uygulamanızın ihtiyaçlarına göre belirleyin.
- Dinamik ve statik varlıkları ayrı yönetin: Statik varlıklar için agresif cacheleme, dinamik varlıklar için kısa süreli cacheleme veya SWR kullanın.
- Offline modda kullanıcı deneyimini koruyun: Offline sayfaları ve Background Sync API ile kullanıcıları bilgilendirin ve verileri senkronize edin.
- Performans ve güvenliğe odaklanın: Cache boyutunu sınırlayın, eski verileri temizleyin ve HTTPS/CSP kullanarak güvenlik açıklarını önleyin.
PWA’lar, modern web uygulamalarının geleceğidir. Bu makalede paylaşılan stratejiler ve en iyi uygulamalar, uygulamanızı ölçeklenebilir, güvenilir ve yüksek performanslı hale getirmenize yardımcı olacaktır.
Yorumlar
Bir Yorum Bırakın
Henüz yorum yapılmamış. İlk yorumu siz yapın!