Membangun Progressive Web App dengan Astro dan Service Worker untuk Offline Support
Memahami Peran Service Worker dalam Arsitektur PWA Modern
Progressive Web App (PWA) telah menjadi standar baru dalam pengembangan web modern. Konsep ini memungkinkan website berperilaku seperti aplikasi native — dapat diinstal di home screen, berfungsi saat offline, dan memberikan pengalaman yang responsif. Tiga pilar utama PWA adalah HTTPS, Service Worker, dan Web App Manifest. Dari ketiganya, Service Worker adalah komponen yang paling vital karena menjadi otak di balik kemampuan offline dan caching.

Gambar: Diagram arsitektur high-level Progressive Web App yang menunjukkan bagaimana service worker, web app manifest, dan HTTPS bekerja bersama — Sumber: [Microsoft Edge Documentation](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps/how-to/)
Service Worker berperan sebagai programmable network proxy yang berjalan di background browser, terpisah dari thread utama halaman web. Ini berarti Service Worker tidak memiliki akses ke DOM, namun dapat berinteraksi dengan Cache API dan IndexedDB. Ketika pengguna mengunjungi website kita, Service Worker dapat mencegat setiap network request dan memutuskan bagaimana meresponnya — apakah mengambil dari cache, dari jaringan, atau kombinasi keduanya tergantung pada strategi yang kita terapkan.
Service Worker memiliki lifecycle yang terdiri dari tiga fase utama: Install, Activate, dan Fetch. Pada fase Install, Service Worker diunduh dan dieksekusi untuk pertama kalinya. Di sinilah kita menyiapkan cache awal untuk aset-aset penting seperti file CSS, JavaScript, font, dan gambar. Fase Activate terjadi setelah instalasi berhasil, dan digunakan untuk membersihkan cache lama dari versi sebelumnya. Fase Fetch adalah inti dari Service Worker — setiap request yang dibuat oleh halaman akan melalui event listener ini, memberi kita kendali penuh atas bagaimana respons dikelola.

