Creating Progressive Web Apps Using Angular


Progressive web applications are the new standard in this modern era of web development. They’re pure web applications built with the very web technologies (HTML, JS & CSS) but behave as a hybrid. i.e. somewhere between web and native apps.

The concept of PWAs started booming in late 2015 and is now becoming a standard for modern web apps as companies both large and small are now adopting PWAs for their current and future projects/products. The list includes Twitter Lite & Tinder, among others. You can see some cool examples of PWAs at PWA Rocks.

One important thing to know before targeting PWAs for production is that Apple currently does not support the major features of PWA such as Service Workers, Push Notifications & Installing to home screen through a browser provided prompt. You can read more about this in this informative blog post.


What is a PWA?

According to Google, PWAs should be:

  1. Reliable – They should load instantly even if the network conditions are not so good or if there’s no network at all.
  2. Fast – They should be highly interactive and provide fast user experience. I.e. smooth scrolling and animations etc.
  3. Engaging – They should be engaging so the user gets an immersive experience and stays connected with the app.

Apart from these characteristics, PWAs are usually responsive and should adopt to most devices and screen sizes. They’re installable on mobile devices, meaning you can have a link on your home screen to launch the app right away making it easier to access. And they work in all web browsers. In modern browsers, we’ll leverage the amazing APIs we’ll talk about later, but in older browsers, our app should still work perfectly fine, without the amazing modern stuff of course.

Let’s get started.

I already have a simple web application which searches books using the Google Books API. We will convert this into a Progressive Web App. The finalized PWA can be cloned from this code repo. I suggest you fork the repository, clone into your machine and checkout the non-pwa-app branch to follow along with the tutorial.

The final application should look like this and can be viewed here:


Creating Progressive Web Apps Using Angular: Search for Books Loading then viewing Final Application


The steps going forward assume that you have Git, NodeJS, and Angular CLI installed. You will also need http-server package for this tutorial.

Running the application (non-pwa)

From the root of your project, execute the command ng-serve using terminal/ cmd and navigate to localhost:4200. You should see the app running as:


Creating Progressive Web Apps Using Angular: App Running


Non-pwa served using `ng-serve`


We can always test the performance of our PWA using Lighthouse and improve areas of our application lacking in performance. Here are the stats of our non-pwa:


Creating Progressive Web Apps Using Angular: Stats of non-pwa


Overall stats of non-pwa



Creating Progressive Web Apps Using Angular: Average Load Time Statistics


The average load time on a low speed connection is > 11 seconds


Making the app reliable & faster

We want our application to be reliable. It should work even if the network is poor or is unavailable. Let’s see what happens if we turn off the network and run our application. To do this, open the inspector. Go to the network tab and click on Offline. Do not close the inspector.


Creating Progressive Web Apps Using Angular: Click Offline


Now, refresh the page and you will see something like this:


Creating Progressive Web Apps Using Angular: There is no internet connection


To avoid this happening to end users, we’ll be using Service Workers to cache our application. Then, we can use it even when there’s no network.

To achieve this, we can configure the service worker manually. I recommend using the amazing pwa tools that the Angular team has provided. We’re going to install those tools now to introduce a service worker in our application.
Now, close the chrome inspector. From your project root, execute the following command which installs the required plugins via npm/yarn in our project:

npm install --save @angular/service-worker @angular/platform-server ng-pwa-tools


yarn add @angular/service-worker @angular/platform-server ng-pwa-tools --save

Now we’ll enable service workers inside our application. By default, they’re turned off in angular-cli when creating a project. We can enable them by executing the following command from project root which updates our angular-cli.json:

ng set apps.0.serviceWorker=true

From now on, we’ll be using the bash script to serve our application because Service Workers don’t work in a development environment. We’ll be creating prod builds and serving the dist folder using http-server package. The script now should look like this:

PATH=$PATH:$(npm bin)
set -x
# Production build
ng build --prod
# Serve
cd dist

The next step is to let the service worker know about our application’s routing & assets so the service worker can cache those for repeated visits. We could create a service worker manifest for this purpose but since we already have installed some amazing tools, we’re going to create this manifest automatically by letting the tool know about our application’s routing.
We’re going to add the command below in our to do that:

./node_modules/.bin/ngu-sw-manifest --module src/app/app.module.ts

This creates the routing information in the sw-manifest.json that is being created and since our app’s entry point is app.module.ts it traverses the whole app to gain that information. So our looks like this now.

PATH=$PATH:$(npm bin)
set -x
# Production build
ng build --prod
# merge ngsw-manifest and copy to dist
./node_modules/.bin/ngu-sw-manifest --module src/app/app.module.ts \
--out dist/ngsw-manifest.json
# Serve
cd dist

You can execute the bash script using sh on mac and on windows you can use cmder or git-bash to execute the command. After that, navigate to localhost:8080 to see the app running in prod mode.
What actually happened is that it created the prod build in the dist folder and served to localhost:8080, created a file sw-manifest.json and copied it to the dist folder , included a file worker-basic.min.js which is a basic Service Worker on page load, a service worker registration script which registers this basic service worker on page load.

