PWA Development Guide
Web App Manifest (manifest.json)
{
"name": "My Awesome App",
"short_name": "MyApp",
"description": "A progressive web app",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "portrait",
"theme_color": "#6c63ff",
"background_color": "#1c2035",
"icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
{ "src": "/icons/icon-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
],
"categories": ["productivity"],
"screenshots": [
{ "src": "/screenshots/desktop.png", "sizes": "1280x720", "form_factor": "wide" }
]
}
<!-- In HTML head -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#6c63ff">
Service Worker Registration
// main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
const reg = await navigator.serviceWorker.register('/sw.js', {
scope: '/'
});
console.log('SW registered:', reg.scope);
} catch (err) {
console.error('SW registration failed:', err);
}
});
}
Caching Strategies
// sw.js โ Cache First (for static assets)
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(cached => {
return cached || fetch(event.request);
})
);
});
// Network First (for API calls)
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.then(response => {
const clone = response.clone();
caches.open('api-cache').then(cache => cache.put(event.request, clone));
return response;
})
.catch(() => caches.match(event.request))
);
});
// Stale While Revalidate (for pages)
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('page-cache').then(cache => {
return cache.match(event.request).then(cached => {
const networkFetch = fetch(event.request).then(response => {
cache.put(event.request, response.clone());
return response;
});
return cached || networkFetch;
});
})
);
});
Caching Strategies Reference
| Strategy | Best For | Freshness |
|---|---|---|
| Cache First | Static assets, fonts, images | Stale until updated |
| Network First | API data, dynamic content | Always fresh, fallback to cache |
| Stale While Revalidate | Pages, content that changes occasionally | Fast + fresh on next visit |
| Cache Only | Precached assets | Static |
| Network Only | Real-time data, auth endpoints | Always fresh, no offline |