Gambar: Siklus hidup Service Worker meliputi fase Install (precaching aset), Activate (membersihkan cache lama), dan Fetch (menangani request) — Sumber: [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers)
Astro sebagai static site generator menghasilkan output berupa file HTML, CSS, dan JavaScript statis yang sudah siap di-deploy. Pendekatan ini sangat cocok dengan arsitektur PWA karena semua aset sudah tersedia saat build time dan tidak memerlukan server-side runtime. Berbeda dengan SPA (Single Page Application) yang membutuhkan JavaScript bundle besar untuk client-side routing dan sering kali bergantung pada CDN untuk caching, website Astro yang telah di-build dapat langsung di-cache oleh Service Worker secara utuh tanpa perlu khawatir tentang kompleksitas routing di sisi klien.
Registrasi Service Worker dan Strategi Caching untuk Static Assets Astro
Langkah pertama dalam mengimplementasikan PWA di Astro adalah mendaftarkan Service Worker. Kita perlu membuat file public/sw.js yang ditempatkan di root direktori output agar dapat mengontrol seluruh halaman.
// public/sw.js
const CACHE_NAME = 'astro-pwa-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/favicon.ico',
'/assets/',
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log('Cache opened');
return cache.addAll(ASSETS_TO_CACHE);
})
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request);
})
);
});Logika di atas menerapkan strategi Cache-First untuk semua aset statis. Pada event Install, kita membuka cache bernama astro-pwa-v1 dan menambahkan daftar aset penting ke dalamnya — meliputi halaman utama, file HTML, icon favicon, dan seluruh direktori aset hasil build Astro. Proses ini terjadi hanya sekali selama siklus hidup Service Worker, yaitu saat pertama kali Service Worker diinstal atau saat ada versi baru.
Event Activate bertugas membersihkan cache lama. Saat kita melakukan update pada Service Worker dengan versi cache baru — misalnya astro-pwa-v2 — cache versi sebelumnya akan dihapus secara otomatis. Mekanisme ini penting untuk mencegah konflik antara file lama dan baru yang bisa menyebabkan error pada halaman. Pada event Fetch, Service Worker mencari request di cache terlebih dahulu menggunakan method caches.match(). Jika ditemukan, respons dari cache langsung dikembalikan tanpa menyentuh jaringan. Jika tidak, request diteruskan ke jaringan melalui fetch().
Untuk mendaftarkan Service Worker dari halaman Astro, kita tambahkan script registrasi di komponen layout atau halaman utama. Registrasi hanya perlu dilakukan sekali dan akan membuat browser mengenali keberadaan Service Worker:
// Script registrasi — letakkan di layout Astro
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then((registration) => {
console.log('Service Worker registered:', registration.scope);
})
.catch((error) => {
console.log('Service Worker registration failed:', error);
});
});
}
API Development with Golang
A hands-on, project-based course designed to teach beginners how to build robust...
Membangun Offline Fallback Page agar Aplikasi Tetap Berfungsi Tanpa Koneksi
Salah satu fitur paling penting dari PWA adalah kemampuan untuk tetap menampilkan konten saat pengguna kehilangan koneksi internet. Alih-alih menampilkan halaman error bawaan browser yang tidak ramah, kita bisa menyajikan halaman offline kustom yang informatif.
Pertama, kita buat halaman offline.astro di proyek Astro. Halaman ini akan di-cache oleh Service Worker saat proses instalasi dan ditampilkan ketika pengguna offline:
---
// src/pages/offline.astro
---
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Anda Sedang Offline</title>
<style>
body { font-family: system-ui, sans-serif; display: flex;
justify-content: center; align-items: center; min-height: 100vh;
background: #f8f9fa; }
.offline-container { text-align: center; padding: 2rem; }
</style>
</head>
<body>
<div class="offline-container">
<h1>Tidak Ada Koneksi Internet</h1>
<p>Silakan periksa koneksi Anda dan coba lagi.</p>
<button onclick="window.location.reload()">Coba Lagi</button>
</div>
</body>
</html>Selanjutnya, kita modifikasi Service Worker untuk menangani request navigasi yang gagal dengan Navigation Preload:
// Tambahan di public/sw.js untuk offline fallback
self.addEventListener('activate', (event) => {
event.waitUntil(
Promise.all([
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
);
}),
self.registration.navigationPreload.enable(),
])
);
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.catch(() => caches.match('/offline'))
.catch(() => caches.match('/offline.html'))
);
return;
}
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request);
})
);
});Navigation Preload memungkinkan browser untuk mulai memuat halaman bahkan sebelum Service Worker siap merespon. Fitur ini mempercepat waktu muat navigasi karena request dikirim paralel dengan proses aktivasi Service Worker. Jika request gagal karena pengguna sedang offline, kita mengembalikan halaman offline dari cache. Perhatikan bahwa kita menggunakan dua fallback — pertama mencocokkan dengan /offline (rute Astro) dan kemudian /offline.html — untuk mengantisipasi perbedaan output build.
Dengan pendekatan ini, pengguna tidak akan melihat pesan error browser seperti "No Internet" atau halaman ERR_INTERNET_DISCONNECTED, melainkan halaman kustom yang dirancang khusus dengan informasi yang berguna. Ini adalah prinsip dari graceful degradation — ketika fitur utama tidak bisa berfungsi karena keterbatasan koneksi, aplikasi tetap memberikan nilai dengan menyajikan konten alternatif yang informatif.
Mengelola Caching Dinamis untuk Halaman dan API dengan Workbox
Untuk website yang lebih kompleks dengan halaman dinamis dan panggilan API, strategi caching vanilla menggunakan Cache API mungkin tidak cukup. Workbox adalah library dari Google yang menyediakan abstraksi untuk routing dan caching strategies yang lebih canggih.
// public/sw.js dengan Workbox CDN
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/7.0.0/workbox-sw.js'
);
if (workbox) {
// Cache static assets — CacheFirst
workbox.routing.registerRoute(
/\.(?:js|css|html|json)$/,
new workbox.strategies.CacheFirst({
cacheName: 'static-assets',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
new workbox.expiration.ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60,
}),
],
})
);
// Cache halaman Astro — StaleWhileRevalidate
workbox.routing.registerRoute(
/^https?:\/\/[^\/]+\/(?!api\/).*$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'pages-cache',
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 50,
}),
],
})
);
// Cache API requests — NetworkFirst
workbox.routing.registerRoute(
/^https?:\/\/.*\/api\/.*$/,
new workbox.strategies.NetworkFirst({
cacheName: 'api-cache',
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 100,
maxAgeSeconds: 5 * 60,
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
],
})
);
}Mengapa menggunakan strategi yang berbeda untuk setiap jenis request? Keputusan ini didasarkan pada karakteristik masing-masing resource. Untuk aset statis seperti CSS dan JavaScript, Cache-First adalah pilihan tepat karena file-file ini jarang berubah setelah build dan kita ingin memuatnya secepat mungkin tanpa perlu menunggu respons server. Jika file di-cache, pengguna akan mendapatkan respons dalam hitungan milidetik.
Untuk halaman Astro yang mungkin diperbarui secara berkala ketika konten baru dipublikasikan, Stale-While-Revalidate lebih cocok. Strategi ini langsung mengembalikan konten dari cache sehingga halaman tampil secara instan, kemudian secara diam-diam mengambil versi terbaru dari jaringan di background untuk digunakan pada kunjungan berikutnya. Pengguna mendapatkan kecepatan cache tanpa harus mengorbankan aktualitas konten dalam jangka panjang.
Untuk panggilan API yang membutuhkan data terkini — seperti data profil pengguna atau daftar artikel terbaru — Network-First adalah strategi yang paling sesuai. Service Worker akan mencoba mengambil data dari jaringan terlebih dahulu. Jika berhasil, respons akan disimpan di cache sekaligus dikembalikan ke pengguna. Jika gagal karena offline, data dari cache yang tersimpan sebelumnya akan digunakan sebagai fallback.