Below are the contents of ngsw-manifest.json:

  "routing": {
    "index": "/index.html",
    "routes": {
      "/": {
        "match": "exact"
      "/search": {
        "match": "exact"
      "^/book/[^/]+$": {
        "match": "regex"
  "static": {
    "urls": {
      "/3rdpartylicenses.txt": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
      "/favicon.ico": "84161b857f5c547e3699ddfbffc6d8d737542e01",
      "/index.html": "e8736d97b1c413fa72faaa75710ab839a0bbebea",
      "/inline.71440d3fb16d45c77b34.bundle.js": "1a927b41602a9c74c968b5ce9231bbc96b82da88",
      "/main.78e6e14ecddcde59bd02.bundle.js": "c1ee5368ceaad3adf369fbd1980e9cb65c17914a",
      "/ngsw-manifest.json": "7a2ae9be33b908445d8f69684aad455c2c77c227",
      "/polyfills.574056ad92b56d22f7bb.bundle.js": "7c10ca088d639aac9bab14723e759e22533bf718",
      "/styles.abfd3a51b147501a0813.bundle.css": "729a48e901590214084c2670870f0527e00dbdc3",
      "/sw-register.c3a9f56ebf829a0880d3.bundle.js": "6c5694fa18f55de662ff331e4d69d4521033fd80",
      "/vendor.e5ff14a5323fbc5ed7b3.bundle.js": "37c0e0a51b4ab2828a6073d0d5e00f91651b69a8",
      "/worker-basic.min.js": "2f12848c352bd6baf25f0f1d995351696ef518ff"
Contents of auto-generated ngsw-manifest.json

The contents include our application’s routing as well as all the static files that can be cached for our applications. Notice the long hash against the file URLs. This hash informs the service worker when the files have been updated by us and the service worker now needs to re-cache the newer files.

Now, go to localhost:8080 and open chrome inspector, go to Application tab and you should see our service worker up and running:


Creating Progressive Web Apps Using Angular: Service Worker Running


Since our service worker is alive now, switch to the Network tab, and refresh the page. You should see something like this:


Creating Progressive Web Apps Using Angular: Assets being fetched from the service worker now


Assets being fetched from the service worker now


We’re actually caching our assets now using the service worker. Amazing, right? But this doesn’t load any of the data that we require. That’s because currently we are not caching our search API calls. But we should get some results even if we are offline.
To do that, we’ll add our own custom ngsw-manifest.json inside the src folder in our project. The PWA tools we’re using will combine the auto-generated ngsw-manifest.json with our custom json file and put the output into the dist folder. So let’s create the json file and put the following content inside it:

  "dynamic": {
    "group": [{
      "name": "books api",
      "urls": {
         "": {
           "match": "prefix"
      "cache": { 
        "optimizeFor": "performance",  
        "maxAgeMs": 3600000,  
        "maxEntries": 20,     
        "strategy": "lru"
  "external": {
    "urls": [{
      "url": ""
Contents of our custom ngsw-manifest.json


The Google Books API calls are configured under the dynamic chunk as we want every request prefixing the URL to be cached. We can fine tune the caching technique for every one of our URL configurations for performance (check in service worker first, if not found, fetch from server) or for freshness (check from the server first, if not found/offline, fetch from the service worker).

We can also cache external resources like external CSS, fonts, js files that we might include from some CDN etc.

Now, if you run sh, go to the Network tab in the inspector, and then refresh your page. You will see that the service API call (to Google Books API), is cached too and the data is being received from the server:

Creating Progressive Web Apps Using Angular: Data is being received by the server


Books API Call fetching books list from the service worker


Creating Progressive Web Apps Using Angular: Books API Call fetching book details from the service worker


Books API Call fetching book details from the service worker

Tada! The application is now faster and more reliable because on every repeated visit, it fetches content from the service worker saving network calls for the end-user. Try refreshing the browser a few times and see how fast the data loads providing a smooth, faster and immersive experience. Also, try the offline mode to be further amazed 😉 All the previous visits should be cached.

Creating Progressive Web Apps Using Angular: App Improved

We have improved our app, so let’s see if the performance seems different in Lighthouse.

Creating Progressive Web Apps Using Angular: Performance gain after implementing service worker


Performance gain after implementing service worker


Creating Progressive Web Apps Using Angular: First page view time has decreased but is still 11.3s


First page view time has decreased but is still 11.3s


As you can see, we have made some progress.

*Since this post was published, Angular has introduced Service Worker, which can be used to create PWAs. We will be releasing a blog post series that will walk you through the process of creating PWAs with the new service worker.

*edited to add

This website uses cookies

These cookies are used to collect information about how you interact with our website and allow us to remember you. We use this information in order to improve and customize your browsing experience, and for analytics and metrics about our visitors both on this website and other media. To find out more about the cookies we use, see our Privacy Policy.

Please consent to the use of cookies before continuing to browse our site.

Like What You See?

Got any questions?