Skip to content
← Blog

Membuat PWA yang Tidak Menyajikan JavaScript Kadaluarsa

Arsitektur browser cache dan aplikasi web terversi
Service worker adalah proxy di browser. Tanpa lifecycle dan versioning yang disiplin, ia dapat mempertahankan asset lama.

Gejalanya membingungkan: deployment sukses, server melayani app.js baru, tetapi sebagian pengguna masih menjalankan JavaScript lama. Penyebab umum adalah cache-first dengan URL asset yang tidak berubah atau service worker baru masih waiting.

Lifecycle singkat#

Service worker baru diunduh ketika browser mendeteksi file berubah. Ia install, lalu biasanya menunggu worker lama tidak lagi mengontrol tab. MDN menjelaskan fase install, waiting, activate, serta penggunaan skipWaiting() dan clients.claim().

Versioned cache#

const CACHE_NAME = 'imbhk-v4';
const PRECACHE = ['/', '/assets/css/style.css?v=20260811'];

self.addEventListener('install', event => {
  event.waitUntil(caches.open(CACHE_NAME).then(c => c.addAll(PRECACHE)));
});

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => Promise.all(
      keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))
    ))
  );
});

Fingerprint asset, bukan hanya query version#

Build yang ideal menghasilkan app.a83f21.js. Content berubah berarti URL berubah; file lama dapat diberi cache immutable. Jika proyek PHP sederhana memakai query version, pastikan version benar-benar berubah setiap release dan service worker precache menunjuk URL yang sama dengan HTML.

Strategi sesuai resource#

ResourceStrategiAlasan
HTML/navigationNetwork-firstUser menerima shell baru
Hashed JS/CSSCache-firstURL immutable
Avatar/image berubahStale-while-revalidateCepat sambil refresh
Admin/API pribadiNetwork-onlyHindari data sensitif tersimpan

skipWaiting tidak selalu gratis#

skipWaiting() mengaktifkan worker baru lebih cepat. Jika HTML lama memanggil API cache baru yang incompatible, tab terbuka dapat rusak. Pilihan aman: tampilkan prompt “versi baru tersedia” lalu reload setelah user menyimpan pekerjaan.

Protokol pengujian release#

  1. Buka versi N dan biarkan satu tab aktif.
  2. Deploy versi N+1.
  3. Buka tab kedua dan periksa status worker.
  4. Pastikan cache lama dihapus setelah activation.
  5. Reload offline dan online.
  6. Verifikasi file JS aktual melalui DevTools, bukan hanya halaman server.
  7. Uji rollback ke versi N+2 yang memulihkan behavior.

Emergency recovery#

Jika worker rusak sudah tersebar, deploy worker minimal pada URL yang sama untuk menghapus cache lama dan unregister secara terkontrol. Jangan sekadar menghapus sw.js dari server; browser pengguna masih dapat memiliki worker aktif.

Aturan praktis: precache sedikit, version secara eksplisit, bedakan strategi per resource, dan uji update dengan tab lama masih terbuka.

Kompatibilitas antarversi#

Deploy HTML dan API secara backward-compatible selama window update. Browser dapat memiliki HTML N, worker N+1, dan API N+1 pada saat yang sama. Hindari perubahan atomik yang hanya benar bila seluruh lapisan berganti bersamaan.

Update UX#

registration.addEventListener('updatefound', () => {
  const worker = registration.installing;
  worker.addEventListener('statechange', () => {
    if (worker.state === 'installed' && navigator.serviceWorker.controller) {
      showUpdateAvailable();
    }
  });
});

Ketika user memilih update, kirim message ke waiting worker, tunggu controllerchange, lalu reload sekali. Hindari loop reload dengan flag session.

Observability client#

Kirim app version, service-worker version, dan asset build ID pada laporan error—tanpa data personal. Ini menjawab apakah bug hanya terjadi pada cache lama. Sediakan halaman diagnostik yang memperlihatkan versi tanpa memerlukan DevTools.

Cek pemahaman#

Mengubah CACHE_NAME saja tidak memperbarui tab yang masih dikontrol worker lama. Activation policy, asset URL, cleanup, dan reload strategy harus bekerja bersama.

💬 Comments (0)

No comments yet. Be the first to share your thoughts!

Now Playing Loading...