Skip to content

Instantly share code, notes, and snippets.

@arschmitz
Last active March 26, 2022 01:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arschmitz/0ce03016080f008c0c6040ea3c56d3d9 to your computer and use it in GitHub Desktop.
Save arschmitz/0ce03016080f008c0c6040ea3c56d3d9 to your computer and use it in GitHub Desktop.

What is a PWA

According to google a service worker is...

Progressive Web Apps are user experiences that have the reach of the web, and are:

  • Reliable - Load instantly and never show the downasaur, even in uncertain network conditions.
  • Fast - Respond quickly to user interactions with silky smooth animations and no janky scrolling.
  • Engaging - Feel like a natural app on the device, with an immersive user experience. This new level of quality allows Progressive Web Apps to earn a place on the user's home screen.

Reliable

When launched from the user’s home screen, service workers enable a Progressive Web App to load instantly, regardless of the network state. A service worker, written in JavaScript, is like a client-side proxy and puts you in control of the cache and how to respond to resource requests. By pre-caching key resources you can eliminate the dependence on the network, ensuring an instant and reliable experience for your users.

Fast

53% of users will abandon a site if it takes longer than 3 seconds to load! And once loaded, users expect them to be fast—no janky scrolling or slow-to-respond interfaces.

Engaging

Progressive Web Apps are installable and live on the user's home screen, without the need for an app store. They offer an immersive full screen experience with help from a web app manifest file and can even re-engage users with web push notifications. The Web App Manifest allows you to control how your app appears and how it's launched. You can specify home screen icons, the page to load when the app is launched, screen orientation, and even whether or not to show the browser chrome.

Reliability with service workers

What is a service worker

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. Today, they already include features like push notifications and background sync. In the future, service workers will support other things like periodic sync or geofencing. The core feature is the ability to intercept and handle network requests, including programmatically managing a cache of responses.

Service workers were designed to fix key issues with the previous solution app cache

Caching stratagies for web apps

Cache only

Cache only

Ideal for: Anything you'd consider static to that "version" of your site. You should have cached these in the install event, so you can depend on them being there.

Network only

Network only Ideal for: Things that have no offline equivalent, such as analytics pings, non-GET requests.

Cache, falling back to network

Cache, falling back to network Ideal for: If you're building offline-first, this is how you'll handle the majority of requests. Other patterns will be exceptions based on the incoming request.

Cache & network race

Cache & network race Ideal for: Small assets where you're chasing performance on devices with slow disk access.

With some combinations of older hard drives, virus scanners, and faster internet connections, getting resources from the network can be quicker than going to disk. However, going to the network when the user has the content on their device can be a waste of data, so bear that in mind.

Network falling back to cache

Network falling back to cache Ideal for: A quick-fix for resources that update frequently, outside of the "version" of the site. E.g. articles, avatars, social media timelines, game leader boards.

This means you give online users the most up-to-date content, but offline users get an older cached version. If the network request succeeds you'll most-likely want to update the cache entry.

However, this method has flaws. If the user has an intermittent or slow connection they'll have to wait for the network to fail before they get the perfectly acceptable content already on their device. This can take an extremely long time and is a frustrating user experience. See the next pattern, "Cache then network", for a better solution.

Cache then network

Cache then network Ideal for: Content that updates frequently. E.g. articles, social media timelines, game leaderboards.

This requires the page to make two requests, one to the cache, one to the network. The idea is to show the cached data first, then update the page when/if the network data arrives.

Sometimes you can just replace the current data when new data arrives (e.g. game leaderboard), but that can be disruptive with larger pieces of content. Basically, don't "disappear" something the user may be reading or interacting with.

Twitter adds the new content above the old content & adjusts the scroll position so the user is uninterrupted. This is possible because Twitter mostly retains a mostly-linear order to content. I copied this pattern for trained-to-thrill to get content on screen as fast as possible, but still display up-to-date content once it arrives.

Generic fallback

Generic fallback Ideal for: Secondary imagery such as avatars, failed POST requests, "Unavailable while offline" page.

If you fail to serve something from the cache and/or network you may want to provide a generic fallback.

ServiceWorker-side templating

ServiceWorker-side templating Ideal for: Pages that cannot have their server response cached.

Rendering pages on the server makes things fast, but that can mean including state data that may not make sense in a cache, e.g. "Logged in as…". If your page is controlled by a ServiceWorker, you may instead choose to request JSON data along with a template, and render that instead.

In Conclusion on service workers

You don't have to pick one of these methods, you'll likely use many of them depending on request URL. For example, an app that interacts with Flikr might use:

  • Cache on install, for the static UI and behaviour
  • Cache on network response, for the Flickr images and data
  • Fetch from cache, falling back to network, for most requests
  • Fetch from cache, then network, for the Flickr search results

Engaging users with installable immersive apps

It's so meta!

To make apps installable and appear correct across a range of device many propriatary meta tags are used to control the look and feel of the app when installed. The level of resource access and customizability when installing a PWA range based on the device, browser, and operating system. The range goes from Android which when installed allows full system access just like it was downloaded from google play to iOS which just gives you a homescreen icon and takes away the browser chrome.

