[ BACK TO ALL ARTICLES ]
Web Development

Progressive Web App (PWA): Mengubah Website Anda Menjadi Aplikasi Native di Web

Nadhif Fauzil Adhim
Nadhif Fauzil Adhim
10 Oktober 2026
0 VIEWS

Pendahuluan

Dunia web telah berevolusi pesat sejak pertama kali diperkenalkan pada akhir 1990-an. Namun, hingga era smartphone muncul pada 2008, banyak fitur perangkat—seperti mode offline, notifikasi push, hingga akses kamera—masih menjadi wilayah eksklusif aplikasi native. Kini, dengan hadirnya Progressive Web App (PWA), batasan tersebut lenyap. PWA memadukan kemudahan distribusi dan satu basis kode web dengan kemampuan aplikasi native, sehingga Anda dapat menghadirkan pengalaman pengguna yang cepat, responsif, dan dapat dipasang di homescreen perangkat.

Pada artikel ini, kita akan mengupas tuntas bagaimana membangun PWA dari nol—mulai dari persiapan, pembuatan manifest, penerapan service worker, hingga strategi caching, background sync, dan push notification. Mari kita mulai!

Watch the video on YouTube


1. Persiapan Awal: HTTPS & Audit Kinerja

1.1 Mengapa HTTPS?

Service worker—jantung PWA—hanya berjalan pada konteks aman (HTTPS). Selain itu, pengguna cenderung lebih mempercayai situs yang ber-HTTPS.

1.2 Audit dengan Lighthouse

Gunakan Chrome DevTools → Lighthouse untuk mengukur:

  • Performance: waktu muat, interaksi, dan Core Web Vitals.
  • Accessibility: kepatuhan WCAG.
  • Best Practices: penggunaan API modern, keamanan.
  • SEO: metadata, struktur heading.
  • PWA: kelayakan installable, manifest, service worker.

Saran: Jalankan audit setelah setiap iterasi besar dan tetapkan threshold skor PWA minimal (misal ≥ 90).


2. Menyiapkan Manifes Aplikasi

File manifest.json memberi tahu browser bagaimana aplikasi Anda harus diperlakukan saat "dipasang" di homescreen.

{
  "name": "Contoh Progressive Web App",
  "short_name": "PWA-Contoh",
  "description": "Aplikasi web progresif yang bisa dijalankan offline dan dipasang seperti native",
  "start_url": "/index.html?utm_source=homescreen",
  "scope": "/",
  "display": "standalone",
  "orientation": "portrait-primary",
  "background_color": "#ffffff",
  "theme_color": "#3367D6",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "categories": ["productivity", "utilities"],
  "lang": "id"
}
  • start_url: Halaman awal saat aplikasi dibuka.
  • scope: Batas URL yang termasuk aplikasi.
  • display: Mode tampilan (standalone menghilangkan UI browser).
  • theme_color & background_color: Warna tema dan splash screen.
  • icons: Ikon untuk homescreen; gunakan tool seperti PWA Asset Generator agar tidak membuat manual satu per satu.

Tambahkan referensi ke manifest.json di <head> HTML:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#3367D6">

3. Service Worker: Otak di Balik Offline & Caching

3.1 Registrasi Service Worker

Dalam file JavaScript utama (misal register-sw.js), daftarkan service worker:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', async () => {
    try {
      const registration = await navigator.serviceWorker.register('/serviceworker.js');
      console.log('Service Worker terdaftar:', registration);
    } catch (error) {
      console.error('Gagal mendaftarkan Service Worker:', error);
    }
  });
}

3.2 Struktur Dasar serviceworker.js

// Import Workbox dari CDN (opsional)
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.3/workbox-sw.js');

self.addEventListener('install', event => {
  console.log('[SW] Installing…');
  // Bisa pre-cache aset penting di sini
});

self.addEventListener('activate', event => {
  console.log('[SW] Activating…');
  // Bisa bersihkan cache versi lama
});

self.addEventListener('fetch', event => {
  // Intercept permintaan jaringan
});

4. Pola Caching Lanjutan dengan Workbox

Workbox memudahkan strategi caching tanpa boilerplate berlebih.

4.1 Cache First (Aset Statis)

workbox.routing.registerRoute(
  /\.(?:png|jpg|jpeg|svg|woff2?)$/,
  new workbox.strategies.CacheFirst({
    cacheName: 'static-assets',
    plugins: [
      new workbox.expiration.ExpirationPlugin({
        maxEntries: 100,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 hari
      }),
    ],
  })
);

4.2 Stale-While-Revalidate (Konten Dinamis Ringan)