Gambar: Perbandingan alur kerja tiga strategi caching utama — Cache First (kecepatan), Network First (kesegaran data), dan Stale-While-Revalidate (keseimbangan) — Sumber: [Chrome for Developers — Workbox](https://developer.chrome.com/docs/workbox/caching-strategies-overview/)
Workbox juga menyediakan ExpirationPlugin untuk membatasi jumlah cache entries dan maksimum umur penyimpanan. Ini penting karena penyimpanan Cache API di browser terbatas — biasanya sekitar 50-100MB tergantung browser. Tanpa pembatasan, cache bisa membengkak dan mempengaruhi performa browser secara keseluruhan.
Audit, Debug, dan Best Practices Menggunakan Lighthouse
Setelah mengimplementasikan Service Worker dan strategi caching, langkah selanjutnya adalah melakukan audit untuk memastikan semuanya berfungsi sesuai harapan. Chrome DevTools menyediakan tab Application > Service Workers yang menampilkan status Service Worker saat ini — termasuk versi yang aktif, scope cakupan halaman, dan klien yang terhubung. Dari sini, kita bisa melihat apakah Service Worker terdaftar dengan benar, mengupdate secara manual, atau bahkan meng-unregister untuk keperluan debugging.
Untuk simulasi offline, gunakan tab Network di DevTools dan centang opsi Offline. Dengan demikian, kita bisa melihat secara langsung bagaimana aplikasi berperilaku saat tidak ada koneksi internet. Periksa apakah halaman offline tampil dengan benar, apakah aset statis seperti CSS dan gambar masih tersedia dari cache, dan apakah ada pesan error yang muncul di console. Ini adalah cara paling efektif untuk memvalidasi strategi caching yang telah kita implementasikan.
Lighthouse adalah alat audit otomatis dari Google yang bisa mengukur sejauh mana website kita memenuhi standar PWA. Lighthouse akan memeriksa apakah Service Worker terdaftar, apakah halaman berfungsi saat offline, apakah manifest Web App terkonfigurasi dengan benar, dan apakah koneksi menggunakan HTTPS. Skor Lighthouse juga mencakup metrik performa seperti First Contentful Paint dan Time to Interactive, yang keduanya bisa meningkat signifikan dengan strategi caching yang tepat.
Beberapa best practices yang perlu diperhatikan dalam implementasi PWA. Pertama, versioning cache name — selalu gunakan versi seperti astro-pwa-v1 dan increment nomor versi setiap kali ada perubahan aset. Ini memastikan Service Worker mendownload ulang file-file yang diperbarui. Kedua, handle update Service Worker dengan baik — gunakan self.skipWaiting() pada event Install untuk mengaktifkan Service Worker baru segera setelah terinstal, dan self.clients.claim() pada event Activate untuk mengambil alih kendali semua halaman yang terbuka.
Ketiga, selalu perhatikan ketersediaan fitur di berbagai platform. PWA di iOS Safari memiliki beberapa keterbatasan dibandingkan Android — push notification belum didukung penuh, penyimpanan cache lebih terbatas, dan proses instalasi tidak semulus di Android. Lakukan pengujian menyeluruh di berbagai browser dan platform untuk memastikan pengalaman yang konsisten bagi semua pengguna.
Membangun PWA dengan Astro dan Service Worker adalah langkah maju dalam menghadirkan pengalaman web yang tangguh dan andal. Dengan strategi caching yang tepat, aplikasi kita tetap berfungsi meskipun pengguna berada di daerah dengan koneksi internet yang tidak stabil. Mulai bangun web app yang tangguh dengan Astro bersama kami di Rumah Coding.
Kursus Terkait
API Development with Golang
A hands-on, project-based course designed to teach beginners how to build robust, high-performance RESTful APIs using Golang. Starting from core Go syntax and concurrency, students will progress through routing, database integration, security, and finally containerize their application for production deployment.
EduTrack: Learning Management & Assessment API
- Role-Based Access Control (RBAC)
- Course & Module Management
- Enrollment & Progress Tracking
Advanced Architecture with Laravel Containers & Queues
A problem-driven, project-based course designed to elevate intermediate developers to a senior architectural mindset. Instead of just memorizing documentation, students will tackle real-world bottleneck issues by mastering the Inversion of Control (IoC) principle, Dependency Injection, and asynchronous background processing. Learn to decouple services and orchestrate robust queues to build scalable, high-performance applications that never freeze under heavy loads.
Asynchronous Bulk E-Certificate & Notification Engine
- Decoupled Service Architecture: PDF generation and Email delivery are built as independent, interface-driven services injected via the Service Container.
- Job Chaining: Ensuring processes run in strict asynchronous order (Generate PDF ➔ Upload to Storage ➔ Send Email).
- Job Batching & Real-Time Tracking: Grouping hundreds of jobs together and displaying a live progress bar (e.g., "65% Completed") on the admin dashboard.
Building Modern Apps with Filament
Learn how to build modern, full-stack web applications rapidly using FilamentPHP and the TALL stack. This project-based course is designed for beginners, guiding you step-by-step to create a fully functional backend administration panel. By the end of the course, you will have mastered Filament's powerful Panel Builder, robust CRUD operations, complex database relationships, and interactive dashboards.
Mini Academic Portal (Learning Management System)
- Master Data Management: Comprehensive CRUD functionality to manage Instructors and Course catalogs.
- Student Registry: A dedicated module to manage student profiles and personal information.
- Dynamic Enrollment System: Handling Many-to-Many relationships to enroll students into specific courses using Filament's pivot features.