~/Blog

Brandon Rozek

Photo of Brandon Rozek

PhD Student @ RPI studying Automated Reasoning in AI and Linux Enthusiast.

Listing Offline Pages with Service Workers

Published on

2 minute reading time

Using web service workers, you can set it up so that visitors have an offline experience with your website. In my original blog post, I wrote about how to cache pages, and how to show them when the visitor lacks an Internet connection, or a special offline page instead.

This, however, doesn’t list what pages are cached on their device. Wouldn’t it make sense to show this in the offline page? It was kinda crazy that I didn’t do this before, so in this post we’ll go over how to showcase the list of saved offline pages.


Recall that web workers give us access to the cache interface. From it, we can access any number of caches.

const cache = await caches.open('v1::website')

A cache is a dictionary, with Requests objects mapped to Response objects. We can filter within our cache for request-response pairs that match a particular URL structure or has a certain content type.

for (const request of await cache.keys()) {
    const url = request.url;
    if (url.includes('/blog')) {
        const response = await cache.match(request)
        if (response.headers.get('content-type').includes('text/html')) {
            process(request, response);
        }
    }
}

For my offline pages listing, I want it to look like the following:

We can get the title by searching for the <title> tag within the response object.

const body = response.text()
const title = body.match(/<title>(.*)<\/title>/)[1]

For the last visited, we can look at the response headers.

const visited = new Date(post.headers.get('date'))

Let’s say we stored all of this within a list

result.push({url, title, visited})

We can then iterate over result and add list items within a unordered-list <ul>.

const el = document.querySelector('#offline-posts');
if (result.length) {
	el.innerHTML = result
      .map((res) => {
        let html = `<li>
        <a href="${res.url}">${res.title}</a>
        <small><span title="${res.visited.toString()}">
            (visited ${daysAgo(res.visited)})
        </span></small>
        </li>`;
        return html;
      })
      .join('\n');
}

The function daysAgo returns an easy to read time delta between the visited timestamp and now.

function daysAgo(date) {
  date.setHours(0, 0, 0, 0);
  const time = date.getTime();
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const now = today.getTime();
  const delta = ((now - time) / 1000 / 60 / 60 / 24) | 0;

  if (delta < 1) {
    return 'today';
  }

  if (delta === 1) {
    return 'yesterday';
  }

  return `${delta | 0} days ago`;
}
Reply via Email Buy me a Coffee
Was this useful? Feel free to share: Hacker News Reddit Twitter