loading...
Cover image for Create a never offline web app!

Create a never offline web app!

paco_ita profile image Francesco Leardini Updated on ・4 min read

Welcome to the fifth article about progressive web apps. πŸ™‹
If you read from the first post of this series, you should have now a solid base, even if PWAs were completely unknown.
Terms like service workers, web app manifest, cache API should be familiar to you. In the previous articles we discovered different tools we can use to easily build a PWA from scratch. Therefore probably you already started upgrading your existing web application with the learnt progressive features.

This is already a step forward for offering an improved experience to our users. However there is something else we can do to further leverage progressive web apps capabilities and bring them to a next level. I will show you that nowadays, with modern technologies, we can provide a never offline application to our users.

So grab a coffee, make yourself comfortable and let's start!!

start
Β 

Limits of the Cache API

We previously learnt that the Cache API allows to cache only GET Requests, but no POST nor PUT are currently possible.
If you try to cache a request other than a GET you will receive the following error: TypeError: Invalid request method POST. (here in case we submitted a POST).

So our web app still works offline, it allows to navigate and read content from it, but it offers just a passive experience. Even though this is perfectly fine in many scenarios, it would be great if we could offer full CRUD (Create, Read, Update, Delete) functions even offline.

To achieve this, it is necessary to develop custom solutions to overcome to this limitation. For example we can detect when the client is offline and, in that case, store in the Indexed DB the values the user inputted in forms and attempted to post to the server.
Then, when the user's network connectivity is restored, our app must push all the pending changes. We have also to plan how to handle exceptions if a POST fails and how this should affect the other cached requests.

Another possibility is given by Cloud Firestore.
Β 

Cloud Firestore

firestore-logo

Cloud Firestore is a flexible, scalable NoSQL database for mobile, web, and server development from Firebase and Google Cloud Platform. It keeps your data in sync across client apps through realtime listeners and offers offline support for mobile and web so you can build responsive apps that work regardless of network latency or Internet connectivity.

structure
Data in Firestore database is saved as json objects (key:value structure) called Documents and contained in Collections. This organisation makes it easier to design domain objects (persisted in the database) in a fashion similar to our web app DTOs.

Firebase platform also proposes a generous free tier:

free-tier

So we can use it for our personal projects or demos without any worries about initial costs.

I will reserve a separate article to describe more in detail the Firebase platform and other Cloud Firestore features. Here we concentrate on its offline persistence functionality.
Β 

Offline persistence

Offline storage is enabled by default for mobile development, but not for the web. We have to activate it explicitly by calling the enablePersistence method:

// Register Firebase Keys
firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###',
} ,"myDemoApp");


// Enable offline support
firebase.firestore().enablePersistence()
  .catch(function(err) {
      if (err.code == 'unimplemented') {
          // The current browser does not support all of the
          // features required to enable persistence
      }
  });
});

From this moment any document received from the server is stored locally in an Indexed DB. Now we can read, edit or delete any cached document, even without a network connection. If the cache does not contain the requested document, an error is returned.
All pending local changes are then automatically synchronised with the DB on the server as soon as the user comes back online.

Let's image we are travelling by train with a discontinue network connection, continuously turning offline and online. Sound familiar, doesn't it?

offline

Nevertheless our application would still be accessible and even allow to modify its content (as long as we have the requested documents in the cache). We designed a PWA behaving seamlessly while online or offline.

We can analyse the cached data within the "Application" Tab in DevTools (if using Chrome):

cached-data

By default the cache limit is 40MB. After exceeding this quota, Firestore attempts to clean up old documents until the cache size returns under the limit set. It is possible to specify a different threshold (the minimum value must be 1MB) or disable the eviction process entirely:

firebase.firestore().settings({
  cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED
});

Β 

Firestore limitations

Before deciding to use Firestore in our application though, we have to be aware of some limitations:

  • Limit of pending changes is set to 500.
    Google engineers explicitly designed such a limit, as the offline persistence is meant to cover temporary connection discontinuity and not to be used for a long time.

  • Concurrent updates policy is "last write wins".
    If there are multiple updates against the same document on the database, the last write arriving to the server will be saved. This might lead to potentially save older data if this comes from a client that was offline and is now synchronising its pending changes.
    Β 

At this point the choice is yours. It is not always necessary to offer edit functionality while offline, it depends on your business requirements. If you decide to go for it, then either you develop a full custom solution or opt for Firestore. I found the latter choice giving a lot of benefits out of the box with a very little effort.

In this post we saw how to further improve our PWA and I hope to have been able to convince you that nowadays it is possible to implement web applications that are potentially never offline!
Β 
bye

Β 
You can follow me on:
Β 
follow-me-twitter
Β 

Posted on by:

paco_ita profile

Francesco Leardini

@paco_ita

Software Engineer βˆ™ International speaker βˆ™ Focusing on Javascript, Angular, React and PWAs

Discussion

markdown guide
 

Hi! I have been trying to find how I can check whether a document 'create', 'update' or 'delete' happened on the cache when the device is offline.

The official documentation for AngularFire and Firestore only talks about ways to check whether you're receiving data from the server or the cache.

 

Hi Aritra.

Have a look here: firebase.google.com/docs/firestore...

You can use addSnapshotListener for your requirement:
"Local writes in your app will invoke snapshot listeners immediately. This is because of an important feature called "latency compensation." When you perform a write, your listeners will be notified with the new data before the data is sent to the backend."

 

Thanks a lot! This is exactly what I was looking for. πŸ™‚