Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

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 Adobe Experience Cloud Blog.

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

…or…

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 run.sh 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:

#!/bin/bash
PATH=$PATH:$(npm bin)
set -x
# Production build
ng build --prod
# Serve
cd dist
http-server

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 run.sh 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 run.sh looks like this now.

#!/bin/bash
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
http-server

You can execute the bash script using sh run.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": {
         "https://www.googleapis.com/books/": {
           "match": "prefix"
         }
      },
      "cache": { 
        "optimizeFor": "performance",  
        "maxAgeMs": 3600000,  
        "maxEntries": 20,     
        "strategy": "lru"
      }
    }]
  },
  "external": {
    "urls": [{
      "url": "https://fonts.googleapis.com/icon?family=Material+Icons"
    }]
  }
}
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 https://www.googleapis.com/books/ 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 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

Posted in Application Development
Share this

Ahsan Ayaz

Ahsan Ayaz is a Google Developer Expert in Angular. During his time at Modus, Ahsan worked as a Software Architect. Apart from building web and hybird-mobile apps based on Angular, Ionic & MEAN Stack, Ahsan contributes to open-source projects, speaks at events, writes articles and makes video tutorials.
Follow

Related Posts

  • Ionic
    Creating Apps with Ionic 2

    Ionic is a fantastic and established framework for creating hybrid mobile apps for both iOS…

  • Angular Elements - Your ngComponents Everywhere
    Angular Elements -- Your ngComponents Everywhere

    If you’re reading this, you already know Angular. So whether you’ve worked on AngularJS (1.x)…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
IT modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Careers
  • Let’s talk
  • EN
  • FR