Progressive Web App with Angular 18
We are going to make our standard Web Application a PWA ( Progressive Web App )
We will use the Angular javascript framework version 18.0.2
What are we going to do ?
This is step 7 of our Angular guide which will allow us to obtain a PWA type Web Application . The basic Angular project that we will use already has the following characteristics
- Generated with Angular CLI
- Routing
- Lazy Loading
- The Bootstrap CSS framework
- Module management
- Server Side Rendering
All the sources created are indicated at the end of the tutorial.
The application is at the following address
Before you start
2008 App Store is an application store distributed by Apple on mobile devices running iOS.
2012 Google Play Store is an online application store created by Google.
2014 , annual global sales of smartphones exceed one billion units.
2017 two mobile operating systems share the global smartphone market.
Android 85.1% and IOS 14.8%
More than 50% of internet searches are now carried out on mobile in France.
Android and iOS operating systems are written in different programming languages.
So iOS apps run on Objective-C/Swift , while Android apps run on Java .
If you want to develop a mobile application, you can either develop a specific version for each platform or use a cross platform tool that will allow you to have only one source for both OS.
It will nevertheless be necessary to manage registration on the app stores.
In all cases, users must go to a download platform to install an app.
In 2015, Frances Berriman and Google engineer Alex Russell proposed the term “progressive web apps”
A PWA can be consulted like a classic website, from a secure URL but allows a user experience similar to that of a mobile application, without the constraints of the latter (submission to App-Stores, significant use of the device's memory …).
Initialization
We will use the Angular documentation to apply this technique.
https://angular.io/guide/service-worker-intro
We will use the angular-cli command
ng add
# Adding the pwa library
ng add @angular/pwa
Angular-cli automatically made a number of changes to our project.
- modification of the package.json file (in this example we will update the dependencies and the descriptors)
- editing angular.json file
- creating the ngsw-config.json file
- creation of the src/manifest.webmanifest file
- modifying the src/index.html file
- modifying the src/app.module.ts file
- creating icons src/app/assets/icons
Auto-created icons do not work during deployment.
Get the ones that are available on the final repo.
"dependencies": {
"@angular/animations": "18.0.2",
"@angular/common": "18.0.2",
"@angular/compiler": "18.0.2",
"@angular/core": "18.0.2",
"@angular/forms": "18.0.2",
"@angular/platform-browser": "18.0.2",
"@angular/platform-browser-dynamic": "18.0.2",
"@angular/platform-server": "18.0.2",
"@angular/router": "18.0.2",
"@angular/service-worker": "18.0.2",
"@angular/ssr": "18.0.3",
"@fortawesome/fontawesome-free": "6.5.2",
"bootstrap": "5.3.3",
"express": "4.19.2",
"rxjs": "7.8.1",
"tslib": "2.6.3",
"zone.js": "0.14.7"
},
"devDependencies": {
"@angular-devkit/build-angular": "18.0.3",
"@angular/cli": "18.0.3",
"@angular/compiler-cli": "18.0.2",
"@types/express": "4.17.21",
"@types/jasmine": "5.1.4",
"@types/node": "20.14.2",
"angular-eslint": "18.0.1",
"eslint": "9.4.0",
"jasmine-core": "5.1.2",
"karma": "6.4.3",
"karma-chrome-launcher": "3.2.0",
"karma-coverage": "2.2.1",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.1.0",
"typescript": "5.4.5",
"typescript-eslint": "8.0.0-alpha.20"
}
{
"assets": [
"src/favicon.ico",
"src/assets",
"src/manifest.webmanifest"
],
........
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kb",
"maximumError": "4kb"
}
],
"outputHashing": "all",
"serviceWorker": "ngsw-config.json"
},
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/media/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}
{
"name": "angular-starter",
"short_name": "angular-starter",
"theme_color": "#1976d2",
"background_color": "#fafafa",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularStarter</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- Google tag (gtag.js) -->
<script async="" src="https://www.googletagmanager.com/gtag/js?id=YOUR-ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'YOUR-ID');
</script>
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>
import { ApplicationConfig, isDevMode } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';
import { provideServiceWorker } from '@angular/service-worker';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideClientHydration(), provideServiceWorker('ngsw-worker.js', {
enabled: !isDevMode(),
registrationStrategy: 'registerWhenStable:30000'
})]
};
Conclusion
We will test how the PWA works
The following scripts allow you to do this
- npm run build
- npm run serve:ssr:angular-starter
- http://localhost:4000/
All that remains is to open Chrome Developer Tools with Ctrl + Shift + J
And run a test of the Lighthouse tool
- Audits
- Run audits
Source Code
The source code used at the beginning of the tutorial is available on github
https://github.com/ganatan/angular-ssr
The source code obtained at the end of this tutorial is available on github
https://github.com/ganatan/angular-react-pwa
The following steps will allow you to obtain a prototype application
- Step 8: Search Engine Optimization with Angular
- Step 9: HttpClient with Angular
The last step provides an example application
The source code of this final application is available on GitHub
https://github.com/ganatan/angular-app