An overview of the motivation behind progressive web apps, how to implement them, and other useful tools and discussion. For full presentation with usable links: https://goo.gl/VRKE6L
2. Overview
● Why progressive?
● Service Workers
● Cache API
● IndexedDB
● Manifest
● Current Browser Support
● Development with Lighthouse
● Build Tools & Plugins
● The Future
3. ● Don’t make network connectivity, browser or device choice a limiting factor
● Boost web app performance even for good connectivity
● Enable engagement for offline users
● Create a native-like experience
● Four components: service workers, cache API, IndexedDB, manifest file
Why Progressive?
4. ● Progressive web apps bigger topic than offline support
● AppCache difficult to work with
● Alternative with service workers and cache API
● Service workers are just code
● Simple, repeatable patterns
Service Workers: the Why
5. Service Workers: the What
● Run in their own worker context (no DOM access)
● Use postMessage, onMessage for child/parent communication
● Fully asynchronous
● Have access to cache API and fetch API
● Basic idea: service workers act as a proxy server
● HTTPS only
6. Service Workers: the How
● Lots of ways to do this…
● Progressive Enhancement: Register service worker
● Declare network resources to cache
● Subsequent page request fetch cached resources
● Can additionally choose to fetch updated resources from network
7. Service Workers to the Rescue: Service worker lifecycle
Waiting
Terminated
Fetch /
Message
Error
Install
Activate
Idle
No Service
Worker
9. More about Cache API
● Request/Response storage
● Origin can have multiple cache objects
● Should periodically delete unused caches to be safe
● Cache polyfill (https://github.com/coonsta/cache-polyfill)
10. IndexedDB
● Allow storage of larger, more structured datasets
● Supports queries, cursors etc.
● Transactional, Object-Orientated database
● Built with async in mind, indexeddb-promised (for Chrome only)
11. Manifest
● Specify appearance of web app
● More native-like experience
● Example
● Include with link tag
<link rel="manifest" href="/manifest.json">
13. Current Browser Support
● Basically just Chrome, Firefox, and Opera for the time being
● Is Service Worker Ready?
● Also polyfills for different APIs
● Chrome has good support for development
○ DevTools: Toggle force upload in sources tab
○ DevTools: Clear cache/unregister service workers with “clear storage”
○ Check running service workers: chrome://inspect/#service-workers
○ Check all registered instances: chrome://serviceworker-internals/
19. ● Progressive Web Apps
○ Addy Osmani
○ Google Developers
○ pazguille/offline-first
○ Udacity: Offline Web Applications
● Service Workers
○ Introduction to Service Workers
References
20. ● Application Cache
● Cache API
● IndexedDB
○ Using IndexedDB
● Browser Support
References
Editor's Notes
This presentation will provide a high level introduction and overview of the technologies behind progressive web apps: service workers, cache API, IndexedDB, and the manifest file. I’ve decided to structure the presentation in this for at least two reasons I can think of. Firstly, the technologies behind progressive web apps, while not exactly brand new, are not equally implemented in all browsers as yet if at all. Secondly, as a self contained subject progressive web apps is fairly brief, meaning either you know nothing about them at all or pretty much everything there is to know. If I haven’t lost you at this point, good! Let’s continue.
This presentation will provide a high level introduction and overview of the technologies behind progressive web apps: service workers, cache API, IndexedDB, and the manifest file. I’ve decided to structure the presentation in this for at least two reasons I can think of. Firstly, the technologies behind progressive web apps, while not exactly brand new, are not equally implemented in all browsers as yet if at all. Secondly, as a self contained subject progressive web apps is fairly brief, meaning either you know nothing about them at all or pretty much everything there is to know. If I haven’t lost you at this point, good! Let’s continue.
With all that said, why do we care about progressive web apps? Really, what we want is to ensure that neither network connectivity, browser or device choice is a limiting factor for using our web application. In fact, we can go further than this and enhance the app performance for the whole range of network connectivity. At the one end, with ideal network connectivity, we can ensure that the page loads as quickly as possible by fetching locally cached assets instead of fetching them across the network. At the other end, with poor or even no connectivity, we can serve up some experience where this would not have been possible.
More broadly, progressive web apps unlock multiple capabilities such as push notifications and web app display customisation that compete directly with a native app. We can make the move to much more lightweight web app alternatives that much more compelling.
I should also flag up some conflation between progressive web apps and offline-first initiatives. Although progressive web apps enable offline interaction, offline should never be the end goal - we really just care about reliability over flaky network connections. Offline is just a nice add-on, but that won’t stop be using the term!
Also should make clear, this is only considering the current Chrome support
AppCache is just a configuration manifest - problems we have in development simply require us to read documentation. Other problems: forcing updates, reads from cache even if offline etc.
Service workers are again case of code over configuration: can debug, test etc. We have complete control over the experience
Repeatable patterns: exists plugins to save us time of writing from scratch every time
Service workers and cache can be used independently, but together can be effective replacement for AppCache
Moving on to progressive web apps as there are now. The main workhouse are service workers
“Workers” as in run in own thread in browser. A service worker is run in a worker context: it therefore has no DOM access, and runs on a different thread to the main JavaScript that powers your app, so it is not blocking. It is designed to be fully async; as a consequence, APIs such as synchronous XHR and localStorage can't be used inside a service worker.
Both main program and service worker pattern work in event dispatch / event listening
Perhaps no surprise that service workers are fully asynchronous. , APIs such as synchronous XHR and localStorage can't be used inside a service worker.
Access to multiple API such as cache API and fetch API. Will return to cache API later, but for completeness just discuss fetch a bit more here. fetch API is a new alternative to XHR API with full promise support.
Basic idea: service worker acts a programmable proxy server
Because of this, service workers must be served over HTTPS only to prevent man in the middle attacks. Can still develop on localhost - considered secure origin
Lifecycle independent of the page: assets, page, and service worker have separate lifetimes. In fact the service worker has a maximum lifespan of 24hours. We will go into this a bit more soon, but to elaborate, after 24 hours, the browser will look to replace the existing service worker once all
The specific implementation of a progressive web depends very much on the kind of web app you are developing, and the kind of progressive experience you want to enable. For this presentation and the demo, I will consider the case where we have a hard dependency on our assets - we need them for the page to load as expected. If you are interested in other patterns, this link is to an article by Jake Archibald talking about different strategies for both caching and serving assets. In our case, we are going to register the service worker as a progressive enhancement in the main app script. Then in the service worker script, we will declare the resources to cache and well, cache them. On a subsequent page reload, the service worker will step in and serve up the cached assets. Additionally, we can make the further step in our fetch event, we can request missing assets from the network if needs be.
Before looking at some code, let’s look at the service worker lifecycle in a bit more detail
A service worker has a lifecycle that is completely separate from your web page.
To install a service worker for your site, you need to register it, which you do in your page's JavaScript. Registering a service worker will cause the browser to start the service worker install step in the background.
We use eventhandlers to bind the install, activate and fetch events
During the install step, you'll want to cache some static assets. If all the files are cached successfully, then the service worker becomes installed. If any of the files fail to download and cache, then the install step will fail and the service worker won't activate (i.e. won't be installed). If that happens, don't worry, it'll try again next time. But that means if it does install, you know you've got those static assets in the cache.
At the activation step we handle management of old caches, which we'll cover during the service worker update section.
After the activation step, the service worker will control all pages that fall under its scope, though the page that registered the service worker for the first time won't be controlled until it's loaded again. Once a service worker is in control, it will be in one of two states: either the service worker will be terminated to save memory, or it will handle fetch and message events that occur when a network request or message is made from your page.
Only ever one service worker in control of a page at one time, if there is already an active service worker for a given page, a new service worker is queued in the waiting state. Once all instances of the current web app are closed, the old service worker is prepped for deletion and the new worker is activated.
A new service worker is required usually due to some update to the service worker script. We can force a service worker update through basic cache invalidation e.g. changing the name of our assets cache.
Downloaded at least every 24 hours
From project code:
Implementation in sw.js
sw.js can only have scope of files either in the immediate directory it is placed in or subdirectories. For this reason it is typical to place service at project root. It may be preferable in development to place the service worker, then at build time move it to project root
Discuss `filesToCache` array
Discuss event listeners
Register in js/app.js
Progressive enhancement
Can specify scope - this limits files service workers can access
I’m now going to demonstrate this behaviour in the browser
Service worker installation event
Refresh cache storage to show update cache
Service worker fetch
Service worker response
Showw offline
Application > Cache > Cache Storage > static cache name (specified in sw.js)
Application > Service workers > toggle “Update on reload”
Installing a new service worker - will automatically if service worker changed, e.g. versioning assets
We are using localstorage to store todos, and cache API for static assets
Browsers have hard limit as to how much disk space is made available to a given origin - should ensure that caches are frequently purged
A single origin can have multiple cache objects, collected under the CacheStorage API
As of Chrome 46, the Cache API will only store requests from secure origins, meaning those served over HTTPS.
More flexible than AppCache
Service workers have no persistent state - require indexedDB to support multiple service workers
LocalStorage does not support query language
Transactions good for dealing with problems that may arise from multiple instances across multiple tabs. Transactions are atomic.
Transaction scope is defined when it is initialised and fixed for the lifetime of the transaction. This to prevent possible overlap with multiple writes to the same object store. This is designed to prevent race conditions.
Include link tag in main HTML file
It is a best practice to place the manifest link on all your site’s pages, so it will be retrieved by Chrome right when the user first visits, no matter what page they land on.
Demo with GIF
DevTools: Toggle force upload in sources tab - force new service worker install event on cmd-r/ctrl-r
Use serviceworker-internals to debug failing installations
Available as CLI and chrome plugin - audits page to show presence of service worker, 200 status when offline, and other useful metrics
Service workers have been around since 2013
All these are still in progress
Achieve good performance even with full page reloads (server reloads) without javascript
Stream are a big deal in front end web development nowaday. Identity streams: stream resources in the background without requiring javascript
Navigation preload: quicker network response time, at same time as service worker boot up
Service-worker-navigation-preload header
Foreign fetch: dedupe third party requires via service worker
Background fetch: solve issues caused by background sync, higher visibility