Last update on Saturday, January 12th 2019

Creating an Ionic PWA with Firebase Offline and Service Workers

Progressive Web Apps or PWA are rising.
As the name suggests, they are web applications. The only difference is the progressive aspect.
This word represents what we have been doing for years. We could have stayed at the Web 1.0 with static websites and funky blinking links, but thank god we didn't.
The web evolved with client-server communications, serverless architectures and more is coming.
Progressive web apps are quite hard to define because they evolve with time.
Google's definition is quite complete, identifying a PWA as an application that can be used offline, installed directly from the web, responsive, etc.
Five years from now, this might change and a PWA might become a web application with new features like Virtual Reality or Augmented Reality.
It might seem frightening to know that most of what we learn today might not serve tomorrow with new frameworks (Angular 45, Ionic 39, React 900, etc) but that's the reality and also why we generally get paid a lot of money.

In this tutorial we are going to see one aspect of a current PWA: the offline support.

In my opinion, this is one of the most important features for a progressive web app.
From previous projects, this feature was always on the todo list. Allowing people to keep using a web app if they lose their internet connection.

Our first PWA will use:

  1. A Service Worker to cache the web page's logic. A Service Worker is similar to a Web Worker, it will silently do the work in the background. In our case, it will cache the data received from the server. If an atomic bomb falls on your remote servers, your minified JavaScript files will stay on the user's computer and it won't matter (PWA for the win!)
  2. Firebase to handle the database synchronization
  3. The Firebase offline plugin to keep the data consistent once the disconnection happens

The TODO-firebase Ionic app from this previous tutorial will be used as a base (you should check it because it contains Firebase's configuration). You can grab the code there.

Only one additional plugin is required. In the terminal:

npm install angularfire2-offline --save

And the app.module.ts file:

...

import { AngularFireModule } from 'angularfire2';
import { AngularFireOfflineModule } from 'angularfire2-offline';
import { AngularFireDatabaseModule } from 'angularfire2/database';

@NgModule({
  ...
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireDatabaseModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireOfflineModule
  ]
})
export class AppModule {}

Offline Web Application

We can now activate our Service Worker in the index.html by uncommenting those lines:

  <!--un-comment this code to enable service worker-->
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('service-worker.js')
        .then(() => console.log('service worker installed'))
        .catch(err => console.error('Error', err));
    }
  </script>

If the navigator supports the Service Worker feature, we register the service-worker.js file as a Service Worker.

Here is the content of our Service Worker:

/**
 * Check out https://googlechrome.github.io/sw-toolbox/ for
 * more info on how to use sw-toolbox to custom configure your service worker.
 */

"use strict";
importScripts("./build/sw-toolbox.js");

self.toolbox.options.cache = {
  name: "ionic-cache"
};

// pre-cache our key assets
self.toolbox.precache([
  "./build/main.js",
  "./build/main.css",
  "./build/polyfills.js",
  "index.html",
  "manifest.json"
]);

// dynamically cache any other local assets
self.toolbox.router.any("/*", self.toolbox.cacheFirst);

// for any other requests go to the network, cache,
// and then only use that cached resource if your user goes offline
self.toolbox.router.default = self.toolbox.networkFirst;

We use Google's sw-toolbox library.
This toolbox contains properties and methods specific to Service Workers patterns. Just like classic design patterns, Service Workers have their own patterns. Here are two bad examples:

  1. Don't cache anything and always ask for the files
  2. Cache everything. Every requests will always give the same results even if the data have been modified by somebody else

Our service-worker.js already has a very good pattern, it's been created by the Ionic (or Angular) team.

Firstly, a name is given to a cache.
The key files will be pre-cached, they are all located in the "www" folder:

ionic PWA firebase offline service worker

The last two lines focus on the access pattern:

// dynamically cache any other local assets
self.toolbox.router.any("/*", self.toolbox.cacheFirst);

// for any other requests go to the network, cache,
// and then only use that cached resource if your user goes offline
self.toolbox.router.default = self.toolbox.networkFirst;

By default the network is preferred.
If the network is down or a local asset is required, the cache will be used first.

And ... that's it.

Thanks to Google's technology creating an offline application is very easy!

Let's handle the Firebase section now.

Offline Database

The previous project used AngularFire Services to handle the data sync.
However, this library is not yet ready for offline usage which is crucial for our progressive web apps.

We already installed the Firebase offline library, all we need to do now is using it in the home.ts file:

import {
  AfoListObservable,
  AngularFireOfflineDatabase } from 'angularfire2-offline/database';
...

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  tasks: AfoListObservable<any[]>;
  newTask = {name: ''};

  constructor(afoDatabase: AngularFireOfflineDatabase) {
    this.tasks= afoDatabase.list('/tasks');
  }
  ...
}

Our tasks are now AfoListObservable and the AngularFireOfflineDatabase Service is injected then used to access the list of tasks located on Firebase.

That's it!

All the methods we created in the previous tutorial stay the same, no need to modify them.

The final step: hosting the PWA on Firebase.

We build our Ionic application:

ionic build --prod

This command generates production-ready files in the "www" folder.

The firebase commands now:

firebase login
firebase init

Once logged in, the init command will create some important files.
We need to show Firebase where the files are located, this is done in the firebase.json file:

{
  "hosting": {
    "public": "www"
  }
}

Finally we deploy the files:

firebase deploy --only hosting

ionic PWA firebase offline service worker deploy

Unlike other web applications, our app is still available for offline use alongside Firebase’s data which are propagated to other users once we are back online:

ionic PWA firebase offline service worker result

Conclusion

Progressive Web Apps (PWA) are top-notch web applications implementing many useful features.
We have seen in this tutorial how to implement the offline functionality.
Offline applications rely on Service Workers, they are easy to implement thanks to Google’s sw-toolbox library, instead of writing every instructions by hand, we tell the toolbox where the files are and which pattern should be used.
By coupling Service Workers with the Firebase offline library we can create an application that will record our disconnected users’ progress and update the database once they are back online.

Adding Twitter Authentication with Firebase in Ionic

Learn how to mix
the Twitter OAut...
...

Using Ionic With Capacitor in One Go

Learn how to use
Capacitor plugin...
...

Understanding the Manifest of an Ionic PWA in One Go

Learn how to
configure your Io...
...

Stay up to date


Join over 4000 other developers who already receive my tutorials and their source code out of the oven with other free JavaScript courses and an Angular cheatsheet!
Designed by Jaqsdesign