workbox.routing.registerRoute(
  /\/api\/articles/,
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: 'articles-cache',
    plugins: [
      new workbox.expiration.ExpirationPlugin({ maxEntries: 50 }),
    ],
  })
);

4.3 Network First (Konten Terbaru)

workbox.routing.registerRoute(
  /\/api\/live-updates/,
  new workbox.strategies.NetworkFirst({
    cacheName: 'live-updates',
    networkTimeoutSeconds: 3,
    plugins: [
      new workbox.cacheableResponse.CacheableResponsePlugin({
        statuses: [0, 200],
      }),
    ],
  })
);

5. Data Offline & Background Sync

5.1 Menyimpan Data Lokal dengan IndexedDB

Gunakan idb untuk API yang lebih bersahabat:

import { openDB } from 'idb';

const dbPromise = openDB('my-app-db', 1, {
  upgrade(db) {
    db.createObjectStore('notes', { keyPath: 'id', autoIncrement: true });
  },
});

async function saveNoteOffline(note) {
  const db = await dbPromise;
  await db.put('notes', note);
}

5.2 Background Sync

// Daftarkan sync di klien
navigator.serviceWorker.ready.then(reg => {
  return reg.sync.register('sync-notes');
});

// Tangani sync di SW
self.addEventListener('sync', event => {
  if (event.tag === 'sync-notes') {
    event.waitUntil(syncNotesToServer());
  }
});

async function syncNotesToServer() {
  const db = await dbPromise;
  const allNotes = await db.getAll('notes');

  for (const note of allNotes) {
    await fetch('/api/notes', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(note),
    });
    await db.delete('notes', note.id);
  }
}

6. Push Notifications

Menambah kedalaman engagement dengan notifikasi real-time.

6.1 Meminta Izin

Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    subscribeUserToPush();
  }
});

6.2 Berlangganan Push Service

async function subscribeUserToPush() {
  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array('<VAPID_PUBLIC_KEY>')
  });
  // Simpan subscription ke server
  await fetch('/api/save-subscription', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(subscription)
  });
}

6.3 Menampilkan Notifikasi di SW

self.addEventListener('push', event => {
  const data = event.data.json();
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: '/icons/icon-192x192.png',
      badge: '/icons/badge-72x72.png'
    })
  );
});

7. Integrasi Framework Populer

Framework Cara Integrasi PWA
React create-react-app → serviceWorker.register()
Angular ng add @angular/pwa → auto-generate config
Vue CLI vue add pwa → Workbox Webpack Plugin

Setelah integrasi, pastikan:

  • Build pipeline memasukkan manifest.json dan serviceworker.js.
  • CI/CD menjalankan Lighthouse CI untuk memantau skor PWA.

8. UX: Prompt Instalasi yang Efektif

let deferredPrompt;

window.addEventListener('beforeinstallprompt', e => {
  e.preventDefault();
  deferredPrompt = e;
  showInstallButton(true);
});

installBtn.addEventListener('click', async () => {
  deferredPrompt.prompt();
  const { outcome } = await deferredPrompt.userChoice;
  console.log('Hasil pilihan user:', outcome);
  deferredPrompt = null;
});
  • Tampilkan tombol install setelah interaksi pengguna (scroll atau klik).
  • Batasi frekuensi prompt: satu kali per sesi atau per hari.

9. Studi Kasus PWA Sukses

  1. Twitter Lite
    • Mode data saver, notifikasi real-time, > 65% lebih cepat.
  2. Starbucks PWA
    • Menu offline, payment caching, load < 3 detik.
  3. Pinterest
    • Pertumbuhan engagement 60% setelah migrasi ke PWA.

Pelajari langsung dengan membuka mobile.twitter.com atau app.starbucks.com.


10. Tren & API Eksperimental

  • Periodic Background Sync: sinkron data berkala di latar belakang.
  • Background Fetch: unduh file besar sambil menampilkan progress.
  • Web Bluetooth/USB/MIDI: koneksi perangkat IoT langsung.
  • WebXR: AR/VR di browser.

Kesimpulan

PWA menutup celah antara website dan aplikasi native dengan:

  1. Satu Basis Kode untuk semua platform.
  2. Distribusi Mudah tanpa app store (atau lewat TWA).
  3. Biaya Rendah tanpa komisi tinggi.
  4. Pengalaman Native: offline, notifikasi, homescreen.

Dengan mengikuti langkah-langkah di atas—mulai dari audit Lighthouse, pembuatan manifest.json, pendaftaran service worker, strategi caching, background sync, hingga push notifications—Anda dapat membangun aplikasi web yang cepat, andal, dan memikat pengguna layaknya aplikasi native.

Selamat mencoba membuat PWA Anda sendiri, dan terus eksplorasi API web modern lainnya!

SHARE THIS LOG