PWA DOCS

PWA-INTRODUCTION

Progressive Web App (PWA)
Description: Aplikasi web yang menggunakan API modern untuk memberikan pengalaman seperti aplikasi native (offline, push notification, installable).
Example:
Menggabungkan HTTPS, Service Worker, dan Web App Manifest.
Output: Aplikasi web yang dapat diinstal
HTTPS Required
Description: Service Worker dan banyak API PWA hanya berfungsi melalui koneksi aman (HTTPS) atau localhost untuk development.
Example:
Pastikan website di-deploy dengan sertifikat SSL/TLS.
Output: Koneksi aman

WEB-APP-MANIFEST

<link rel="manifest">
Description: Menghubungkan file manifest.json ke halaman HTML.
Example:
<link rel="manifest" href="/manifest.json">
Output: Browser membaca metadata PWA
name
Description: Nama lengkap aplikasi (digunakan di splash screen dan Add to Home Screen).
Example:
"name": "My Awesome App"
Output: Judul panjang
short_name
Description: Nama pendek untuk ikon aplikasi (di bawah ikon).
Example:
"short_name": "Awesome"
Output: Nama pendek di homescreen
start_url
Description: URL yang dibuka saat aplikasi dijalankan. Biasanya root.
Example:
"start_url": "/?utm_source=homescreen"
Output: Halaman awal
display
Description: Mode tampilan: standalone, fullscreen, minimal-ui, browser.
Example:
"display": "standalone"
Output: Tampilan seperti aplikasi native (tanpa URL bar)
background_color
Description: Warna latar belakang splash screen saat aplikasi diluncurkan.
Example:
"background_color": "#ffffff"
Output: Putih di splash screen
theme_color
Description: Warna tema browser (toolbar/address bar).
Example:
"theme_color": "#6c5ce7"
Output: Toolbar ungu
orientation
Description: Mengunci orientasi layar: any, natural, portrait, landscape, dll.
Example:
"orientation": "portrait"
Output: Hanya potret
icons
Description: Daftar ikon untuk berbagai ukuran dan tujuan (homescreen, splash).
Example:
"icons": [{ "src": "/icon-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }]
Output: Ikon 192px
purpose: maskable
Description: Ikon dapat dipotong menjadi bentuk yang aman (Android adaptive icons).
Example:
"purpose": "maskable"
Output: Ikon adaptif
scope
Description: Batasan navigasi yang dianggap dalam aplikasi. Di luar scope akan dibuka di browser.
Example:
"scope": "/app/"
Output: Hanya URL di dalam /app/
description
Description: Deskripsi aplikasi (opsional).
Example:
"description": "Aplikasi catatan terbaik"
Output: Metadata deskripsi
screenshots
Description: Array gambar tangkapan layar untuk promosi di instalasi (Chrome 88+).
Example:
"screenshots": [{ "src": "/screenshot.jpg", "sizes": "1280x720", "type": "image/jpeg" }]
Output: Galeri di dialog instalasi
categories
Description: Kategori aplikasi (biasanya untuk toko aplikasi).
Example:
"categories": ["productivity", "utilities"]
Output: Kategori produktivitas
iarc_rating_id
Description: ID rating konten IARC.
Example:
"iarc_rating_id": "..."
Output: Rating konten
shortcuts
Description: Daftar shortcut ke halaman tertentu di dalam aplikasi (long press ikon).
Example:
"shortcuts": [{ "name": "New Note", "short_name": "New", "url": "/new", "icons": [...] }]
Output: Menu pintasan
protocol_handlers
Description: Mendaftarkan aplikasi untuk menangani skema URI tertentu (web+...).
Example:
"protocol_handlers": [{ "protocol": "web+myapp", "url": "/handle?uri=%s" }]
Output: Aplikasi membuka URI khusus
file_handlers (experimental)
Description: Mendaftarkan tipe file yang bisa dibuka oleh PWA.
Example:
"file_handlers": [{ "action": "/open", "accept": { "text/*": [".txt"] } }]
Output: Aplikasi dapat membuka file .txt
related_applications
Description: Daftar aplikasi native terkait (untuk menghindari duplikat instalasi).
Example:
"related_applications": [{ "platform": "play", "url": "...", "id": "..." }]
Output: Terkait dengan aplikasi Android
prefer_related_applications
Description: Jika true, browser menyarankan aplikasi native terlebih dahulu.
Example:
"prefer_related_applications": false
Output: PWA diprioritaskan

SERVICE-WORKER-LIFECYCLE

navigator.serviceWorker.register()
Description: Mendaftarkan file service worker.
Example:
navigator.serviceWorker.register('/sw.js')
Output: Promise registrasi
install event
Description: Dipicu saat service worker pertama kali diinstal. Tempat pre-caching.
Example:
self.addEventListener('install', event => {
  event.waitUntil(caches.open('v1').then(cache => cache.addAll(['/offline.html'])))
})
Output: Cache awal terbentuk
activate event
Description: Dipicu setelah service worker diaktifkan. Tempat membersihkan cache lama.
Example:
self.addEventListener('activate', event => {
  event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== 'v1').map(k => caches.delete(k)))))
})
Output: Cache lama dibersihkan
fetch event
Description: Intersep semua request. Tempat strategi caching.
Example:
self.addEventListener('fetch', event => {
  event.respondWith(caches.match(event.request).then(response => response || fetch(event.request)))
})
Output: Respon dari cache atau jaringan
skipWaiting()
Description: Memaksa service worker baru untuk langsung aktif tanpa menunggu tab lama ditutup.
Example:
self.addEventListener('install', event => { self.skipWaiting() })
Output: Aktivasi instan
claim()
Description: Mengambil alih semua klien yang sudah ada dalam scope service worker.
Example:
self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()) })
Output: Kontrol penuh

