Handling Dynamic and Static Content Offline

A fully functional offline PWA must cache both static assets and dynamic content.

1. Caching HTML Pages for Offline Use

To cache full pages dynamically, modify service_worker.js:

self.addEventListener("fetch", (event) => {
  if (event.request.mode === "navigate") {
    event.respondWith(
      fetch(event.request)
        .then((response) => {
          return caches.open("pages-cache").then((cache) => {
            cache.put(event.request, response.clone());
            return response;
          });
        })
        .catch(() => caches.match("/offline.html"))
    );
  }
});

This ensures that:


2. Preloading Key Static Assets

To make the app available offline instantly, pre-cache key assets during the service worker’s installation:

const STATIC_CACHE_NAME = "static-assets-v1";
const STATIC_ASSETS = [
  "/",
  "/offline.html",
  "/assets/logo.png",
  "/stylesheets/application.css",
];

self.addEventListener("install", (event) => {
  event.waitUntil(
    caches.open(STATIC_CACHE_NAME).then((cache) => {
      return cache.addAll(STATIC_ASSETS);
    })
  );
});

3. Providing a Reliable Offline Experience

If a user navigates to a page that is not cached, a proper fallback should be provided.

1. Create an Offline Page (public/offline.html):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Offline Mode</title>
</head>
<body>
  <h1>You are offline</h1>
  <p>Please check your connection and try again.</p>
</body>
</html>

2. Serve the Offline Page from the Service Worker

Modify service_worker.js to return this page when a request fails:

self.addEventListener("fetch", (event) => {
  event.respondWith(
    fetch(event.request).catch(() => caches.match("/offline.html"))
  );
});

This ensures that even if a user visits a page that hasn’t been cached, they see a friendly offline page instead of a browser error.