It is the second part of the series about making your ember app more mobile-friendly. The first part was about adding Home Screen icons, Splashscreen, and controlling app shell display on mobile devices. This time, I want to write more about offline assets caching.
Offline caching - quick recap
Some offline caching techniques are available for many years. There is a standard browser cache, but this mechanism cannot be reliable as a browser can throw our cache out at any point in time. There is also an ApplicationCache interface to tackle this problem, but it is obsolete now, and you had to mind many gotchas along the way of using it. Fortunately, there is a new way that utilizes service workers to achieve the same goal.
What is a service worker?
In a nutshell, a service worker is a JavaScript script that runs in a separate thread in the browser. There is a standardized API designed to allow communication between your web application and its service workers. I strongly encourage you to look up for more information about this concept. Here are a few things you could achieve using those scripts:
- offline caching
- background syncing
- push notifications
- geo-fencing (I’d love to make a post about it in the future)
In this particular post, I’m writing about the first case, but stay tuned to my blog, the moar stuff about service workers is coming ;).
So, back to offline support, compared to the mentioned ApplicationCache, Service Worker API is way more complicated, but also way more powerful. The main difference is the flexibility that is given to us, we can programmatically control which assets and how will be cached.
How to use Service worker with Cache API
Before I go any further, it is worth mentioning that your application must be served over HTTPS. This is a requirement for service workers to work :).
I will shuffle with some code so you can get a general idea.
Register service worker
First, you have to register the script.
Service worker lifecycle
Service workers have two lifecycle events you can attach to: install, activate , and another fetch event that we will be using to serve cached assets.
Add things to cache
Part of the Service Worker API is a Cache Interface which provides a storage mechanism for your assets. You are responsible for handling cache updates/purge/etc.
Here is a simple example of how we could use the install event to cache assets.
Fetch things from cache
As we have something cached, we would like to use it somehow when the user visits
our application subsequent time. FetchEvent is dedicated to doing that. You can modify
the response to requests in any way you want using respondWith
method, so it’s
basically a proxy to all requests.
What about updates?
What if your service worker script changes? Simply, the new version of the service worker is installed in the background, but it could be not active yet. It is only activated when there are no longer any pages loaded that are still using the old version. That’s why it is a good practice to use a different cache store for the new version, let’s say “v2”. You should get rid of the old cache in “activate” lifecycle event when the new service worker takes control.
Some helpers
The Above examples were framework agnostic and should give you some basic understanding of the whole idea.
And what’s more, there are some tools to simplify the process like sw-toolbox which provides caching
strategies, and sw-precache util to generate service-worker.js
that precaches resources for you.
How to start offline caching in Ember.js app
You may think, finally some Ember stuff but I feel compelled to make the above introduction. Anyway, as in [the first post][first-part] I will be using SplittyPie application as an example.
Broccoli Service Worker
There is a great service worker generator which will ease our process a lot.
What this does is generate service-worker.js
and add service worker register code to your index.html
.
It uses the mentioned sw-toolbox library which helps with various caching strategies.
In order to enable this addon, add some configuration into app/config/environment.js
file.
By default, it will add all Ember app resources (files in dist
folder) as precached assets using
cache first strategy. Available cache strategies are described here.
In many applications, that could be the last step, although I had to make some further adjustments.
I’m using google fonts fetched directly from google CDNs and “history” location type.
See my current setup below.
I’m using a different preloader page for other than index page requests (app.html just showing “Loading Splittypie…”), that’s why the need of pre-cache this page and fallback if a user is offline. Additionally, you can see caching Google fonts using the “fastest strategy”. About cache strategies, you can read on sw-toolbox documentation.
Also, I’m not using the default registration code (includeRegistration: false
), instead, I wanted to
have more control over the registration process to inform users about offline capability and
application updates. My offline-support
initializer below.
What’s next?
Unfortunately, my SplittyPie still doesn’t work without internet connection as I’m using firebase as a data layer. That’s why the next part is going to be about offline data access and synchronization.