Progressive Web Applications Manifest and Cache API

Progressive Web Applications Manifest and Cache API

In this PWA post I will cover the Cache API and the storage limitations of the Cache and IndexedDB APIs, how you can use a Manifest file to support touch icons and the 'add to homescreen' functionality and the Lighthouse audit tool.

Cache API

A cache is technically a request-to-response map, where we store request URLs and their responses in the cache. This allows us to serve data from the cache initially, or intercept network requests and serve directly from the cache where possible.

There are a number of methods in the Cache API, however I will not be covering them in this post.

Building a simple application cache

Mapping our cache actions to Service Worker events will help us to understand how to incorporate caching into service workers and allow you to build upon your service workers easily.

SW event Cache action
Install Build cache
Activate Update cache
Fetch Retreive asset

There are a number of common caching strategies such as the Cache with Network fallback you have seen in a previous PWA post. This strategy focuses on caching on network response, other strategies focus on caching on installation or on user interaction.

Note: You should have a service worker setup prior to continuing. Instructions to set-up a basic service worker and how to implement it on your page can be found on my GitHub Gist.

Cache on Install

Caching on install happens in almost every service worker, because we almost always cache some static assets. For instance a website header image, the CSS file etc. This particular caching stategy extends to webapps in a specific way, caching your application shell! By caching our application shell we stop the user from having to redownload the static parts of a web application, meaning that they only use data for the dynamic parts of the application.

Cache on Install flow diagram

The code example for this can be found on my GitHub Gist.

Cache on User Interaction

Caching on user interaction is very useful for a lot of user journeys, for instance a blog that does not fully-support an offline experience could make use of this strategy by allowing users to "Save for Later". Triggering this action would then put a copy of an article/post in the cache, allowing the user to visit that post at their leisure e.g. while on the train home from work, while offline.

The Cache API is available from pages, not just the service worker and this means that we can add things to the cache without involving the service worker. The following code is an example DOM structure and JavaScript that should be added to your webapp's JavaScript and not your service worker:

HTML:

<div id="articleList" >
  <div class="article" id="articleID">
    <!-- your article link/thumbnail goes here -->
  </div>
</div>

JavaScript:

// when an item in your articleList is clicked
document.querySelector('#articleList').addEventListener('click', (event) => {
  event.preventDefault();
  var class = event.target.class;
  if (class.includes("article")) {
    var id = event.target.id;
    
    // create a new cache for the article and add it
    caches.open('mysite-article-' + id)
      .then((cache) => {
        // fetch the article to add to the response
        fetch('/get-article-urls?id=' + id)
          .then((response) => return response.json())
          .then((urls) => cache.addAll(urls))
          .catch((error) => return error);
      }).catch((error) => sreturn error);
  }
});

Using the code example above you should be able to implement Cache on User Interaction with ease, the only real changes needed are configuration-related for your website e.g. DOM structure and fetch URL + parameters. You will also need to adjust your fetch event listener in the service worker to check for article caches.

Storage limitations

Due to Progressive Web Application's being a rather young technology, the specifications for these young APIs aren't quite as unified across browsers as you would expect and therefore implementation details vary slightly. To clarify: there is no change in behaviour across browsers.

It is very common for these storage limitation to be across the various storage APIs, that means that your cache, indexedDB, localStorage and cookies etc can all count towards your storage limit.

Browser Limitations Notes
Chrome & Opera No Limit Storage is per origin, not API
Firefox No Limit Prompts after 50mb
Safari No Limit Prompts after 5mb
Internet Explorer (v10+) 250mb Prompts after 10mb
Edge 50mb Limitations are calculated from available space

These are not hard figures as the specification is still being standardised across browsers, therefore they are subject to change. I would use the rule of thumb: Don't bank on more than 20mb of space available. Think of your mobile users, your poor storage starved mobile users!


Manifest file

A manifest file is primarily for mobile browsers, allowing you to simulate a native-app experience for your web app. This is achieved by giving users the opportunity to 'Add to Homescreen'. This will 'install' the application on the user's device and allow them to run it from their app launcher, in a headerless browser. This gives the user a more native-feeling experience.

Screenshot of a PWA running as an app

The file is just some json information, here is an example:

{
  "name": "My Application",
  "short_name": "My Application",
  "start_url": "index.html",
  "icons": [{
    "src": "images/touch/icon-128x128.png",
    "sizes": "128x128",
    "type": "image/png"
  }],
  "background_color": "#ffffff",
  "display": "standalone",
  "theme_color": "#f05f40"
}

You can examine your manifest file in Chrome Dev Tools, via the 'Application' tab and Manifest heading. You can now examine many of the individual properties in your manifest, it will even render the icon images.

Manifest as shown in Chrome Developer Tools for https://wandr.world

You can include your manifest in your webapp by adding the following HTML to your head tag:

<link rel="manifest" href="manifest.json">

Touch icons

The icons key in your manifest file are important, especially as the manifest specification matures. These icons are used not just as the 'app launcher' tile image, but also in the splash page of the app while it loads.

Currently for other non-Android operating systems, we need to specify some HTML shivs so that our icons are picked up. The below example uses the Wandr website as an example:

  <!-- Add to homescreen for Safari on iOS -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="Wandr">
  <link rel="apple-touch-icon" href="./assets/static/favicon_192px.png">

  <!-- Tile for Win8 -->
  <meta name="msapplication-TileColor" content="#f05f40">
  <meta name="msapplication-TileImage" content="./assets/static/favicon_192px.png">

As Progressive Web Applications mature and become more widely supported, these shivs won't be necessary. You can read more about all the different properties you can set in your manifest at Google Developer docs.

Lighthouse audit tool

Lighthouse is an open-source audit tool for webpages, focusing on the core areas: progressive web apps (most of this comes from the PWA checklist), performance, accessibility and best practices. Lighthouse scores the webapp in each of these areas and provides human-friendly information on how to score higher and fix issues in your webapp.

You can run Lighthouse directly from Chrome dev. tools on a page (open Chrome dev tools and navigate to the Audits tab), as a Chrome extension or from the commandline using the npm package.

Screenshot of Lighthouse

You can run Lighthouse directly from Chrome dev. tools on a page, as a Chrome extension or from the commandline using the npm package.

The best part of a Lighthouse report is the feedback given for each of your scores, the feedback tells you what was done correctly and what can be approved. The highlight of this is that the information is human-friendly, not just a generic error as we so regularly find in web development.

Screenshot of https://wandr.world/ PWA breakdown from Lighthouse

As you can see in the screenshot above, the criteria your webapp is measured by are clearly displayed and in cases where it does not meet these criteria comprehensive errors are given, as depicted in the screenshot below:

Screenshot of https://wandr.world/ Performance enhancement opportunities

Opportunities to improve the performance of my webapp are listed in the above screenshot, with clear instructions on how this can be achieved.

Using Lighthouse to audit your webapp helps you to contribute to a reach PWA ecosystem and ensures that you are building responsive, performant webapps. In cases where your webapp isn't as well-built as it could be, Lighthouse even offers insights on improving your webapp. I believe that Lighthouse is an invaluable tool that will become a part of all web developers toolkits in the near future, get ahead of the curve and start using it now!


What have you built?

You can view a large and growing list of Progressive Web Applications at https://outweb.io/ and https://pwa.rocks/, you can even index your own applications on these websites!

Leave a comment or tweet me, letting me know what you've been building throughout this post! I'm a massive advocate of PWAs and can't wait for the day that the majority of websites leverage service workers and manifest files.