Offline Cache Implementation

Consider the very simple example below:

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Simple HTML with Script</title>
</head>
<body>
    <h1>Hello, World!</h1>
    <img src="https://img.freepik.com/free-photo/red-white-cat-i-white-studio_155003-13189.jpg?w=200"/>
    <img src="https://avatars.githubusercontent.com/u/16440123?v=4"/>
    <div class="data"></div>
    <script src="app.js"></script>
</body>
</html>

app.js

if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('sw.js', {
            scope: "/"
        })

        navigator.serviceWorker.getRegistration().then(reg => {
            if (typeof reg === "undefined") {
                console.log("There is no service worker here", reg)
                return;
            }
        })
    })
}

fetch('https://pokeapi.co/api/v2/pokemon/ditto')
  .then(response => {
    if (response.ok) {
        return response.json()
    } else {
        throw new Error('Network response was not OK.');
    }
  })
  .then(data => {
    document.querySelector(".data").innerHTML = JSON.stringify(data);
    // Handle the API response here
  })
  .catch(error => {
    console.log('Fetch error:', error);
    // Handle the error here
  });

sw.js

const CACHE = 'v1';

// Service Worker Installation
self.addEventListener('install', event => {
    console.log('Service Worker: Installing', event);
    // Perform any pre-caching or initialization tasks here
});

// Service Worker Activation
// Perform any cache cleanup or initialization tasks here
self.addEventListener('activate', event => {
    console.log('Service Worker: Activating', event);
});

// Service Worker Fetch Event
// Handle incoming network requests or cache responses here
self.addEventListener('fetch', (event) => {
    console.log("Service worker fetch called for: ", event.request.url);
    event.respondWith(handleFetch(event))

});


async function handleFetch(event) {
    let cache = await caches.open(CACHE)
    let response;

    try {
        response = await fetch(event.request)
        if (response && response.status === 200) {
            cache.put(event.request, response.clone())
        }
    } catch (exception) {
        response = await cache.match(event.request)
    }

    return response;
}

We can use the cache browser API and get the cache out using cache.match.

This fetch listener will intercepts all fetch request — including external APIs. However it will not intercepts request like <iframe> because it's not a fetch request.