<!-- Must -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<meta name="description" content="Description">
<meta name="keywords" content="Keywords">
<title>Page Title</title>

<!-- Android  -->
<meta name="theme-color" content="red">
<meta name="mobile-web-app-capable" content="yes">

<!-- iOS -->
<meta name="apple-mobile-web-app-title" content="Application Title">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">

<!-- Windows  -->
<meta name="msapplication-navbutton-color" content="red">
<meta name="msapplication-TileColor" content="red">
<meta name="msapplication-TileImage" content="ms-icon-144x144.png">
<meta name="msapplication-config" content="browserconfig.xml">

<!-- Pinned Sites  -->
<meta name="application-name" content="Application Name">
<meta name="msapplication-tooltip" content="Tooltip Text">
<meta name="msapplication-starturl" content="/">

<!-- Tap highlighting  -->
<meta name="msapplication-tap-highlight" content="no">

<!-- UC Mobile Browser  -->
<meta name="full-screen" content="yes">
<meta name="browsermode" content="application">

<!-- Disable night mode for this page  -->
<meta name="nightmode" content="enable/disable">

<!-- Fitscreen  -->
<meta name="viewport" content="uc-fitscreen=yes"/>

<!-- Layout mode -->
<meta name="layoutmode" content="fitscreen/standard">

<!-- imagemode - show image even in text only mode  -->
<meta name="imagemode" content="force">

<!-- Orientation  -->
<meta name="screen-orientation" content="portrait">

ALL THE LINKS!

While the meta tags instruct the device how to display your app link tags will tell it what images to use for various icons and loading screens

<!-- Main Link Tags  -->
<link href="favicon-16.png" rel="icon" type="image/png" sizes="16x16">
<link href="favicon-32.png" rel="icon" type="image/png" sizes="32x32">
<link href="favicon-48.png" rel="icon" type="image/png" sizes="48x48">

<!-- iOS  -->
<link href="touch-icon-iphone.png" rel="apple-touch-icon">
<link href="touch-icon-ipad.png" rel="apple-touch-icon" sizes="76x76">
<link href="touch-icon-iphone-retina.png" rel="apple-touch-icon" sizes="120x120">
<link href="touch-icon-ipad-retina.png" rel="apple-touch-icon" sizes="152x152">

<!-- Startup Image  -->
<link href="touch-icon-start-up-320x480.png" rel="apple-touch-startup-image">

<!-- Pinned Tab  -->
<link href="path/to/icon.svg" rel="mask-icon" size="any" color="red">

<!-- Android  -->
<link href="icon-192x192.png" rel="icon" sizes="192x192">
<link href="icon-128x128.png" rel="icon" sizes="128x128">

<!-- Others -->
<link href="favicon.icon" rel="shortcut icon" type="image/x-icon">

<!-- UC Browser  -->
<link href="images/icon-52x52.png" rel="apple-touch-icon-precomposed" sizes="57x57">
<link href="images/icon-72x72.png" rel="apple-touch-icon" sizes="72x72">

<!-- Manifest.json  -->
<link href="/manifest.json" rel="manifest">

The manifest

The web app manifest is a simple JSON file that gives you, the developer, the ability to control how your app appears to the user in areas where they would expect to see apps (for example, a mobile device's home screen), direct what the user can launch, and define its appearance at launch.

Web app manifests provide the ability to save a site bookmark to a device's home screen. When a site is launched this way:

It has a unique icon and name so that users can distinguish it from other sites. It displays something to the user while resources are downloaded or restored from cache. It provides default display characterstics to the browser to avoid too abrupt transition when site resources become available.

{
  "short_name": "AirHorner",
  "name": "Kinlan's AirHorner of Infamy",
  "icons": [
    {
      "src": "launcher-icon-1x.png",
      "type": "image/png",
      "sizes": "48x48"
    },
    {
      "src": "launcher-icon-2x.png",
      "type": "image/png",
      "sizes": "96x96"
    },
    {
      "src": "launcher-icon-4x.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ],
  "start_url": "index.html?launcher=true"
}

Browserconfig the Microsoft way...

Browser configuration files (also known as browserconfig) can be used to define pinned site customizations, such as tile backgrounds, badge updates, and tile notifications. Browser configuration files let you set these customizations using external XML files rather than metadata within the HTML markup of a webpage.

<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
   <msapplication>
     <tile>
        <square70x70logo src="small.png"/>
        <square150x150logo src="medium.png"/>
        <wide310x150logo src="wide.png"/>
        <square310x310logo src="large.png"/>
        <TileColor>#009900</TileColor>
     </tile>
     <badge>
        <polling-uri src="badge.xml"/>
        <frequency>30</frequency>
     </badge>
     <notification>
        <polling-uri  src="1.xml"/>
        <polling-uri2 src="2.xml"/>
        <polling-uri3 src="3.xml"/>
        <polling-uri4 src="4.xml"/>
        <polling-uri5 src="5.xml"/>
        <frequency>30</frequency>
        <cycle>1</cycle>
     </notification>
   </msapplication>
</browserconfig>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment