Publishing an Ionic Progressive Web App - part 3

March 5, 2018, 8:00 am Categories:

Categories

In part 1 of this tutorial series we used the Ionic Pro Backend as a Service (BaaS) platform to generate a new Ionic project.

In part 2 of this tutorial series we then used this Ionic project to develop a realtime chat application with the Socket.io library and node.

In this final tutorial of our three-part series we're going to convert this realtime chat application into a Progressive Web App (PWA), publish that to a remote server and then test the PWA using the Google Chrome Lighthouse plugin.

The Lighthouse plugin uses a scoring guide to rate PWA's across the following auditable areas:

  • Performance
  • Progressive Web App
  • Accessibility
  • Best Practices
  • SEO

These audits are based on the Google Baseline Progressive Web App Checklist.

In case you need a reminder here's the existing application that we'll be converting and publishing as a PWA:

Realtime chat application built with Ionic and Socket.io

Fortunately Ionic projects come with built-in PWA support so most of the work has already been done for us thanks to the inclusion of the following elements:

  • Viewport meta tag
  • iOS specific meta tags
  • Web manifest
  • Service worker

That said we will need to make some adjustments though so let's go through each of the above, as well as other requirements we need to implement and satisfy, in more depth so that we can take this knowledge into other Ionic (and non-Ionic) projects where Progressive Web Apps might be required.

Viewport meta tag

The Viewport meta tag, introduced by Apple with iOS, allows developers to control the size and scaling of the browser viewport (the area within which web content can be seen) allowing web pages to be rendered for mobile viewing in a more user friendly way.

By default Ionic applications generate the following viewport meta tag within the src/index.html file:

<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

Unfortunately, at the time of writing, there is no agreed web standard for the viewport meta tag which results in the above content declaration generating the following error when published as a PWA and tested with the Google Chrome Lighthouse plugin:

Invalid properties found: {"viewport-fit":"cover"}

 Although this isn't a "dealbreaker" (as our application will continue to perform regardless) we can change this default generated viewport meta tag for the ionic-communicata/src/index.html page from the above example to the following instead:

<meta name="viewport" content="width=device-width, initial-scale=1">

In all fairness you can ignore this step if you want to as it's solely there to satisfy the Lighthouse PWA audit.

iOS specific meta tags

You might already have noticed that the default src/index.html file for all automatically generated Ionic projects has the following Apple specific meta tags:

<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">

The first meta tag allows a web application to run in full screen mode while the second meta tag (which can only be used IF the first meta tag is set to a value of yes) sets the style for the status bar of a web application.

The content attribute for the apple-mobile-web-app-status-bar-style meta tag can be set to any of the following values:

  • black - status bar is set to black with web content displayed underneath this
  • default - status bar is set to normal with web content displayed underneath this
  • black-translucent - web content is displayed on the entire screen and is partly obscured by the status bar

Simply keep this as the default value of black.

No Cordova required

As we're not publishing our codebase for iOS and/or Android we can simply remove (or comment out - as demonstrated in the following snippet) the default generated <script> tag for importing the cordova.js file:

<!-- cordova.js required for cordova apps (remove if not needed) -->
<!--script src="cordova.js"></script-->

Only keep this tag inside the src/index.html file when you are developing Ionic Native/Apache Cordova applications that will be deployed to iOS and/or Android.

When it comes to publishing PWAs however we can safely remove this from the index.html file.

Web App Manifest

