PWA - Progressive Web Apps — Bangun Pengalaman Seperti Aplikasi di Web

PWA - Progressive Web Apps — Bangun Pengalaman Seperti Aplikasi di Web

10/11/2025 Web By Tech Writers
Progressive Web AppsService WorkersPengembangan WebOffline SupportMobile WebJavaScriptPerforma

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

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:

  1. Visit your PWA in browser
  2. Tap the install prompt (or menu → “Add to Home Screen”)
  3. 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

  • 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

  1. Application Tab: View manifest, service workers, storage
  2. Service Workers: Check status, unregister, skip waiting
  3. Storage: Inspect cache, local storage, IndexedDB
  4. 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

  • Twitter Lite
  • Spotify
  • Pinterest
  • 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

  • Twitter Lite
  • Spotify
  • Pinterest
  • Starbucks

PWAs are the future of web development!