Progressive Web App

My Experience Building a Progressive Web App (PWA)

Web apps are not new, but there is a new term Progressive Web App (PWA) introduced by Google. What is it exactly? I got a taste of how it feels like developing one during CS3216 Assignment 3.

Progressive Web App – What’s New?

According to Google, Progressive Web App is a subset of web applications that has the following characteristics (or standards):

  • Progressive – Work for every user, regardless of browser choice because they’re built with progressive enhancement as a core tenet.

  • Responsive – Fit any form factor: desktop, mobile, tablet, or whatever is next.

  • Connectivity independent – Enhanced with service workers to work offline or on low quality networks.

  • App-like – Feel like an app to the user with app-style interactions and navigation because they’re built on the app shell model.

  • Fresh – Always up-to-date thanks to the service worker update process.

  • Safe – Served via HTTPS to prevent snooping and ensure content hasn’t been tampered with.

  • Discoverable – Are identifiable as “applications” thanks to W3C manifests and service worker registration scope allowing search engines to find them.

  • Re-engageable – Make re-engagement easy through features like push notifications.

  • Installable – Allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.

  • Linkable – Easily share via URL and not require complex installation.

Some characteristics are not entirely new. For example, Responsive and Safe are already adopted by lots of web applications. App-like is also a relatively old concept, given the popularity of frameworks such as Ionic that makes web applications more native-like.

However, some of them do rely heavily on cutting-edge technologies or specifications. For example,  Fresh and Installable requires the use of service worker and application manifest, whereas Re-engageable requires push notifications. This opens up new doors but also means there will be compatibility issues at the same time as we drop supports for old browser.

Building a Progressive Web App

With the help of guides from Google and Mozilla, we were on our way to building our cool progressive web app. The principles are always easy to describe, but implementation is whole different story.

Online or Offline?

I was expecting a simple browser API that could tell me if the client is online or offline. Indeed, there was one,  navigator.onLine , except it is not so inconsistently across browsers and platforms. We did not want to resort to using Ajax or external libraries to do this as it seems to be an overkill for such a trivial task. So we did our own testing to see how bad navigator.onLine is.

It turned out to be usable for our project. We tested it across Windows, Mac, Android and iOS, with Chrome and Firefox. Only Windows seem to give the inconsistent results, that is returning true when there is no Internet connection.

We considered ourselves lucky as the simple solution meets our need, since we are mainly targeting mobile users. Nonetheless this demonstrates a deeper issue with web specifications that are browser and platform dependent. You may have a cool feature that works well on Chrome but does nothing on Firefox, and that is painful for web developers in general.

Offline Usage – Service worker & Client-side Storage

For offline usage of the app, we need two parts:

  • Service worker for caching app logic and static resources such as css and images, and
  • Client-side storage for caching user-specific data, which is dynamic, and has to be synchronized with the server.

Service worker is very powerful. It caches the entire app and runs in the browser as a proxy between the client and the server. However, there are problems that makes it less than ideal in its current form.

Firstly, service worker can only cache assets on the app’s domain, but not from external domains. This makes it hard to use it together with a CDN or external cloud services such as Google Maps API. And our app happens to be the second case.

The rendering of the map, the overlays and the markers depends on the Google Maps API, and Google does not provide a standalone JS file. Hence we are left with very few choices for offline functionalities. In the end, we resort to caching still images from Google Static Maps API and saving them on the client side for offline viewing. This is obviously less ideal than the full interactive Google Map.

Secondly, service worker requires explicit declaration of all assets. Want to add a new image? Add it to sw.js. Want to add a css file? Add it to sw.js. It just seems too tedious and it makes you wonder why they do not allow some kind of patterns for adding files into the cache. There are tools for automating such tasks, but they were never mentioned in the official guides so we only discovered them later from a friend after the hard work.

Compared to service worker, the client-side storage is less of a hassle. We managed to find a nice library called localForage, which served as a high level wrapper for interacting with various client-side storage technologies such as IndexedDB, WebSQL and localStorage. It has a simple API interface with a key-value paired storage. With the help of localForage, we could storage and retrieve user data within the browser without worrying about browser compatibility issues.

Getting the Native-look with Ionic

One of the characteristics for PWA is native-like UI and installable like a native app. We thought using a framework like Ionic would solve it for us, but it was not so simple.

Ionic looks easy to use at first, especially considering that we are using Angular.js, on which Ionic is built. However, as we began developing the app, issues keep coming out.

Compatibility issues with Angular.js – For example, Ionic’s tabs builds on top of AngularUI Router’s concept of states but do not directly correspond to them. Switching tabs in Ionic does trigger switch of states, but switching of states with additional parameters creates new instances of tabs in Ionic instead of restoring the existing tab. This caused huge problems for our app. We need a way to switch tabs based on user’s selection, not creating new instances of tabs with empty contents. In the end, we had to use a hackish way of passing parameters via rootScope instead of switching states directly.

Half-baked UI components – A lot of Ionic’s UI components look nice in the demo but lacks flexibility and scalability. The demo shows the use case of one button, but the UI messes up when there are more than one button. Also, basic features such as “closing popup upon clicking on backdrop” is not available. There are also cases where the default CSS is not enough to style the UI components as shown on the demo page. In other words, the default CSS shipped with release version of Ionic is basically incomplete. You have to use nightly version or write additional CSS just to achieve the demoed effects.

I suspect a lot of these issues happen because they are shifting their focus to their new release Ionic 2 and no longer actively developing for Ionic 1. Hopefully with the release of Ionic 2, which has built-in support for PWA, it would be on the right track to the future of web applications.

Final Thoughts

With Progressive Web App, there are cool things that you can do with new technologies. However, expect issues with immaturity of the entire PWA technology stack.

With that said, I do believe in the future of PWA. Tech companies like Google, Facebook are actively adopting new standards and developing tools and frameworks. This means developers can enjoy a simpler and more pleasant experience as PWA becomes more mature and common.

Cover photo from

One comment

Leave a Reply