CACHING-STRATEGIES

Cache First
Description: Ambil dari cache dulu, fallback ke network. Cocok untuk asset statis.
Example:
event.respondWith(caches.match(event.request).then(r => r || fetch(event.request).then(res => { cache.put(event.request, res.clone()); return res })))
Output: Cache diutamakan
Network First
Description: Ambil dari network dulu, fallback ke cache. Cocok untuk data dinamis.
Example:
event.respondWith(fetch(event.request).catch(() => caches.match(event.request)))
Output: Network diutamakan, cache fallback
Cache Only
Description: Hanya dari cache. Cocok untuk konten offline-only.
Example:
event.respondWith(caches.match(event.request))
Output: Hanya cache
Network Only
Description: Hanya dari network. Cocok untuk hal yang tidak bisa di-cache.
Example:
event.respondWith(fetch(event.request))
Output: Hanya network
Stale-While-Revalidate
Description: Ambil dari cache, lalu fetch network untuk update cache di background.
Example:
event.respondWith(caches.open('v1').then(cache => {
  return cache.match(event.request).then(cached => {
    const fetchPromise = fetch(event.request).then(networkResponse => {
      cache.put(event.request, networkResponse.clone());
      return networkResponse;
    });
    return cached || fetchPromise;
  });
}))
Output: Cepat dari cache, update di belakang

WORKBOX

Workbox Setup
Description: Library Google untuk mempermudah service worker.
Example:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js')

if (workbox) {
  workbox.routing.registerRoute(...)
}
Output: Workbox siap
workbox.precaching.precacheAndRoute
Description: Precache file yang dihasilkan oleh build tool (Webpack, Vite).
Example:
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
Output: Manifest precache
workbox.routing.registerRoute
Description: Mendaftarkan rute dengan strategi tertentu.
Example:
workbox.routing.registerRoute(
  ({ request }) => request.destination === 'image',
  new workbox.strategies.CacheFirst()
)
Output: Gambar di-cache
workbox.strategies.CacheFirst
Description: Strategi Cache First siap pakai.
Example:
new workbox.strategies.CacheFirst({ cacheName: 'images' })
Output: CacheFirst
workbox.strategies.NetworkFirst
Description: Strategi Network First.
Example:
new workbox.strategies.NetworkFirst({ cacheName: 'api' })
Output: NetworkFirst
workbox.strategies.StaleWhileRevalidate
Description: Strategi Stale-While-Revalidate.
Example:
new workbox.strategies.StaleWhileRevalidate({ cacheName: 'pages' })
Output: SWR
workbox.backgroundSync.BackgroundSyncPlugin
Description: Menyimpan request yang gagal saat offline dan mengirimnya saat online kembali.
Example:
new workbox.strategies.NetworkOnly({
  plugins: [new BackgroundSyncPlugin('myQueue', { maxRetentionTime: 24 * 60 })]
})
Output: Request gagal diantrekan
workbox.expiration.ExpirationPlugin
Description: Membatasi jumlah item atau usia cache.
Example:
new CacheFirst({ plugins: [new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 30 * 24 * 60 * 60 })] })
Output: Cache maks 50 item, 30 hari

