Building Offline-Ready Webpage with Service Worker and Cache Storage
Tags: webdev, javascript, frontend, tutorial
Published: 2023-09-01 19:40:52

## Why We Need Offline Web Pages

Sometimes, our internet connection isn't reliable or completely absent. In those moments, we still want to use websites and apps. This is where offline web pages come in handy. They allow us to access content even when we're not online.

## Introducing Service Workers and Cache Storage

**[Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)** are like web helpers. It work behind the scenes to make offline web pages possible. It can save website stuff (like pictures, fonts and other assets) on our device so we can see them even without the internet. It also control what our web page does when it's online.

**[Cache Storage](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage)** is like a storage room for web things. It keeps all the website stuff we might need, organised neatly. Service Workers can go there and grab what's needed for page to load offline. So, when we're not online, we still get to see and use web pages.


Let's explore how to make a webpage available offline by doing some simple coding. We'll save an HTML file and an image so that users can still see them, even when they are not connected to the internet.


**Step 1: Getting Started**
First, Let's create a folder for our project and put main HTML file `index.html` and the image we want to use `cat.jpeg` inside it.

**Step 2: Registering the Service Worker**
Now, let's register the Service Worker in `index.html` file. Place the following code:

```js
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hi There!</h1>

    <img src="./cat.jpeg" width="300" height="300" />

    <script>
      async function registerServiceWorker() {
        if ("serviceWorker" in navigator) {
          try {
            const registration = await navigator.serviceWorker.register(
              "sw.js"
            );
            console.log(
              "Service Worker registered with scope:",
              registration.scope
            );
          } catch (error) {
            console.error("Service Worker registration failed:", error);
          }
        }
      }

      registerServiceWorker();
    </script>
  </body>
</html>

```
In this code we check if the browser supports Service Workers.

**Step 3: Writing the Service Worker Code**
Now, let's create a JavaScript file called `sw.js` in project folder. This file will contain the code for Service Worker.

```js
const cacheName = "offline-cache-v1";
const cacheUrls = ["index.html", "cat.jpeg"];

// Installing the Service Worker
self.addEventListener("install", async (event) => {
  try {
    const cache = await caches.open(cacheName);
    await cache.addAll(cacheUrls);
  } catch (error) {
    console.error("Service Worker installation failed:", error);
  }
});

// Fetching resources
self.addEventListener("fetch", (event) => {
  event.respondWith(
    (async () => {
      const cache = await caches.open(cacheName);

      try {
        const cachedResponse = await cache.match(event.request);
        if (cachedResponse) {
          console.log("cachedResponse: ", event.request.url);
          return cachedResponse;
        }

        const fetchResponse = await fetch(event.request);
        if (fetchResponse) {
          console.log("fetchResponse: ", event.request.url);
          await cache.put(event.request, fetchResponse.clone());
          return fetchResponse;
        }
      } catch (error) {
        console.log("Fetch failed: ", error);
        const cachedResponse = await cache.match("index.html");
        return cachedResponse;
      }
    })()
  );
});

```
THere's what's happening in the code:
- We give a name to our cache (cacheName) and list the URLs (cacheUrls) we want to store for offline use.
- In the "install" part, we prepare our cache and add the URLs to it.
- We open the cache and attempt to match the request with the cached responses.
- If a cached response is found, it's returned. If not, we fetch the resource from the network, cache it for future use, and return the network response.
- In case of any errors during the fetch process, we handle it by returning a cached version of "index.html" to ensure the user still sees something.


**Step 4: Testing our Offline-Friendly webpage**
To check if the page works offline:

- Open the page while the device is online to make sure it loads correctly, including the image.
- Disconnect from the internet (turn off Wi-Fi or unplug network cable).
- Reload the page. We should still see the page, including the image, even though there's no internet.

We can also test from the chrome browser, here's the steps:
- Open the page while the device is online
- Open devtools in chrome browser and go to the `Application` tab
- Click on `Service Workers` from the sidebar and check the `Offline` option
- Reload the page and we can see the contents loading offline


![Cate image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tfjbg2k6kgv0cgx4dr2m.png)



We've now created a webpage that can work offline using Service Workers. This technique can be expanded to store more things and make websites robust even when there's no internet.

Full Code 👉 https://github.com/nsourov/offline-web-page