Pengertian
PWA (Progressive Web App) adalah website yang bisa "diinstal" di perangkat pengguna dan bekerja layaknya aplikasi: punya ikon di layar utama, bisa dibuka tanpa koneksi, dan memuat lebih cepat pada kunjungan berikutnya. Tiga pilar PWA:
- Web App Manifest — metadata aplikasi (nama, ikon, warna tema, cara tampil).
- Service Worker — skrip latar yang mencegat permintaan jaringan dan mengelola cache.
- HTTPS — wajib, karena service worker dapat mengubah lalu lintas jaringan.
Untuk website statis, PWA memberi nilai tambah besar: pembaca artikel bisa membuka halaman yang sudah dikunjungi meski jaringan tidak stabil.
Kelebihan
- Lebih cepat pada kunjungan berulang: aset disajikan dari cache lokal.
- Bisa dibuka offline untuk halaman yang sudah dicache.
- Bisa diinstal ke layar utama, tampil seperti aplikasi.
- Tanpa backend tambahan: cukup berkas statis.
- Gratis dan terbuka: didukung semua browser modern.
Kekurangan
- Manajemen cache merepotkan: salah strategi bisa menyajikan aset basi.
- Update tidak instan: service worker baru perlu siklus aktivasi.
- Penyimpanan terbatas di perangkat pengguna.
- Sulit di-debug bagi pemula karena berlatar belakang.
- Tidak dihitung sebagai aplikasi toko: tanpa push notification dan wrapper, fiturnya terbatas dibanding aplikasi native.
Catatan penting: Service worker hanya berjalan di HTTPS (ataulocalhost). Selalu uji di domain produksi atau server lokal, bukan difile://.
Web App Manifest
Buat site.webmanifest di akar situs:
{
"name": "Masyarakat",
"short_name": "Masyarakat",
"description": "Mari berbagi ilmu lewat artikel dan karya digital.",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#0d0d12",
"theme_color": "#0d0d12",
"lang": "id",
"icons": [
{ "src": "/favicon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
{ "src": "/favicon-192.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
]
}Tautkan di setiap halaman:
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content="#f7f7f9" />
<meta name="theme-color" content="#0d0d12" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />Service Worker: Cache Aset Inti
Buat sw.js di akar situs:
const CACHE = 'masyarakat-v3';
const PRECACHE = [
'/',
'/styles.css?v=2',
'/site-config.js',
'/nav.js',
'/offline.html',
];
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.clients.claim();
});
self.addEventListener('fetch', (event) => {
const { request } = event;
if (request.method !== 'GET') return;
// Halaman: network-first agar konten baru tetap didahulukan.
if (request.mode === 'navigate') {
event.respondWith(
fetch(request).catch(() => caches.match(request).then((r) => r || caches.match('/offline.html')))
);
return;
}
// Aset statis: cache-first, perbarui di latar.
event.respondWith(
caches.match(request).then((cached) => {
const network = fetch(request)
.then((res) => {
const copy = res.clone();
caches.open(CACHE).then((cache) => cache.put(request, copy));
return res;
})
.catch(() => cached);
return cached || network;
})
);
});Naikkan angka versi (v3 → v4) setiap kali aset inti berubah agar cache lama dibersihkan.
Mendaftarkan Service Worker
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').catch(() => {});
});
}
</script>Halaman Offline
Sediakan offline.html sederhana yang dipakai saat jaringan mati:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Offline - Masyarakat</title>
</head>
<body>
<main style="max-width:640px;margin:12vh auto;padding:24px;text-align:center;font-family:sans-serif">
<h1>Anda sedang offline</h1>
<p>Halaman ini belum tersimpan di perangkat. Sambungkan kembali internet lalu muat ulang.</p>
</main>
</body>
</html>Strategi Caching yang Umum
| Strategi | Cocok untuk | Perilaku |
|---|---|---|
| Cache-first | CSS, JS, font, ikon | Ambil cache dulu, perbarui di latar |
| Network-first | HTML, artikel | Utamakan jaringan, fallback ke cache |
| Stale-while-revalidate | Aset berversi | Sajikan lama, perbarui diam-diam |
| Cache-only | Halaman offline | Selalu dari cache |
Mengukur dan Menguji
- Buka DevTools → Application → Service Workers untuk memastikan status
activated. - Cek Manifest untuk ikon, nama, dan warna.
- Centang Offline di tab Network lalu muat ulang halaman yang sudah dicache.
- Jalankan Lighthouse dengan kategori PWA untuk memverifikasi instalabilitas.
Troubleshooting
- Service worker tidak terdaftar: cek console; penyebab umum adalah bukan HTTPS atau path
/sw.jssalah. - Perubahan tidak muncul: naikkan nama cache dan panggil
self.skipWaiting()agar SW baru segera aktif. - Aset basi terus tersaji: pastikan aset berversi (
?v=2) atau gunakan strategi network-first untuk HTML. - Offline malah menampilkan halaman error browser: cek path
offline.htmlada diPRECACHEdan bisa diakses. - Ikon PWA tidak muncul: sediakan minimal 192x192 dan 512x512,
purposememadai, dansrcdapat diakses. - Cache menumpuk: hapus cache lama di event
activate; batasi jumlah entri untuk situs besar.
Kesimpulan
PWA pada website statis cukup dengan tiga berkas: site.webmanifest, sw.js, dan offline.html, ditambah pendaftaran service worker. Dengan strategi cache yang tepat — cache-first untuk aset, network-first untuk HTML — situs terasa cepat dan tetap bisa dibaca walau jaringan terputus.