OFFLINE-CAPABILITIES

Offline Fallback Page
Description: Menampilkan halaman kustom saat tidak ada koneksi.
Example:
self.addEventListener('fetch', event => {
  event.respondWith(fetch(event.request).catch(() => caches.match('/offline.html')))
})
Output: Halaman offline
IndexedDB for Offline Data
Description: Menyimpan data terstruktur di sisi klien untuk digunakan offline.
Example:
const db = await openDB('myDB', 1, { upgrade(db) { db.createObjectStore('items') } })
await db.put('items', data, 'key')
Output: Data tersimpan lokal
Background Sync
Description: Menyinkronkan data saat koneksi kembali meskipun tab sudah ditutup.
Example:
navigator.serviceWorker.ready.then(reg => reg.sync.register('sync-queue'))
// Di service worker:
self.addEventListener('sync', event => { if (event.tag === 'sync-queue') { event.waitUntil(processQueue()) } })
Output: Sinkronisasi di latar belakang
Periodic Background Sync
Description: Memperbarui konten secara berkala di latar belakang (terbatas).
Example:
navigator.serviceWorker.ready.then(reg => reg.periodicSync.register('update-feed', { minInterval: 60 * 60 * 1000 }))
// Di service worker:
self.addEventListener('periodicsync', event => { if (event.tag === 'update-feed') { event.waitUntil(fetchNewContent()) } })
Output: Update berkala

NOTIFICATIONS-PUSH

Notification.requestPermission()
Description: Meminta izin untuk menampilkan notifikasi.
Example:
Notification.requestPermission().then(permission => { if (permission === 'granted') { ... } })
Output: Izin granted / denied / default
Push API (subscription)
Description: Mendaftarkan pengguna untuk menerima push notification.
Example:
navigator.serviceWorker.ready.then(reg => reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: vapidPublicKey }))
Output: PushSubscription
push event (service worker)
Description: Menerima push event dari server dan menampilkan notifikasi.
Example:
self.addEventListener('push', event => {
  const data = event.data.json()
  event.waitUntil(self.registration.showNotification(data.title, { body: data.body, icon: '/icon.png' }))
})
Output: Notifikasi muncul
notificationclick event
Description: Menangani klik pada notifikasi (membuka URL atau fokus aplikasi).
Example:
self.addEventListener('notificationclick', event => {
  event.notification.close()
  event.waitUntil(clients.openWindow(event.notification.data.url))
})
Output: Aplikasi terbuka

INSTALLABILITY

beforeinstallprompt event
Description: Disela sebelum dialog instalasi muncul. Bisa digunakan untuk menunda atau menampilkan tombol install kustom.
Example:
window.addEventListener('beforeinstallprompt', e => { e.preventDefault(); deferredPrompt = e; showInstallButton() })
Output: Tombol install kustom
prompt() pada deferredPrompt
Description: Menampilkan dialog instalasi atas permintaan tombol kustom.
Example:
deferredPrompt.prompt().then(result => { console.log(result.outcome) })
Output: Dialog muncul
appinstalled event
Description: Dipicu setelah PWA berhasil diinstal.
Example:
window.addEventListener('appinstalled', () => { console.log('PWA installed') })
Output: Log instalasi
navigator.standalone (iOS)
Description: Mendeteksi apakah aplikasi dibuka dalam mode standalone di iOS.
Example:
if (window.navigator.standalone) { /* iOS standalone */ }
Output: true jika di homescreen
display-mode media query
Description: Mendeteksi mode tampilan aplikasi melalui CSS.
Example:
@media (display-mode: standalone) { /* Gaya untuk mode standalone */ }
Output: CSS khusus PWA

TOOLS-TESTING

Lighthouse PWA Audit
Description: Memeriksa skor PWA dan persyaratan installability.
Example:
Chrome DevTools > Lighthouse > PWA
Output: Skor dan daftar perbaikan
Chrome DevTools Application Panel
Description: Melihat service worker, cache storage, indexedDB, manifest.
Example:
DevTools > Application > Service Workers
Output: Status SW, update, unregister
pwabuilder.com
Description: Tool online untuk memvalidasi dan mengemas PWA menjadi paket aplikasi store (Google Play, Microsoft Store).
Example:
Buka pwabuilder.com, masukkan URL.
Output: Laporan dan paket
Workbox CLI
Description: Tool untuk menghasilkan service worker dengan Workbox tanpa perlu menulis kode manual.
Example:
npx workbox-cli generateSW
Output: File sw.js siap pakai