Progressive web apps are web applications built with technologies that make them behave like native apps.
An advantage of progressive web apps is that the ability to work smoothly when network coverage is unreliable. Also, unlike native apps, no installation is required, but they’re faster than typical web apps.
This blog isn’t about what progressive web apps are and what they’re not, it’s about how you’ll be able to build progressive web apps with Angular. you can read more about progressive web apps, here.
Getting started to show you ways to create progressive web apps with Angular, we are going to build a really simple website. Once we are done, we’ll use the Lighthouse Chrome extension to check if our app is actually progressive.

Creating a brand new Angular Project to make a new Angular project via Angular CLI, you have to install Angular CLI on your machine, first. If Angular CLI isn’t installed on your machine yet, run the command below to install it globally.
//install Angular CLI
npm install -g @angular/cli
Once Angular CLI is globally installed, you’ll be able to proceed to make a brand new project with it. By default, Angular will generate test files that are of no use in our little project. so as to stop this, we’ll add the --skip-tests
flag to our command.
//create a new Angular project without test files.
ng new ng-pwa --skip-tests
Web App Manifest a web app manifest is a simple JSON file that contains configurations that provides web applications the power to be saved on the user’s home screen. While also defining its appearance and behavior when launched from the home screen. Web app manifest is a basic requirement for progressive web apps but can be used on any website. you’ll be able to read more about the web app manifest here.
To create a web app manifest for our app, navigate to the src/
folder, and create a file named manifest.json
within the root of the folder. Copy and paste the content below into the file.
// src/manifest.json
{
"name": "Angular Progressive Web App",
"short_name": "Ng-PWA",
"start_url": "./",
"theme_color": "#008080",
"background_color": "#008B8B",
"display": "standalone",
"description": "A PWA that is built with Angular",
"icons": [
{
"src": "/assets/images/icons/icon-16x16.png",
"sizes": "16x16",
"type": "image/png"
},
{
"src": "/assets/images/icons/icon-32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "/assets/images/icons/icon-150x150.png",
"sizes": "150x150",
"type": "image/png"
},
{
"src": "/assets/images/icons/icon-180x180.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "/assets/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
In our web app manifest, we defined the name
which will be attached to our app icon on users’ home screen and a short_name
which will replace it, just in case it’s too long. We also specified the landing page of the app, when launched from the home screen with start_url
. The theme_color
specifies the color the browser UI will assume when users visit our site. The background_color
property controls the color of the background on which our app icon is going to be displayed when users launch our app from their home screen. With display
, you specify if the browser UI should be hidden or not when users visit your site.
We expect users to go to our site with different kinds of devices with different screen sizes, so there’s a requirement to create duplicates of your app icons in multiple dimensions. Real Favicon Generator can help automate your work.

When you are done, visit the index.html
file and add it to the head section.
<!-- src/index.html -->
...
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#008080">
...
The web app manifest won’t be added to the build folder unless we instruct Angular to do so. we’ll do this by adding the manifest.json
file to the assets array within the apps section of angular-cli.json
file.
// .angular-cli.json
...
"apps": [
{
...
"assets": [
...
"manifest.json"
],
...
Service Workers Service workers are the backbone of progressive web apps. Written in Javascript, they assist cache important assets and files, so as to keep the downosaur at bay and make our app functional when the network coverage is unavailable or unreliable. Service workers also can intercept requests and manage responses from the server amid other things. you’ll be able to read more about service workers here.
Run the npm install
command to put in the package.
//install sw-precache-webpack-plugin as a development dependency
npm install --save-dev sw-precache-webpack-plugin
Once the package is installed, visit the app root and make a file named precache-config.js
. Copy and paste the code below into the file.
// pre-cache.config.js
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
module.exports = {
navigateFallback: '/index.html',
navigateFallbackWhitelist: [],
stripePrefix: 'dist',
root: 'dist/',
plugins:[
new SWPrecacheWebpackPlugin({
cacheId: 'ng-pwa',
filename: 'service-worker.js',
staticFileGlobs: [
'dist/index.html',
'dist/**.js',
'dist/**.css'
],
})
],
stripePrefix: 'dist/assets',
mergeStaticsConfig: true
};
The precache-config.js
file configures the sw-precache-webpack-plugin
using literal objects key-value pairs.
Angular as a front-end framework for building single-page applications uses client-side URL routing and can, therefore, generate arbitrary URLs that aren’t cached by the auto-generated service worker.
In such situations, we’ll define an HTML entry the requested URL is going to be mapped to and navigateFallback
handles that. The HTML entry should be able to provide the specified resources (Our app is a SPA, and index.html
is the entry point. It can handle arbitrary URLs) and must be among the files selected to be cached within the staticFileGlobs
array. navigateFallbackWhitelist
can be empty or contains a regex that defines the type/pattern of URL that navigateFallback is going to be used for.
To get a deeper understanding of the way to configure sw-precache-webpack-plugin
, read the documentation.
To finish the service worker setup, we’ll create a custom npm script/command which will be used to build our app and auto-generate the service worker file in the build folder. head to the package.json
file and add the following to scripts
.
// package.json
...
"scripts": {
...
"pwa": "ng build --prod && sw-precache --root=dist --config=precache-config.js"
},
...
The View We only have one view, since our primary focus is on the process of building progressive web apps with Angular.
<!-- src/app/app.component.html -->
<div class="container">
<h1>
A Progressive Web App Built with Angular.
</h1>
<img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo="
alt="Angular logo">
<h2>Get Started With Progressive Web Apps: </h2>
<ul>
<li>
<h4><a target="_blank" rel="noopener"
href="https://developers.google.com/web/fundamentals/primers/service-workers/">Service Workers</a>
</h4>
</li>
<li>
<h4><a target="_blank" rel="noopener"
href="https://developers.google.com/web/fundamentals/web-app-manifest/">Web App Manifest</a></h4>
</li>
<li>
<h4><a target="_blank" rel="noopener"
href="https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/">Code Lab (PWA)</a>
</h4>
</li>
</ul>
</div>
The rel="noopener
attribute is important in progressive web apps if the anchor element’s target
attribute is set to _blank
for security and performance reasons. Read more.
Below is the CSS
code.
/* src/styles.css */
body{
background-color: teal;
}
.container{
text-align: center;
}
ul{
list-style: none;
}
h1, h2, a {
color: white;
}
Hosting the service worker is the heartbeat of any progressive web app. However for the service worker to work fine, our app must be served over a secure connection. Hence, we’ll be deploying our app to Firebase because apps hosted on Firebase are served over a secure connection. you’ll be walked through the steps.

Once a brand new Firebase project has been created, move to the command terminal and navigate to your progressive web app folder. Run npm install -g firebase-tools
to install firebase-tools globally. The firebase-tools package will allow us to check run and deploy apps to Firebase from the command terminal.
When the installation is complete, we’d like to build our app in preparation to deploy. to build our Angular app and auto-generate the service worker, run npm run pwa
. This runs a custom script we created earlier and makes our app production-ready.
Now it is time to introduce Firebase to the app. Run this command to log in to Firebase:
firebase login
At this point, you will be asked for your firebase credentials. Enter your account information into the terminal.
Once authenticated, run the following command to initialise Firebase in your project:
firebase init
Then answer the following questions
Are you ready to proceed? (Y/n) = Y
Which Firebase CLI features do you want to setup for this folder? = Hosting
Select a default Firebase project for this directory = Your-Firebase-Project-Name
What do you want to use as your public directory? = dist
Configure as a single-page app (rewrite all urls to /index.html)? (y/N) = Y
File dist/index.html already exists. Overwrite? (y/N) = N
Our app is ready to be deployed. Run the following command to deploy the app to Firebase:
firebase deploy
Finally, run the following command to see the app:
firebase open hosting:site
Troubleshooting
If you see a “Firebase Hosting Setup Complete” message instead of your app, you may have overwritten your index.html
. Rebuild with npm run pwa
, firebase init
, and ensure you select “No” for overwriting index.html
.
Depending on your configuration, your app may exist under "ng-pwa"
(the name of the Angular project). During firebase init
, you can set the public directory to dist/nw-pwa
instead of dist
to avoid this.
Your progressive web application has now been built and deployed. Now, we can use a tool to test.
Lighthouse is a Chrome extension made by Google. It can be used to test how compliant a progressive web app is to the progressive web app standard, in addition to other tests.
The highest score is 100%, and the PWA score for this app is 91%.
To test your PWA, open the hosted app in your Google Chrome Web Browser. Click on the Extensions button and select Lighthouse. A window will display and prompt you to click on a Generate report button. After clicking the button, you will temporarily see a screen with a Waiting for Lighthouse results message. When the test completes, you will be presented with a screen of the test results.
Conclusion
In this article, you’ve built a progressive web app with Angular and deployed through Firebase. Progressive web apps provide users with an experience similar to native apps. However, PWAs are lighter and much more flexible.