PWA

The Bare Necessities: Progressive Web Apps in Ionic



·

You’ve probably heard of Progressive Web Applications by now, but if you haven’t then you may want to give this a read. In short, they are all about giving applications made available through the web a more native-like experience. This means at a minimum that they should work offline, and can be installed onto a user’s device.

This is a separate concept to a hybrid application, which you can also build with Ionic. A hybrid application consists of a web view embedded into an actual native application, the resulting package is no different to any other native application and as such, it is generally distributed through app stores. A Progressive Web App is not built as a native application or distributed through app stores, it is made available directly through the web – you visit the application through your normal browser, the application can be used there and then, and you can choose to install it directly to your device for easier access later.

There’s more to Progressive Web Apps (PWA) than adding a service worker to enable offline access and calling it a day, but this tutorial is not about covering best practices or considering the benefits of Progressive Web Apps.

What if all we’re interested in doing is taking the simplest possible route to make an application available as a PWA. What might our friend Baloo do if he were creating a PWA? I don’t think it’s a good idea to only be concerned with the bare necessities, but I do think it is a useful exercise to understand what those bare necessities are.

So, here’s what we want to do. Let’s tackle the bare necessities of PWAs with an example Ionic application. We will need to:

  • Make our Ionic application available on the web
  • Be able to access the application when offline
  • Be able to install it onto a user’s device where support for installing Progressive Web Apps is available

Before We Get Started

Last updated for Ionic 3.5.0

Before you go through this tutorial, you should have at least a basic understanding of Ionic concepts. You must also already have Ionic set up on your machine.

If you’re not familiar with Ionic already, I’d recommend reading my Ionic Beginners Guide or watching my beginners series first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic, then take a look at Building Mobile Apps with Ionic.

1. Generate a New Ionic Application

We’re going to just use a default starter template for this example, so you will just need to run:

ionic start bare-minimum-pwa

and choose a template. It doesn’t really matter which you choose, but I chose the sidemenu template for this example if you can’t make up your mind!

2. Add a Service Worker

Perhaps the most critical step in transforming your Ionic application into a PWA is to set up a service worker. A service worker is a script that runs separately to the application. It doesn’t have access to the DOM like a normal script would, but it can do things like handle network requests and caching.

We will make use of this caching to make the critical files for our Ionic application available when the user is offline. Service workers are also a complicated and powerful beast, but again, we are just channeling our inner Baloo and focusing on the bare necessities.

If using service workers to handle network requests and cache resources sounds difficult there’s no need to worry – Ionic handles it all for us. The code for the service worker is already included in your Ionic application, we just need to register it by uncommented some code.

Modify src/index.html to uncomment the following code:

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

With this code uncommented, the service worker in the service-worker.js file will be registered and it will start caching resources for us. If you take a look at the code for that service worker you will see this:

/**
 * 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;

Even without understanding it, you can probably tell that we are caching the following resources in this script:

    './build/main.js',
    './build/main.css',
    './build/polyfills.js',
    'index.html',
    'manifest.json'

We have our bundled main.js file which contains all of the application’s code, the main.css file which contains all of the styles for the application, we have some polyfills, the index.html (which is, of course, a key ingredient for any website), and a manifest.json file.

This is fine for the example application we are using, but if you do add more resources to your application that need to be available offline then you will need to include them here also.

3. Create the Manifest File

Let’s talk about that manifest.json file we just set up caching for. This is what will allow us to install the application where support is provided. The manifest file gives some instructions to the browser about the application, including the applications name, colours that you want to use, what file should be used to start the application, and more.

Here’s what the default file looks like:

{
  "name": "Ionic",
  "short_name": "Ionic",
  "start_url": "index.html",
  "display": "standalone",
  "icons": [{
    "src": "assets/imgs/logo.png",
    "sizes": "512x512",
    "type": "image/png"
  }],
  "background_color": "#4e8ef7",
  "theme_color": "#4e8ef7"
}

You can just modify this to suit your needs (if you want an application icon for your PWA you should make sure to create one at assets/imgs/logo.png). There are other options you can include in a manifest.json file, but again… bare necessities.

4. Build for the Browser

Now we need to create a production build for our application. Creating a production build for the browser isn’t really much different to what happens when you run ionic serve, but we do want to pass the --prod flag so that the build is minified. To do that, we can run the following command:

npm run ionic:build --prod

5. Upload It!

The last step is to upload it somewhere on the web! All you have to do is upload the contents of your www folder (not the folder itself) – which contains the built, bundled, and minified version of your application – somewhere accessible via a URL. Then just visit that URL to load the application. Once you have visited it for the first time, try closing it down completely, going offline, and accessing it again. Even if you haven’t installed it and are just accessing it through your browser, it should continue to load just fine.

Here’s one I uploaded earlier: Bare Necessities PWA

Summary

If you want to build an application that meets the minimum technical requirements of a Progressive Web App, then the steps above is all there is to it. If your application is available through the web, then there is no reason not to do this – it gives you some big wins for very little effort.

Progressive Web Apps do have a much broader scope, though. For a more specific definition of what the goals of PWAs are, you should take a look at this checklist made available by Google.

  • Will un-commenting service-worker code affect android/ios build?

  • Mark Dunn

    Worked great BUT how do I go back?

    When I comment out the service worker and go back to using ionic serve –lab, I get the below error…

    Uncaught (in promise): TypeError: Cannot read property ‘call’ of undefined TypeError: Cannot read property ‘call’ of undefined at __webpack_require__

  • Fabian

    Great first introduction into PWA’s!
    Maybe someone can give me a hint for a good push service for Desktop Notifications in a Ionic PWA and the iOS, android. I tried onesignal ionic nativ but its not working in desktop browsers.

  • a n onymous

    One issue I have come across when un-commenting the service worker code on my local development machine is that subsequent updates I make while editing a .ts or .html file in VS Code are not picked up by the browser (using Chrome). If you unregister the service worker – as described here: https://github.com/ionic-team/ionic-app-scripts/issues/363#issuecomment-297213949 – then updates display again. What are the implications of this for publishing the pwa to a web server? Are subsequent updates not going to be picked up by the end user?

    • In the Chrome Developer tools under ApplicationService worker you can tick “Update on Reload” – this helps a bit to not cache everything during dev

  • a n onymous

    Seems very strange that the –prod flag does not enable Angular itself to be in prod mode?
    There is an ionic forum post about the issue here:
    https://forum.ionicframework.com/t/enableprodmode-question/54896/15

  • Should it be expected that the web build still tries to load cordova.js? The 404 error is harmless, but noise.

    • I just manually remove the cordova.js tag for my PWA builds

      • You may want to there. That’s just me though – I see an error in console and I twitch. 😉 Surprised the Ionic CLI doesn’t handle this for you though.

      • The same goes for the Vendor.js file it seems