SPA Series: Turn our ShowTitle app into a Progressive Web App

In this post we turn our great web app into a Progressive Web App (PWA). "A progressive web app provides an app-like user experience that is low friction and is built using modern web capabilities and hosted on the web and can become an app on the user's system over time." To learn more about the great promises of Progressive Web Apps read Addy Osmani's great overview article Getting started with Progressive Web Apps. Google also has a great entry point to the required information at https://developers.google.com/web/progressive-web-apps/.

Getting up to speed with Progressive Web Apps

Progressive Web Apps are cool, and in my opinion the future of a whole category of mobile apps. An inspiring introduction to this vision is this presentation by Bruce Lawson. See also https://dev.opera.com/blog/pwa-taipei/. For a great overview of other material available on Progressive Web Apps have a look at https://github.com/hemanth/awesome-pwa.

What do I want to achieve in this blog post

In this article we explore how to get the following functionality working in our PWA:

  • Hosting in a SharePoint document library - for authentication, access to data within your company, and freedom of distribution
  • Add to homescreen - so we get an icon between the other apps on your mobile device or between the apps in your browser
  • Splash screen - for direct visual feedback on start of our application
  • Offline support - so we can use our app even if we are not connected to the network

The code for our sample Progressive Web App can be found at https://github.com/svdoever/sharepoint-progressive-web-apps/tree/master/ShowTitleProgressiveWebApp.

Generating artifacts

For the PWA we need things like a favicon, icons for the different (mobile) platforms, html code to include these icons, and configuration directives for platforms to provide us with PWA functionality. The site http://realfavicongenerator.net/ can help us out with some of these steps. It generates a zip file with icons and other artifacts based on a single uploaded icon. Because we are creating the amazing "Show Title" app that shows the title of SharePoint site hosting our app, I downloaded an icon of the letter and used that for the generation. The generator created a zip file with artifacts and the following HTML lines for inclusion in the head of our app page:

<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<meta name="theme-color" content="#ffffff">

Because we are hosting in a subfolder of a SharePoint document library and not in the root of a website we need to remove the leading slashes as in:

<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="manifest.json">
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#5bbad5">
<meta name="theme-color" content="#ffffff">

Besides a set of icons it generated a browserconfig.xml file for Internet Explorer with the following contents (leading slashes removed):

<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
  <msapplication>
  <tile>
    <square70x70logo src="mstile-70x70.png"/>
    <square150x150logo src="mstile-150x150.png"/>
    <square310x310logo src="mstile-310x310.png"/>
    <wide310x150logo src="mstile-310x150.png"/>
    <TileColor>#da532c</TileColor>
  </tile>
  </msapplication>
</browserconfig>

The web manifest file

Now we need to add a manifest file that drives our Progressive Web App. The specifications for the app manifest can be found at https://www.w3.org/TR/appmanifest/, but a better readable reference can be found at https://developer.mozilla.org/en-US/docs/Web/Manifest. In most examples, and in the generated zip file by the generator, the manifest file is named manifest.json. When hosting in SharePoint files ending in .json are not allowed. We will rename the file to manifest.webmanifest.

I made some small changes to the generated manifest, like adding a short_name and description and background_color (used as background color for the splash screen), and I added 128x128 and 144x144 version of the icon (I resized the 256x256 icon using a paint program) as that seems to be required by Firefox (128x128) and for the splash screen support (144x144). The start_url we set to index.html?home=true so that when we add the app to homescreen we can identify that it is an app lounched from the homescreen.

The manifest file manifest.webmanifest:

End of file manifest.webmanifest.

If we look into the descriptions about add to homescreen requirements (https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/) we find that the site:

  • Has a web app manifest file with:
    • a short_name (used on the home screen)
    • a name (used in the banner when showing the splash screen)
    • a 144x144 png icon used on the splash screen, (the icon declarations must include a mime type of image/png)
    • a start_url that loads
  • Has a service worker registered on your site (service worker may be empty)
  • Is served over HTTPS (a requirement for using service worker).
  • Is visited at least twice, with at least five minutes between visits.