Progressive Web Apps are able to be installed to a user's home page courtesy of details provided by the application's Web App Manifest. This is simply a JSON text file which contains information about the application including - but not limited to:

  • name - The name of the web application
  • short_name - A shortened version of the name of the web application (used when there is insufficient space to display the full name of the application
  • start_url - The URL loaded by the shortcut displayed on the user's device for the web application
  • display - How the application should be displayed (Options are: Standalone, Full Screen, Minimal UI and Browser)
  • icons - The icon associated with the web app that is displayed as a shortcut on the user's homescreen
  • background_color - Background colour for the application (until the stylesheets have fully loaded)
  • theme_color - Colour used by the browser and system UI when displaying the web application

The default generated Web App Manifest for an Ionic project is located in the src/manifest.json file and contains the following information about the application:

{
  "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"
}

In and of itself this default manifest.json file would be sufficient for developing a PWA but we're going to expand upon this by adding some further icon sizes and the following additional fields:

  • orientation - The display mode for the application (options include any, landscape, landscape-primary, landscape-secondary, landscape, natural, portrait, portrait-primary, portrait-secondary)
  • splash_pages - Used to display a splash screen for launching the application (available for use in Chrome 47 and later)

We could add these fields/values manually but the following tools are available for developers to use when configuring their Web App Manifest files:

We'll use the Web App Manifest Generator - particularly as this will help to generate a more complete icon set for the ionic-communicata PWA.

To generate this icon set simply upload a 512 x 512 pixel image that represents the application and the service will generate a downloadable zip file containing the different sized image icons (be sure to drop these into the src/assets/imgs/ directory)

After using this tool we end up with a src/manifest.json file that resembles the following instead:

{
  "name": "Communicata",
  "short_name": "Communicata",
  "description": "A realtime chat application built with Ionic and Socket.io",
  "start_url": "index.html",
  "display": "standalone",
  "icons": [
    {
      "src": "assets/imgs/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "assets/imgs/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "splash_pages": null,
  "orientation": "portrait",
  "background_color": "#2196f3",
  "theme_color": "#2196f3"
}

Service Worker

Along with the Web App Manifest the Servicer Worker API is a critical ingredient in developing and publishing Progressive Web Apps.

A Service Worker simply acts as a proxy server that sits between your web application, the browser and the network (if available) and has the following characteristics and functions:

  • Non-blocking as it runs on a different thread to the JavaScript that powers your web application
  • Runs in its own worker context and has no access to the DOM
  • Works only across HTTPS for security reasons
  • Designed to be fully asynchronous (this means that API's such as localStorage and synchronous XHR are NOT able to be used within a Service Worker context)
  • Intercepts network requests to determine if network is available
  • Allows caching of application resources

By default Ionic applications come pre-built with a src/service-worker.js file included along with a <script> block within the src/index.html file to enable this service-worker.js file to be registered and installed.

To enable this simply uncomment the <script> block as demonstrated in the example below:

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

Now the service worker is available for use with the ionic-communicata PWA and our assets, once remotely retrieved and available, are then able to be cached should the application go offline.

Graceful degradation

When developing our PWAs with Ionic we also need to consider the possibility that some users might not have JavaScript enabled for their web browser for a number of reasons (security, accessibility, low system resource consumption etc).

With this in mind it's important therefore that we design our applications to provide non-JavaScript fallbacks where and IF possible.

Otherwise we simply inform the user that JavaScript needs to be enabled for the PWA with the following code:

<noscript>
    <p>JavaScript needs to be enabled to use this application.</p>
</noscript>

Offline handling

We can't always assume that network availability will be present when the user launches our installed PWA so it's important that we provide a means of handling how the application behaves should the browser/mobile device be offline.

In the previous tutorial we added the following method to the ionic-communicata/src/providers/sockets/sockets.ts service to initiate a HTTP request to the remote server whether the chat application was running:

/**
  * @public
  * @method pollServer
  * @description    			Use Angular Http call to determine if server address is reachable
  * @return {Observable}
  */
pollServer() : Observable<any>
{
   return this._HTTP
              .get(this._SERVER);
}

This was then used within the HomePage component for the ionic-communicata application to handle network detection as follows:

/**
 * @public
 * @method ionViewDidLoad
 * @description    	On view loaded detect whether the network is able to be accessed	
 * @return {none}
 */
ionViewDidLoad() : void
{
   this.detectNetworkConnection(); 
}




/**
 * @public
 * @method detectNetworkConnection
 * @description    	Detects whether the chat server can be contacted			
 * @return {none}
 */
detectNetworkConnection() : void
{
   this._SOCKET
   .pollServer()
   .toPromise()
   .then((data : any) =>
   {
      this.displayMessages();
   })
   .catch((error) =>
   {
      this.displayNetworkErrorWarning();
   }); 
}




/**
 * @public
 * @method displayNetworkErrorWarning
 * @description    	Displays an alert window informing the user that network connectivity
 * 					cannot be detected		
 * @return {none}
 */
displayNetworkErrorWarning() : void
{
   let alert : any = this._ALERT.create({
       title 	    	: 'Network error',
       subTitle     	: 'Please check your network connection and try again',
       buttons 	    : [
          {
             text 	: 'Retry',
             handler 	: (data) =>
             {
                this.detectNetworkConnection();                  
             }
          }]
   });
   alert.present();
}

With this we logic in place we have the means of informing the user that the PWA needs to be online in order to be used.

Now we can generate our PWA build.

Generating a PWA build

Within the root of the ionic-communicata project we can generate a production build for our Progressive Web App using the following CLI command:

npm run ionic:build --prod

This will then, assuming no build errors are detected, build the application within the ionic-communicata/src/www directory (similar to what happens when we run the ionic serve command to run our applications in the browser).

Now we can publish the www directory (which contains our PWA build files) to a remote server for hosting.

The team at Ionic recommend using Firebase hosting so this is what we'll focus on (although any privately hosted/remote host/Content Delivery Network would suffice for hosting our PWA files).

Firebase hosting

Firebase hosting provides the following benefits for Ionic developers looking to host their PWAs:

  • SSL certificate enabled by default (no complicated set-up process required)
  • 1GB storage (with free developer plan)
  • 10GB data transfer monthly allowance (with free developer plan)
  • Custom domain
  • Simply deployment process

It's important to note at this point that you can use Firebase Hosting WITHOUT having to use any of the other services provided by this BaaS - although you WILL need to create a new project (or select an existing one) to enable Firebase Hosting.

To do this go to the web browser, log into the Firebase console, create a new/select an existing project and, on the project overview screen, select Firebase Hosting:

Firebase project overview screen

From the default view for the Firebase Hosting dashboard simply click on the Get Started button:

Firebase hosting service dashboard

We then follow the Set up hosting wizard which guides us through the steps necessary to configure and enable Firebase Hosting for the selected project:

Firebase set up hosting wizard

If you haven't already done so outside of this tutorial follow the Set up hosting wizard instructions and globally install the Firebase CLI to your desktop machine with the following command:

npm install -g firebase-tools

If you should encounter permission errors on a Unix based system you might need to prefix the above command with sudo.

The final screen of the Set up hosting wizard simply provides the CLI commands that we'll need to use to publish our Ionic PWA production build to the Firebase Hosting service:

Final screen of the Firebase set up hosting wizard

Return back to the command line and, with the Firebase CLI now installed, log into your firebase account like so:

firebase login

From within the root of the ionic-communicata project directory issue the following command to initiate a Firebase project:

firebase init

This will launch an interactive wizard which allows you to initialise a Firebase project within the ionic-communicata directory via the following prompts:

  • The Firebase CLI features to set up for the project - select Hosting (as shown in the below screen capture)
  • The default Firebase project for the directory - select the project you enabled the Firebase Hosting service for earlier in this section (as shown in the second screen capture)

Firebase CLI wizard for generating project hosting

Firebase CLI wizard for selecting project for hosting to be assigned to

Once the project has been selected the Firebase CLI will then ask the following questions (the answers you need to provide are included in bold):

  • What do you want to use as your public directory? www
  • Configure as a single-page app (rewrite all urls to /index.html)? Yes
  • File www/index.html already exists. Overwrite? No
=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? www
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? File www/index.html already exists. Overwrite? No
i  Skipping write of www/index.html

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

With the firebase init command completed the following JSON files have been generated in the root of the ionic-communicata project directory:

  • firebase.json (provides information on which Ionic project directories the Firebase Hosting service will use/ignore)
  • .firebaserc (lists the project that the Firebase Hosting service has been initialised for)

With these in place the Firebase CLI now "knows" which service to utilise, the remote project to communicate with and what data needs to be transferred.

As we have already generated our PWA production build we can simply upload this to Firebase Hosting with the following command:

firebase deploy

Which triggers output akin to the following:

=== Deploying to 'fir-comm-d000a'...

i  deploying hosting
i  hosting: preparing www directory for upload...
✔  hosting: 43 files uploaded successfully

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/fir-comm-d000a/overview
Hosting URL: https://fir-comm-d000a.firebaseapp.com

Notice that the firebase deploy command has also provided the hosting url for your PWA?

Copy this somewhere safe for later reference.

The PWA production build code has now been deployed to the Firebase Hosting service for the selected Firebase Project like so (as you can see from the following there have been a number of deployments for further code fixes and enhancements - as is often the case when testing developed code remotely):

List of current and previous deployments to Firebase Hosting

Now you can install the PWA on your mobile device by opening the device browser and navigating to the Firebase Hosting URL that was returned by the firebase deploy command!

FYI: The team at Ionic are working on offering a PWA hosting service through Ionic Pro so expect some announcements on that front shortly.

Auditing an Ionic PWA

With our PWA production build securely hosted on Firebase we can test how the application performs using the Google Chrome Lighthouse plugin.

Within the Google Chrome browser simply navigate to the Firebase Hosting URL for the PWA, open the Developer Tools, click onto the Audits tab and make the following selections:

Selecting the Lighthouse PWA audit in Google Chrome Developer tools

Click on the Run audit button which will then run each selected audit accordingly:

Lighthouse Audit running in Google Chrome Developer Tools

Once completed your PWA audit scores will then be displayed by ranking for the following criteria:

  • Progressive Web App
  • Performance
  • Accessibility
  • Best Practices

Any errors, warnings or issues encountered during the audit will also be displayed within this report:

Lighthouse PWA score report

In Summary

Publishing an Ionic PWA is relatively simple and straightforward as most of the work has already been done for you with the code that's included in each default generated Ionic project - all you need to do is make a few tweaks in selected parts (as covered in the above tutorial).

Hosting a production ready PWA can be handled by any hosting service with an SSL certificate enabled for the domain - this is why Firebase Hosting is such a great choice (amongst other features that it offers).

As you've no doubt realised from this tutorial publishing a PWA is MUCH simpler than publishing a mobile app (as there are no additional hoops to jump through such as code signing, App Store submission etc).

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore different aspects of working with the Ionic framework in my e-book featured below and if you're interested in learning more about further articles and e-books that I'm writing please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top