PWA DOCS
PWA-INTRODUCTION
Name
Description
Example
Output
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
Progressive Web App (PWA)Aplikasi web yang menggunakan API modern untuk memberikan pengalaman seperti aplikasi native (offline, push notification, installable).
Menggabungkan HTTPS, Service Worker, dan Web App Manifest.
Aplikasi web yang dapat diinstal
HTTPS RequiredDescription: 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
HTTPS RequiredService Worker dan banyak API PWA hanya berfungsi melalui koneksi aman (HTTPS) atau localhost untuk development.
Pastikan website di-deploy dengan sertifikat SSL/TLS.
Koneksi aman
WEB-APP-MANIFEST
Name
Description
Example
Output
<link rel="manifest">Description: Menghubungkan file manifest.json ke halaman HTML.
Example:
<link rel="manifest" href="/manifest.json">
Output: Browser membaca metadata PWA
<link rel="manifest">Menghubungkan file manifest.json ke halaman HTML.
<link rel="manifest" href="/manifest.json">
Browser membaca metadata PWA
nameDescription: Nama lengkap aplikasi (digunakan di splash screen dan Add to Home Screen).
Example:
"name": "My Awesome App"
Output: Judul panjang
nameNama lengkap aplikasi (digunakan di splash screen dan Add to Home Screen).
"name": "My Awesome App"
Judul panjang
short_nameDescription: Nama pendek untuk ikon aplikasi (di bawah ikon).
Example:
"short_name": "Awesome"
Output: Nama pendek di homescreen
short_nameNama pendek untuk ikon aplikasi (di bawah ikon).
"short_name": "Awesome"
Nama pendek di homescreen
start_urlDescription: URL yang dibuka saat aplikasi dijalankan. Biasanya root.
Example:
"start_url": "/?utm_source=homescreen"
Output: Halaman awal
start_urlURL yang dibuka saat aplikasi dijalankan. Biasanya root.
"start_url": "/?utm_source=homescreen"
Halaman awal
displayDescription: Mode tampilan: standalone, fullscreen, minimal-ui, browser.
Example:
"display": "standalone"
Output: Tampilan seperti aplikasi native (tanpa URL bar)
displayMode tampilan: standalone, fullscreen, minimal-ui, browser.
"display": "standalone"
Tampilan seperti aplikasi native (tanpa URL bar)
background_colorDescription: Warna latar belakang splash screen saat aplikasi diluncurkan.
Example:
"background_color": "#ffffff"
Output: Putih di splash screen
background_colorWarna latar belakang splash screen saat aplikasi diluncurkan.
"background_color": "#ffffff"
Putih di splash screen
theme_colorDescription: Warna tema browser (toolbar/address bar).
Example:
"theme_color": "#6c5ce7"
Output: Toolbar ungu
theme_colorWarna tema browser (toolbar/address bar).
"theme_color": "#6c5ce7"
Toolbar ungu
orientationDescription: Mengunci orientasi layar: any, natural, portrait, landscape, dll.
Example:
"orientation": "portrait"
Output: Hanya potret
orientationMengunci orientasi layar: any, natural, portrait, landscape, dll.
"orientation": "portrait"
Hanya potret
iconsDescription: 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
iconsDaftar ikon untuk berbagai ukuran dan tujuan (homescreen, splash).
"icons": [{ "src": "/icon-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }]Ikon 192px
purpose: maskableDescription: Ikon dapat dipotong menjadi bentuk yang aman (Android adaptive icons).
Example:
"purpose": "maskable"
Output: Ikon adaptif
purpose: maskableIkon dapat dipotong menjadi bentuk yang aman (Android adaptive icons).
"purpose": "maskable"
Ikon adaptif
scopeDescription: Batasan navigasi yang dianggap dalam aplikasi. Di luar scope akan dibuka di browser.
Example:
"scope": "/app/"
Output: Hanya URL di dalam /app/
scopeBatasan navigasi yang dianggap dalam aplikasi. Di luar scope akan dibuka di browser.
"scope": "/app/"
Hanya URL di dalam /app/
descriptionDescription: Deskripsi aplikasi (opsional).
Example:
"description": "Aplikasi catatan terbaik"
Output: Metadata deskripsi
descriptionDeskripsi aplikasi (opsional).
"description": "Aplikasi catatan terbaik"
Metadata deskripsi
screenshotsDescription: 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
screenshotsArray gambar tangkapan layar untuk promosi di instalasi (Chrome 88+).
"screenshots": [{ "src": "/screenshot.jpg", "sizes": "1280x720", "type": "image/jpeg" }]Galeri di dialog instalasi
categoriesDescription: Kategori aplikasi (biasanya untuk toko aplikasi).
Example:
"categories": ["productivity", "utilities"]
Output: Kategori produktivitas
categoriesKategori aplikasi (biasanya untuk toko aplikasi).
"categories": ["productivity", "utilities"]
Kategori produktivitas
iarc_rating_idDescription: ID rating konten IARC.
Example:
"iarc_rating_id": "..."
Output: Rating konten
iarc_rating_idID rating konten IARC.
"iarc_rating_id": "..."
Rating konten
shortcutsDescription: 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
shortcutsDaftar shortcut ke halaman tertentu di dalam aplikasi (long press ikon).
"shortcuts": [{ "name": "New Note", "short_name": "New", "url": "/new", "icons": [...] }]Menu pintasan
protocol_handlersDescription: Mendaftarkan aplikasi untuk menangani skema URI tertentu (web+...).
Example:
"protocol_handlers": [{ "protocol": "web+myapp", "url": "/handle?uri=%s" }]Output: Aplikasi membuka URI khusus
protocol_handlersMendaftarkan aplikasi untuk menangani skema URI tertentu (web+...).
"protocol_handlers": [{ "protocol": "web+myapp", "url": "/handle?uri=%s" }]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
file_handlers (experimental)Mendaftarkan tipe file yang bisa dibuka oleh PWA.
"file_handlers": [{ "action": "/open", "accept": { "text/*": [".txt"] } }]Aplikasi dapat membuka file .txt
related_applicationsDescription: Daftar aplikasi native terkait (untuk menghindari duplikat instalasi).
Example:
"related_applications": [{ "platform": "play", "url": "...", "id": "..." }]Output: Terkait dengan aplikasi Android
related_applicationsDaftar aplikasi native terkait (untuk menghindari duplikat instalasi).
"related_applications": [{ "platform": "play", "url": "...", "id": "..." }]Terkait dengan aplikasi Android
prefer_related_applicationsDescription: Jika true, browser menyarankan aplikasi native terlebih dahulu.
Example:
"prefer_related_applications": false
Output: PWA diprioritaskan
prefer_related_applicationsJika true, browser menyarankan aplikasi native terlebih dahulu.
"prefer_related_applications": false
PWA diprioritaskan
SERVICE-WORKER-LIFECYCLE
Name
Description
Example
Output
navigator.serviceWorker.register()Description: Mendaftarkan file service worker.
Example:
navigator.serviceWorker.register('/sw.js')Output: Promise registrasi
navigator.serviceWorker.register()Mendaftarkan file service worker.
navigator.serviceWorker.register('/sw.js')Promise registrasi
install eventDescription: 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
install eventDipicu saat service worker pertama kali diinstal. Tempat pre-caching.
self.addEventListener('install', event => {
event.waitUntil(caches.open('v1').then(cache => cache.addAll(['/offline.html'])))
})Cache awal terbentuk
activate eventDescription: 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
activate eventDipicu setelah service worker diaktifkan. Tempat membersihkan cache lama.
self.addEventListener('activate', event => {
event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== 'v1').map(k => caches.delete(k)))))
})Cache lama dibersihkan
fetch eventDescription: 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
fetch eventIntersep semua request. Tempat strategi caching.
self.addEventListener('fetch', event => {
event.respondWith(caches.match(event.request).then(response => response || fetch(event.request)))
})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
skipWaiting()Memaksa service worker baru untuk langsung aktif tanpa menunggu tab lama ditutup.
self.addEventListener('install', event => { self.skipWaiting() })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
claim()Mengambil alih semua klien yang sudah ada dalam scope service worker.
self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()) })Kontrol penuh
CACHING-STRATEGIES
Name
Description
Example
Output
Cache FirstDescription: 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
Cache FirstAmbil dari cache dulu, fallback ke network. Cocok untuk asset statis.
event.respondWith(caches.match(event.request).then(r => r || fetch(event.request).then(res => { cache.put(event.request, res.clone()); return res })))Cache diutamakan
Network FirstDescription: 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
Network FirstAmbil dari network dulu, fallback ke cache. Cocok untuk data dinamis.
event.respondWith(fetch(event.request).catch(() => caches.match(event.request)))
Network diutamakan, cache fallback
Cache OnlyDescription: Hanya dari cache. Cocok untuk konten offline-only.
Example:
event.respondWith(caches.match(event.request))
Output: Hanya cache
Cache OnlyHanya dari cache. Cocok untuk konten offline-only.
event.respondWith(caches.match(event.request))
Hanya cache
Network OnlyDescription: Hanya dari network. Cocok untuk hal yang tidak bisa di-cache.
Example:
event.respondWith(fetch(event.request))
Output: Hanya network
Network OnlyHanya dari network. Cocok untuk hal yang tidak bisa di-cache.
event.respondWith(fetch(event.request))
Hanya network
Stale-While-RevalidateDescription: 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
Stale-While-RevalidateAmbil dari cache, lalu fetch network untuk update cache di background.
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;
});
}))Cepat dari cache, update di belakang
WORKBOX
Name
Description
Example
Output
Workbox SetupDescription: 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 SetupLibrary Google untuk mempermudah service worker.
importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js')
if (workbox) {
workbox.routing.registerRoute(...)
}Workbox siap
workbox.precaching.precacheAndRouteDescription: Precache file yang dihasilkan oleh build tool (Webpack, Vite).
Example:
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
Output: Manifest precache
workbox.precaching.precacheAndRoutePrecache file yang dihasilkan oleh build tool (Webpack, Vite).
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)
Manifest precache
workbox.routing.registerRouteDescription: Mendaftarkan rute dengan strategi tertentu.
Example:
workbox.routing.registerRoute(
({ request }) => request.destination === 'image',
new workbox.strategies.CacheFirst()
)Output: Gambar di-cache
workbox.routing.registerRouteMendaftarkan rute dengan strategi tertentu.
workbox.routing.registerRoute(
({ request }) => request.destination === 'image',
new workbox.strategies.CacheFirst()
)Gambar di-cache
workbox.strategies.CacheFirstDescription: Strategi Cache First siap pakai.
Example:
new workbox.strategies.CacheFirst({ cacheName: 'images' })Output: CacheFirst
workbox.strategies.CacheFirstStrategi Cache First siap pakai.
new workbox.strategies.CacheFirst({ cacheName: 'images' })CacheFirst
workbox.strategies.NetworkFirstDescription: Strategi Network First.
Example:
new workbox.strategies.NetworkFirst({ cacheName: 'api' })Output: NetworkFirst
workbox.strategies.NetworkFirstStrategi Network First.
new workbox.strategies.NetworkFirst({ cacheName: 'api' })NetworkFirst
workbox.strategies.StaleWhileRevalidateDescription: Strategi Stale-While-Revalidate.
Example:
new workbox.strategies.StaleWhileRevalidate({ cacheName: 'pages' })Output: SWR
workbox.strategies.StaleWhileRevalidateStrategi Stale-While-Revalidate.
new workbox.strategies.StaleWhileRevalidate({ cacheName: 'pages' })SWR
workbox.backgroundSync.BackgroundSyncPluginDescription: 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.backgroundSync.BackgroundSyncPluginMenyimpan request yang gagal saat offline dan mengirimnya saat online kembali.
new workbox.strategies.NetworkOnly({
plugins: [new BackgroundSyncPlugin('myQueue', { maxRetentionTime: 24 * 60 })]
})Request gagal diantrekan
workbox.expiration.ExpirationPluginDescription: 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
workbox.expiration.ExpirationPluginMembatasi jumlah item atau usia cache.
new CacheFirst({ plugins: [new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 30 * 24 * 60 * 60 })] })Cache maks 50 item, 30 hari
OFFLINE-CAPABILITIES
Name
Description
Example
Output
Offline Fallback PageDescription: 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
Offline Fallback PageMenampilkan halaman kustom saat tidak ada koneksi.
self.addEventListener('fetch', event => {
event.respondWith(fetch(event.request).catch(() => caches.match('/offline.html')))
})Halaman offline
IndexedDB for Offline DataDescription: 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
IndexedDB for Offline DataMenyimpan data terstruktur di sisi klien untuk digunakan offline.
const db = await openDB('myDB', 1, { upgrade(db) { db.createObjectStore('items') } })
await db.put('items', data, 'key')Data tersimpan lokal
Background SyncDescription: 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
Background SyncMenyinkronkan data saat koneksi kembali meskipun tab sudah ditutup.
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()) } })Sinkronisasi di latar belakang
Periodic Background SyncDescription: 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
Periodic Background SyncMemperbarui konten secara berkala di latar belakang (terbatas).
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()) } })Update berkala
NOTIFICATIONS-PUSH
Name
Description
Example
Output
Notification.requestPermission()Description: Meminta izin untuk menampilkan notifikasi.
Example:
Notification.requestPermission().then(permission => { if (permission === 'granted') { ... } })Output: Izin granted / denied / default
Notification.requestPermission()Meminta izin untuk menampilkan notifikasi.
Notification.requestPermission().then(permission => { if (permission === 'granted') { ... } })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 API (subscription)Mendaftarkan pengguna untuk menerima push notification.
navigator.serviceWorker.ready.then(reg => reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: vapidPublicKey }))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
push event (service worker)Menerima push event dari server dan menampilkan notifikasi.
self.addEventListener('push', event => {
const data = event.data.json()
event.waitUntil(self.registration.showNotification(data.title, { body: data.body, icon: '/icon.png' }))
})Notifikasi muncul
notificationclick eventDescription: 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
notificationclick eventMenangani klik pada notifikasi (membuka URL atau fokus aplikasi).
self.addEventListener('notificationclick', event => {
event.notification.close()
event.waitUntil(clients.openWindow(event.notification.data.url))
})Aplikasi terbuka
INSTALLABILITY
Name
Description
Example
Output
beforeinstallprompt eventDescription: 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
beforeinstallprompt eventDisela sebelum dialog instalasi muncul. Bisa digunakan untuk menunda atau menampilkan tombol install kustom.
window.addEventListener('beforeinstallprompt', e => { e.preventDefault(); deferredPrompt = e; showInstallButton() })Tombol install kustom
prompt() pada deferredPromptDescription: Menampilkan dialog instalasi atas permintaan tombol kustom.
Example:
deferredPrompt.prompt().then(result => { console.log(result.outcome) })Output: Dialog muncul
prompt() pada deferredPromptMenampilkan dialog instalasi atas permintaan tombol kustom.
deferredPrompt.prompt().then(result => { console.log(result.outcome) })Dialog muncul
appinstalled eventDescription: Dipicu setelah PWA berhasil diinstal.
Example:
window.addEventListener('appinstalled', () => { console.log('PWA installed') })Output: Log instalasi
appinstalled eventDipicu setelah PWA berhasil diinstal.
window.addEventListener('appinstalled', () => { console.log('PWA installed') })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
navigator.standalone (iOS)Mendeteksi apakah aplikasi dibuka dalam mode standalone di iOS.
if (window.navigator.standalone) { /* iOS standalone */ }true jika di homescreen
display-mode media queryDescription: Mendeteksi mode tampilan aplikasi melalui CSS.
Example:
@media (display-mode: standalone) { /* Gaya untuk mode standalone */ }Output: CSS khusus PWA
display-mode media queryMendeteksi mode tampilan aplikasi melalui CSS.
@media (display-mode: standalone) { /* Gaya untuk mode standalone */ }CSS khusus PWA
TOOLS-TESTING
Name
Description
Example
Output
Lighthouse PWA AuditDescription: Memeriksa skor PWA dan persyaratan installability.
Example:
Chrome DevTools > Lighthouse > PWA
Output: Skor dan daftar perbaikan
Lighthouse PWA AuditMemeriksa skor PWA dan persyaratan installability.
Chrome DevTools > Lighthouse > PWA
Skor dan daftar perbaikan
Chrome DevTools Application PanelDescription: Melihat service worker, cache storage, indexedDB, manifest.
Example:
DevTools > Application > Service Workers
Output: Status SW, update, unregister
Chrome DevTools Application PanelMelihat service worker, cache storage, indexedDB, manifest.
DevTools > Application > Service Workers
Status SW, update, unregister
pwabuilder.comDescription: 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
pwabuilder.comTool online untuk memvalidasi dan mengemas PWA menjadi paket aplikasi store (Google Play, Microsoft Store).
Buka pwabuilder.com, masukkan URL.
Laporan dan paket
Workbox CLIDescription: Tool untuk menghasilkan service worker dengan Workbox tanpa perlu menulis kode manual.
Example:
npx workbox-cli generateSW
Output: File sw.js siap pakai
Workbox CLITool untuk menghasilkan service worker dengan Workbox tanpa perlu menulis kode manual.
npx workbox-cli generateSW
File sw.js siap pakai