Conference talk slides about creating your own progressive web app, comparing appcache and Service Worker and how they can be used in Drupal (or as standalone without!)
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Taking Drupal 8 Sites Offline: airplane mode surfing!

Ryan Weal

Kafei Interactive Inc.

DrupalCamp Northern Lights, Reykjavík, Iceland

Formatted as slides here:

Why talk about offline?

  • Wifi not always on board aircraft
  • Travelling internationally without data
  • Bored while on the bus
  • Networks can be slow, load time is slow
  • Adventure awaits (when you are out in the mountains!)
  • Internet goes down due to IoT devices, undersea cables, etc.

Planning for Offline

  • Decide what content you need offline
  • Do you want fallback content if not online?
  • What will we sync with an online Database?

Architecture considerations...

  • How long should your initial page load take?
    • People generally abandon requests of 10s or more.
  • Keep it light! 5MB or less is ideal.
    • Storage limits set by browser. See "The Offline Cookbook" for more details.
    • You may use IndexedDB to get around this*
  • Will you need a companion desktop application? (ie, Electron?)

Does this sound familiar?

  • Content Security Policy (CSP)
    • Forces same origin - no CDN, embeds, AJAX*
  • Bigpipe loads the initial shell of the site
  • Cache expiry headers
  • XMLsitemap lists all resources on a site