The app page index.html

In the index.html file we see the registration of the service worker. Besides the service worker registration there is one really important thing: the link to the web manifest. When specifying the link to the manifest file as found in all examples as <link rel="manifest" href="manifest.webmanifest"> it works perfectly locally, but does not work when deployed to SharePoint because authentication headers are not passed through on requesting the manifest. I tried everything. Providing the manifest content from a page manifest.aspx so I could set the correct content type (made no difference). Embedding the manifest as base64 in the href on the link (seems not supported on Chrome, see https://github.com/w3c/manifest/issues/534). The answer came on a question I posted on https://github.com/w3c/manifest/issues/535: we need to use the attribute crossOrigin="use-credentials", now the authentication headers are passed as required. So the manifest should be referenced as: <link rel="manifest" href="manifest.webmanifest" crossOrigin="use-credentials">. I think this is a bug, because on access of resources on the same origin the security context should be inherited (https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy).

The file index.html:

End of file index.html.

Testing the app from a browser and from a device

During development we use the sp-rest-proxy and can access the site on http://localhost:8081. We can now test the app from for example Chrome. Testing the app in Chrome is interesting because Chrome has support for web app manifests in the developer tools on the application tab. From this tab it is possible to see if the manifest is correctly parsed and we can test the Add to homescreen functionality:

But what if we want to test the app on another device like a mobile phone while developing on http://localhost:8081? Ngrok to the rescue! Install ngrok on you system and run ngrok http 8081.

We now have an outside https endpoint to access our app. Now open https://471e3571.ngrok.io/index.html to open the app from another device like your mobile.

Deploying to SharePoint

Building on the SharePoint configuration described in the previous blog posts we can now deploy our app to SharePoint. The custom deployment script deploy.js will work for our current situation.

The file deploy.js:

End of file deploy.js.

On deployment we rename the index.html page to index.aspx. But we also need to do rewrites on the index.html and manifest.webmanifest files.

Because we need to deploy more artifacta to SharePoint, the deploy.js command got an optional parameter. If you give no parameter only the index.html and manifest.webmanifest files are deployed. If the parameter assets is given, also all other artifacts are deployed.

For deployment we no support the following npm commands:

  • npm start codedeploy - only deploy the index.html and manifest.webmanifest files
  • npm start deploy - deploy all files (makes the call node deploy.js assets)

When no offline support is required we can get away with an empty service-worker.js file. When we want offline support we need to implement caching functionality like the first approach below. In this first approach I don't remove old caches, and when cached I don't load newer versions. Not even of /_api/ calls. When creating a new version of the app we can increase the version number of the cache to cache the latest versions again. For api call we need another strategy. For more information on caching strategies see Jake Archibalds blog post https://jakearchibald.com/2016/caching-best-practices/. There is also agreat service workers cookbook at https://serviceworke.rs/ describing different caching strategies. In an upcoming blog post I will describe what I think would be the optimal caching strategy for SharePoint hosted apps and /_api service calls.

The file service-worker.js:

End of file service-worker.js.

Easy access to your SharePoint hosted PWA

The links into SharePoint for your Progressive Web App can become quite large, and not easy to share with others. For easy access on devices I registered a short link https://bit.ly/sptitle to my app using the https://bit.ly shortening service.

SharePoint SPA Series blog posts

1 Comment

  • Question did you get the manifest to work in production? You said you got the answer but it didnt seem clear. Im going through the same issue. I tried using javascript to replace the file extension to make it a json file and that didnt work either. The crossOrigin="use-credentials" didnt work for me but it could be because it is an anonymous form on the front end and the data goes through an api before hitting a SharePoint list on the backend. For me this is the last bit I got service worker and local storage going but not a manifest. Thanks in advance.

Comments have been disabled for this content.