PWA - Progressive Web Apps — Bangun Pengalaman Seperti Aplikasi di Web
Pengenalan: Masa Depan Web Applications
Progressive Web Apps (PWAs) menjembatani kesenjangan antara aplikasi web dan aplikasi native, memberikan yang terbaik dari kedua dunia. PWAs bekerja offline, dapat diinstal di layar beranda, mengirim notifikasi push, dan berjalan di kecepatan native-like. Panduan komprehensif ini mencakup semua yang Kamu perlukan untuk membangun PWAs modern.
Daftar Isi
- Pengenalan
- Apa itu PWA?
- PWA Core Requirements
- Service Workers
- Web Manifest
- Offline Functionality
- Push Notifications
- Installation and Distribution
- Performance Optimization
- Popular PWA Examples
- Debugging PWAs
- Best Practices
Apa itu PWA?
Progressive Web App menggabungkan web dan app features untuk memberikan pengalaman pengguna yang ditingkatkan. PWAs adalah:
- Progressive: Bekerja di semua perangkat dan browser
- Responsif: Sempurna pas untuk ukuran layar
- Tidak tergantung konektivitas: Bekerja offline via service workers
- Seperti aplikasi: Navigasi dan interaksi terasa native
- Fresh: Selalu up-to-date berkat service workers
- Aman: Disajikan via HTTPS
- Dapat ditemukan: Dapat diidentifikasi sebagai “aplikasi”
- Dapat diinstal: Instalasi layar beranda tanpa app store
- Dapat dibagikan: Berbagi mudah via URL
Mengapa PWAs Penting
PWAs menyelesaikan tantangan kritis:
- Dukungan Offline: Tidak ada internet? Tidak masalah
- Penggunaan Data Berkurang: Konten cached berarti bandwidth lebih sedikit
- Pemuatan Lebih Cepat: Sumber daya cached dimuat secara instan
- Terasa Seperti Aplikasi Native: Layar penuh, ikon layar beranda
- Notifikasi Push: Kemampuan re-engagement
- Tanpa App Store: Distribusi langsung via web
PWA Core Requirements
1. Keamanan HTTPS
Semua PWAs harus disajikan melalui HTTPS. Ini memastikan komunikasi aman dan mengaktifkan service workers.
PWAs memerlukan HTTPS
Pengecualian: localhost untuk pengembangan
Sertifikat: Dapat menggunakan Let's Encrypt (gratis)
Validasi: Periksa konsol browser untuk peringatan HTTPS
2. Pendaftaran Service Worker
Service workers bertindak sebagai proxy antara aplikasi Kamu dan jaringan, mengaktifkan fungsionalitas offline dan caching.
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(registration => {
console.log('Service Worker registered:', registration);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
3. Web App Manifest
File manifest menceritakan kepada browser cara menampilkan aplikasi Kamu saat diinstal.
{
"name": "My Progressive Web App",
"short_name": "MyApp",
"description": "An amazing PWA example",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "/images/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/images/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/images/icon-maskable.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
}
]
}
Adding Manifest to HTML
Tautkan file manifest di bagian kepala HTML Kamu.
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#000000">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon" href="/images/apple-touch-icon.png">
Service Workers
Service workers adalah tulang punggung PWAs, berjalan di latar belakang dan menangani caching, dukungan offline, dan sinkronisasi latar belakang.
Service Worker Lifecycle
Instalasi → Aktivasi → Menangani Fetch/Message → Penghentian
(setup cache) (cleanup old) (layani dari cache) (jika tidak digunakan)
Mengimplementasikan Service Worker Caching
// sw.js - Service Worker
const CACHE_NAME = 'app-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/css/styles.css',
'/js/app.js',
'/images/logo.png'
];
// Event install - cache assets
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// Event activate - cleanup old caches
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
console.log('Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
// Event fetch - serve from cache, fall back to network
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request).then(response => {
// Check if valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response
const responseToCache = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
return response;
});
}).catch(() => {
// Network request failed, return offline page
return caches.match('/offline.html');
})
);
});
Strategi untuk Caching
Cache First (Cache, jatuh kembali ke network)
- Terbaik untuk: Aset yang tidak berubah sering
- Kecepatan: Pengalaman offline yang cepat
- Use case: Gambar, CSS, JavaScript
Network First (Network, jatuh kembali ke cache)
- Best for: Frequently updated content
- Speed: Always gets fresh data when available
- Use case: API responses, dynamic content
Stale While Revalidate
- Best for: Content that can be slightly out of date
- Speed: Fast initial load, background update
- Use case: Blog posts, news feeds
Web Manifest
The web manifest defines how your app appears when installed and how it should behave.
Display Modes
"display": "standalone" // Like a native app
"display": "fullscreen" // Full screen, no browser chrome
"display": "minimal-ui" // Minimal UI
"display": "browser" // Normal browser
Theme Customization
{
"theme_color": "#000000", // Browser UI color
"background_color": "#ffffff", // Background during load
"scope": "/app/", // PWA scope
"start_url": "/app/" // Launch URL
}
Offline Functionality
Offline Detection
// Detect online/offline status
window.addEventListener('online', () => {
console.log('User is online');
syncPendingData();
});
window.addEventListener('offline', () => {
console.log('User is offline');
showOfflineMessage();
});
// Check current status
if (navigator.onLine) {
console.log('Currently online');
} else {
console.log('Currently offline');
}
Local Storage and IndexedDB
Store data locally for offline access.
// IndexedDB for complex data
const dbRequest = indexedDB.open('myapp', 1);
dbRequest.onsuccess = event => {
const db = event.target.result;
const transaction = db.transaction(['items'], 'readwrite');
const store = transaction.objectStore('items');
store.put({ id: 1, title: 'Item 1' });
};
Push Notifications
Requesting Permission
// Request notification permission
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Notification permission granted');
}
});
Sending Notifications
// Service Worker push handler
self.addEventListener('push', event => {
const options = {
body: event.data.text(),
icon: '/images/icon-192x192.png',
badge: '/images/badge-72x72.png',
tag: 'notification',
requireInteraction: false
};
event.waitUntil(
self.registration.showNotification('New Message', options)
);
});
// Handle notification clicks
self.addEventListener('notificationclick', event => {
event.notification.close();
event.waitUntil(
clients.matchAll({ type: 'window' }).then(clientList => {
for (let client of clientList) {
if (client.url === '/' && 'focus' in client) {
return client.focus();
}
}
if (clients.openWindow) {
return clients.openWindow('/');
}
})
);
});
Installation and Distribution
Add to Home Screen
Users can install your PWA directly:
- Visit your PWA in browser
- Tap the install prompt (or menu → “Add to Home Screen”)
- App appears like native app
Web App Install Banners
Show custom install prompts.
let deferredPrompt;
window.addEventListener('beforeinstallprompt', event => {
event.preventDefault();
deferredPrompt = event;
// Show custom install button
document.getElementById('install-btn').style.display = 'block';
document.getElementById('install-btn').addEventListener('click', () => {
deferredPrompt.prompt();
deferredPrompt.userChoice.then(choice => {
if (choice.outcome === 'accepted') {
console.log('User installed PWA');
}
deferredPrompt = null;
});
});
});
window.addEventListener('appinstalled', () => {
console.log('PWA was installed');
});
Performance Optimization
Key Metrics for PWAs
- First Contentful Paint (FCP): < 1.8s
- Largest Contentful Paint (LCP): < 2.5s
- Cumulative Layout Shift (CLS): < 0.1
- Time to Interactive (TTI): < 3.8s
Performance Checklist
✓ Service worker precaches critical assets ✓ Images optimized and lazy-loaded ✓ Code splitting and bundling optimized ✓ Network requests minimized ✓ Offline experience tested ✓ Performance monitored in production
Popular PWA Examples
- Twitter Lite: 30% data reduction, fast loading
- Spotify: Full offline support, home screen
- Pinterest: 40% faster on 3G, home screen install
- Starbucks: Order ahead offline, sync on reconnect
- Washington Post: 1MB total size, fast load times
Debugging PWAs
Chrome DevTools
- Application Tab: View manifest, service workers, storage
- Service Workers: Check status, unregister, skip waiting
- Storage: Inspect cache, local storage, IndexedDB
- Offline Simulation: Test offline behavior
Testing Offline
// Network throttling test
// DevTools → Network → Throttling
// Check app Kamu still works
Best Practices
✓ Selalu serve over HTTPS ✓ Provide offline fallback pages ✓ Optimize manifest icons untuk semua sizes ✓ Test di real devices ✓ Monitor performance metrics ✓ Keep service workers updated ✓ Handle service worker errors gracefully ✓ Provide clear uninstall options
PWAs merepresentasikan future dari web delivery!
Last updated: January 8, 2026
What is a PWA?
A Progressive Web App is a web application that:
- Works offline seamlessly
- Is installable on home screen
- Provides app-like experience
- Is fast and reliable
Requirements
1. HTTPS
All PWAs must be served over HTTPS
2. Service Worker
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
3. Web Manifest
{
"name": "My App",
"short_name": "App",
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone"
}
Service Worker Caching
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/',
'/styles.css',
'/app.js'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Features
✓ Offline support without network ✓ Home screen installation ✓ Push notifications ✓ Background sync ✓ App shell architecture
Popular PWAs
- Twitter Lite
- Spotify
- Starbucks
PWAs are the future of web development!
What is a PWA?
A Progressive Web App is a web application that:
- Works offline seamlessly
- Is installable on home screen
- Provides app-like experience
- Is fast and reliable
Requirements
1. HTTPS
All PWAs must be served over HTTPS
2. Service Worker
// Register service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
3. Web Manifest
{
"name": "My App",
"short_name": "App",
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone"
}
Service Worker Caching
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/',
'/styles.css',
'/app.js'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Features
✓ Offline support without network ✓ Home screen installation ✓ Push notifications ✓ Background sync ✓ App shell architecture
Popular PWAs
- Twitter Lite
- Spotify
- Starbucks
PWAs are the future of web development!