Transforming an existing Angular application into a Progressive Web App
In this tutorial we will show how to transform an existing Angular application into a Progressive Web App (PWA) step by step.We will work on the app that we have built in the previous article. But the steps can be applied any Angular v4 application built with @angular/cli. This is our base repo.
Since it will take to much time to explain what the PWA is, we will focus on the PWA configuration instead of PWA architecture .
We need following key elements to turn a standard web application into a PWA;
- Service Worker
- Service Worker Manifest
- App Manifest
Step-1: Creating Service Worker & App Manifest
A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. Today, they already include features like push notifications and background sync. — Matt Gaunt
We need a Service worker at the first step. There is an easy way to create a service worker by using @angular/service-worker.
Let’s install the library:
npm install @angular/service-worker --save
After installing this library, we also need to tell angular-cli to build the project with service worker.
ng set apps.0.serviceWorker=true
Then add serviceWorker into “src/main.ts ”file;
We easily implemented the service worker. Let’s build our application to see the additional files that automatically generated.
ng build --prod
The build will be stored in the
dist/ directory. We have three new files under dist/ folder;
- worker-basic.min.js: Service Worker
- ngsw-manifest.json: Service Worker Manifest
- sw-register.HASH.bundle.js: required to register Service Worker in index.html
If we look into ngsw-manifest.json, we will see the static content of the application. The service worker checks the contents under “static” (see below) and download and serve them to the application when needed. Service Worker also creates copies of the static content in case of absence of network. Application can work offline by this way.
We can see our Service Worker in action after we deploy the application.
Warning: We deploy the app by publishing it to Firebase Hosting. You can use Firebase Hosting as well or you may need to use additional libraries such as “http-server” to serve production version.
Let’s go to Chrome Dev Tools > Application > Service Worker.
Well Done, we have a working Service Worker.
Second thing we need to do is creating App Manifest and adding it into index.html.
add the following two lines into src/index.html
After building and deploying our app again, we can see our App Manifest in action as well as Service Worker.
Congratulations! We have successfully implemented service-worker and app-manifest into our app.
Step-2: Managing the Offline Behaviour
If we look offline behaviour of our application, we will see something weird.
When we try to go /index.html, app works well. But it doesn’t work when we want to go existing route such as “/search”.
The reason is that we only configured the static plugin in the service worker manifest. Thus service worker serves only the static files in the manifest. Our service worker doesn’t know about the routing yet. We need to state our routing configuration in the manifest to enable service worker understands the routes.
Let’s add the routing configuration into ngsw-manifest.json.
Since we use external font for Material Icons, we need to declare source url in ngsw-manifest otherwise icons will not be visible when the app is offline.
After build & deploy the code again, we have fully offline working application (except getting search results from server).
It can be seen that all files were fetched from Service Worker when the app is offline.
Step-3: Testing Progressiveness
We proceed very well and obtained a working PWA eventually.
But what if we would like to know how progressive our app is? How to test our PWA? Answer is Google Lighthouse.
Lighthouse analyses web apps and web pages, collecting modern performance metrics and insights on developer best practices.
Let’s install Lighthouse plugin then go to our app and click the Lighthouse icon on the extension bar.
Here are the results.
We have 100% Progressive Web app, which is great! But there is a little problem with the performance.
Step-4: Improving the Performance
If we are looking for a performance improvement, first thing to check is our bundle size. Large bundle size causes delay in app loading thus affecting the performance.
We need to build again our project to analyze the bundle by using source-map-explorer. (don’t use --prod when building).
On the command line;
npm install source-map-explorer --save
ng build -aot
Our bundle size is 2.7 Mb and @angular/material covers almost 1Mb of it.
We need to reduce our bundle size as much as possible.
We should renounce some libraries and remove them from our project.
- Angular Material
- We should re-write our styles without getting help from wonderful Angular Material and FlexLayout libraries. Our app will have lack of eye-candy especially without Angular Material.
We will skip these time-consuming operations and directly give the the final result.
Here’s the latest repo after the operation. Let’s check the performance to see how much we proceed.
Great, we managed to increase performance rate to 94 pt.
First meaningful paint reduced from 3.100ms to 2.170ms (%33)
First interactive reduced from 3.390ms to 2.540ms (%25)
Progressive Web Apps are really great! Although documentations are still limited, it is getting easier to build PWAs thanks to the members of the community.
In this tutorial, We aimed to show you the steps to be taken and points to be considered when building a PWA.
Hopefully this tutorial will help you to create PWAs.
Please recommend the article if you would like to make it reach the other people.
Progressive Web Apps using the Angular Mobile Toolkit, Maxim Salnikov
Great Progressive Web App Experiences with Angular (Google I/O ’17), Alex Rickabaugh, Stephen Fluin