appcache (first strategy)

  • Adds a metadata field to your HTML

  • Specifies a manifest file that lists the resources

  • Downloads ALL the resources on the first page hit

  • Content is served locally first, until new manifest

  • Just works™

  • Depreciated (this is why we can't have nice things)

  • Currently the ONLY way to do offline on Apple devices

Our first (non-Drupal) appcache site!

appcache index.html

<!doctype html>
<html manifest="bulletpad.appcache">
  <meta charset="utf-8">
  <script type='text/javascript' src='vue.js'></script>
  <script type='text/javascript' src='main.js'></script>
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
  <meta name="viewport" content="width=device-width">

<div id="app">
  <textarea v-model="newTodo" v-on:keyup.enter="addTodo" placeholder="new note >"></textarea>
    <li v-for="todo in todos | reverse">
      {{ todo.text }}
      <button v-on:click="removeTodo($index)">×</button>


This uses vue.js, btw... we love it.

appcache bulletpad.appcache

# v11

# assets


No offline fallback in this case, but it is possible.

(100% of this "site" is in the manifest)

appcache demo app screenshot of example app

appcache debugging

  • Keep the console log open
  • Update the serial "number" in manifest with each change
  • Chrome dev tools Network tab has "disbable cache" and "offline" modes
  • New version loads after serving old verison to user

appcache basics: further reading

"A Beginner's Guide to Using the Application Cache"

"Application Cache is a Douchebag"

appcache drupal module

"Offline Application"

Made for Frontend United 2016 by swentel

offline_app assumptions

  • All the content is going to fall under /offline/
  • Presumes you will have one level of alias, no / in paths!
  • Suppresses theme from rendering
  • Three new block regions
  • Does not load images or other assets on nodes
  • Will not let you set custom homepage fallback

Very tempting to try putting paths in first page of config... don't! Use the Content and Assets tabs.

offline_app setup

  • Enable permissions for anonymous user:

    • Access Application Cache manifest
    • Access Homescreen manifest
    • Access offline content
  • Add the manifest to pages using one of:

    • default behavior adds iframe to sidebar_first; or...
    • admin/config/services/offline-app checkbox for "Add the manifest attribute to the HTML tag..."
  • Clear the cache

offline_app content type configuration

  • Use content type manage display "custom display settings" to add either (or both) the "offline page" and "offline teaser" view modes.

  • After enabling view mode go to /admin/config/services/offline-app/content

  • Input a node path: beauty/node:1

  • Now /offline/beauty should return /node/1 (rebuild cache?)

offline_app views configuration

  • Add an "offline" display to the view

  • Show: "content" with "offline page" view mode

  • Reference it in our config:


  • Now /offline/articles will show the view called "super_awesome" using the offline_1 variant

offline_app config complete

config page screenshot for offline_app

offline_app ... much wow!

offline_app final result

offline_app potential problems!

  • Nothing added to the manifest automatically (nodes, etc)

  • Add stylesheets to your Assets list, but paths can change...

  • When (and how) to reload with new content

  • No option for separate caches for shell/content

  • Visit the homepage, check that tag has manifest reference

  • Roll your own implementation?

appcache and offline_app: further reading

"Let's make Drupal 8 available offline using appcache"

Service Worker (second strategy)

  • Also known as: "Progressive Web Apps!" (PWA)
  • Can be added to user's Android homescreen*
  • Encouraged to load the shell first, fetch content later...
  • Multiple caches! As many as you want.
  • Our demo code:

Service Worker: Characteristics

  • Manifest file is now in JSON format
  • Requires JavaScript to register the "Service Worker"
  • Recommended to do things like use a loading icon
  • Code can target different stages: install / activate / fetch
  • You are free to create many types of caches for your data
  • Intercepts requets so you can choose offline or online content

Service Worker: Is it ready?

Service Worker demo screenshot of bulletpad_pwa

Service Worker pwa appears "standalone"

screenshot of bulletpad varients in application switcher

Define the caches and context

var cacheName = 'bulletpad-x6'; // app shell
var filesToCache = [

Setting up our app by caching the shell

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil( {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);

If installed correctly this will check for a new version on first launch after reboot.

self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
    caches.keys().then(function(keyList) {
      return Promise.all( {
        if (key !== cacheName) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);

Interceping any http request, serving local if possible!

self.addEventListener('fetch', function(e) {
  console.log('[ServiceWorker] Fetch', e.request.url);
    caches.match(e.request).then(function(response) {
      return response || fetch(e.request);
  ); // iterate on your other caches

Many alternate variations of this: can do cache-only, network-only, network-fallback, or race network vs. cache! Also: cache-then-network, or offline.html message... examples in "Offline Cookbook" (see last slide).

Service Worker debugging

  • Needs https or "localhost" domain to test/run
  • Update the cache key(s) with each revision
  • console_log is your friend
  • chrome://inspect/#service-workers
  • chrome://serviceworker-internals
  • Test with Google Lighthouse (new!)

Service Worker: potential problems

  • Every change can make the entire site re-download (but you can design around this)
  • Devices have storage limits, query them! Find out if full.
  • No reload button for Chrome on Android (pull down to reload)
  • Unless you use Lighthouse to test you may have bugs interfering with offline capability!

Service Worker Drupal Modules

"Progressive Web App" by nod_

for Drupal 7 and Drupal 8

"Service Worker" by nod_

No official release yet. Looks to be a demo in favor of above.

Service Worker PWA Drupal Module

  • has support for "installing" the site, icon config

  • choose standalone app, fullscreen mode, minimal UI

  • pick what URLs to cache on install

  • intended to help speed up CSS and JS

  • tries to be aware of images, etc. but does not cache them

  • cache key is hard to update

Service Worker new features

Google announced in February 2017 that Service Worker apps will now have all of the other capabilities of a native app, including:

  • generated APK file
  • install/uninstall functionality
  • visible in apps drawer, not just homescreen

... but you cannot submit that APK to the Play store.

Service Worker, in Drupal Core?

This idea has been floated as a demonstration of basic functionality that would be "out of the box" functional.

Target audience would be camps primarily. More advanced use cases would make their own module.

Service Worker: further reading

"Your First Progressive Web App"

"Adding a Service Worker and Offline into your Web App"

More Good Stuff

"The offline cookbook"

"Web App Install Banners"


You can also render your PWAs as desktop apps. Electron is a wrapper for Chrome's rendering engine.