Progressive web apps are web applications built with technologies that make them behave like native apps. A benefit of progressive web apps is the ability to work smoothly when network coverage is unreliable. Also, unlike native apps, no installation is required, but they are faster than typical web apps.
In this article, you’ll build a progressive web app with Angular and deploy it with Firebase.
The code for this tutorial is available on GitHub.
Note: Currently, there is an @angular/pwa
package that helps with this process. This tutorial will cover an earlier alternative approach.
To complete this tutorial, you will need:
This tutorial was verified with Node v14.5.0 and npm
v6.14.5.
You can create a new project with Angular CLI. By default, Angular will generate test files that are not of use in this tutorial’s project. To prevent this generation, you’ll add the --skip-tests
flag to the following command to create a new project:
- npx @angular/cli@10.0.0 new ng-pwa --skip-tests
You will be prompted by some configuration options:
Output? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
This will create a new project directory named ng-pwa
.
Navigate to the new directory:
- cd ng-pwa
Now that you have a starter project, you can move on to creating a web app manifest.
A web app manifest is a JSON file that contains configuration that gives a web application the ability to be saved on the user’s home screen. It also defines 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.
To create a web app manifest for your app, you will need a new file named manifest.json
in the root of the src
folder:
- nano src/manifest.json
Add the content below into the file:
{
"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
that will be attached to our app icon on users’ home screen and a short_name
that will replace it, in case it is 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 (user interface) will assume when users visit our site. The background_color
property controls the color of the background on which our app icon will 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 visit our site with different types of devices with different screen sizes, so there is a need to make duplicates of your app icons in multiple dimensions.
When you are done adding image assets, go to the index.html
file and add the following to the <head>
section:
...
<head>
...
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#008080">
</head>
The web app manifest will not be added to the build folder unless we instruct Angular to do so. We will do that by adding the manifest.json
file to the assets array in apps
section of .angular-cli.json
file:
...
"apps": [
{
...
"assets": [
...
"manifest.json"
],
...
Note: If your application is built with Angular 6 or later, you will need to edit angular.json
instead of .angular-cli.json
:
...
"projects": {
"ng-pwa": {
...
"architect": {
"build": {
...
"assets": [
"src/manifest.json"
],
...
After creating a manifest.json
, modifying index.html
, and editing angular-cli.json
(or angular.json
), you are ready for the next step.
Service workers are the foundation of progressive web apps. Written in JavaScript, they help cache important assets and files, which helps keep an app functional when the network coverage is unavailable or unreliable. Service workers can also intercept requests and manage responses from the server amid other things.
We need to build our app with webpack
before pushing it to production. Our service worker must be able to track and cache the build files.
With the sw-precache-webpack-plugin
npm
package, we install the package and configure it.
Note: Currently, the developer for sw-precache-webpack-plugin
recommends using GenerateSW
from workbox-webpack-plugin
.
We can then run a command that will auto-generate the service worker in the build folder.
Run the npm install
command from the ng-pwa
directory to install the package:
- npm install --save-dev sw-precache-webpack-plugin@1.0.0
Once the package is installed, create a file named precache-config.js
:
- nano precache-config.js
Add the following into the file:
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 object key-value pairs.
Angular as a front-end framework for building single-page applications uses client-side URL routing. This means that it can generate arbitrary URLs that are not cached by the auto-generated service worker. In such situations, we’ll define an HTML entry that the requested URL will be mapped to, and navigateFallback
handles that. The HTML entry should be able to provide the desired resources. Because our app is a SPA (single-page application), and index.html
is the entry point — it can handle arbitrary URLs — therefore it must be among the files selected to be cached in the staticFileGlobs
array. navigateFallbackWhitelist
can be empty or contains a regex that defines the type or pattern of URL that navigateFallback
will be used for.
To get a deeper understanding of how to configure sw-precache-webpack-plugin
, read its documentation.
To finish the service worker setup, we will create a custom npm
script or command that will be used to build our app and auto-generate the service worker file in the build folder. Go to the package.json
file and add the following to scripts
:
...
"scripts": {
...
"pwa": "ng build --prod && sw-precache --root=dist --config=precache-config.js"
},
...
After installing the sw-precache-webpack-plugin
, creating precache-config.js
, and editing package.json
, you are ready for the next step.
We only have a single view, since our primary focus is on the process of building progressive web apps with Angular.
Edit app.component.html
and replace the content with the following code:
<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>
This code produces a web page with an image, some text, and three links.
The rel="noopener
attribute is essential in progressive web apps if the anchor element’s target
attribute is set to _blank
for security and performance reasons.
Edit styles.css
and replace the content with the following code:
body {
background-color: teal;
}
.container {
text-align: center;
}
ul {
list-style: none;
}
h1, h2, a {
color: white;
}
This code creates a teal background color, centers the text, and gives the text a white color.
Now, you have completed the view and can move on to deploying the app.
The service worker is the heartbeat of any progressive web app. However, for the service worker to work properly, our app must be served over a secure connection. Hence, we will be deploying our app to Firebase, which hosts over a secure connection. In this step, you will deploy your app to Firebase.
To get started, visit firebase.google.com
. If you don’t have an account already, create one to have access to the console. From the console, create a new Firebase project.
Once logged in, click on the Go to console link in the top right corner. On the console page, select Create a project. You will be prompted for a name for your project. You will also be prompted to enable Google Analytics. This tutorial will not require Google Analytics.
Click Create project and wait for the process to complete.
After the project has been created, you can click Continue to arrive at the Project Dashboard. For the purposes of this tutorial, we will be interested in the Develop section and the Hosting page.
Now you can go back to your command terminal. Run the npm install
command to install the firebase-tools
package globally:
- npm install -g firebase-tools@8.4.3
The firebase-tools
package will allow us to test run and deploy apps to Firebase from the command terminal.
When the installation is complete, we need to build our app in preparation for deployment.
To build the Angular app and auto-generate the service worker, run the following from the ng-pwa
directory:
- 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 prompted for credentials. Enter your account information into the terminal.
Once authenticated, run the following command to initialize Firebase in the project:
- firebase init
Then answer the questions as follows:
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 this command to see the app:
- firebase open hosting:site
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 it.
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!