guide angular pwa - devonfw/devon4ng GitHub Wiki
Progressive web applications (PWA) are web application that offer better user experience than the traditional ones. In general, they solve problems related with reliability and speed:
-
Reliability: PWA are stable. In this context stability means than even with slow connections or even with no network at all, the application still works. To achieve this, some basic resources like styles, fonts, requests, … are stored; due to this caching, it is not possible to assure that the content is always up-to-date.
-
Speed: When an users opens an application, he or she will expect it to load almost immediately (almost 53% of users abandon sites that take longer that 3 seconds, source: https://developers.google.com/web/progressive-web-apps/#fast).
PWA uses a script called service worker, which runs in background and essentially act as proxy between web app and network, intercepting requests and acting depending on the network conditions.
This guide assumes that you already have installed:
-
NodeJS
-
npm package manager
-
Angular CLI / Nx CLI
To explain how to build PWA using angular, a basic application is going to be built. This app will be able to ask for resources and save in the cache in order to work even offline.
This step can be completed with one simple command using the Angular CLI: ng new <name>
, where <name>
is the name for the app. In this case, the app is going to be named basic-ng-pwa
. If you are using Nx CLI, you can use the command nx generate @nrwl/angular:app <name>
in your Nx workspace. You can follow this guide if you want to get started with Nx workspace.
Web applications usually uses external resources, making necessary the addition of services which can get those resources. This application gets a dish from My Thai Star’s back-end and shows it. To do so, a new service is going to be created.
-
go to project folder:
cd basic-ng-pwa
. If using Nx, go to the root folder of the workspace. -
run
ng generate service data
. For Nx CLI, specify the project name with--project
flag. So the command becomesng generate service data --project=basic-ng-pwa
-
Modify data.service.ts, environment.ts, environment.prod.ts
To retrieve data with this service, you have to import the module HttpClient
and add it to the service’s constructor. Once added, use it to create a function getDishes()
that sends HTTP request to My Thai Start’s back-end. The URL of the back-end can be stored as an environment variable MY_THAI_STAR_DISH.
data.service.ts
...
import { HttpClient } from '@angular/common/http';
import { MY_THAI_STAR_DISH } from '../environments/environment';
...
export class DataService {
constructor(private http: HttpClient) {}
/* Get data from Back-end */
getDishes() {
return this.http.get(MY_THAI_STAR_DISH);
}
...
}
environments.ts
...
export const MY_THAI_STAR_DISH =
'https://mts-devonfw-core.cloud.okteto.net/api/services/rest/dishmanagement/v1/dish/1';
...
environments.prod.ts
...
export const MY_THAI_STAR_DISH =
'https://mts-devonfw-core.cloud.okteto.net/api/services/rest/dishmanagement/v1/dish/1';
...
The component AppComponent
implements the interface OnInit
and inside its method ngOnInit()
the subscription to the services is done. When a dish arrives, it is saved and shown (app.component.html).
...
import { DataService } from './data.service';
export class AppComponent implements OnInit {
dish: { name: string; description: string } = { name: '', description: ''};
...
ngOnInit() {
this.data
.getDishes()
.subscribe(
(dishToday: { dish: { name: string; description: string } }) => {
this.dish = {
name: dishToday.dish.name,
description: dishToday.dish.description,
};
},
);
}
}
This step shows code interesting inside the sample app. The complete content can be found in devon4ts-samples.
index.html
To use the Montserrat font add the following link inside the head
tag of the app’s index.html file.
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
styles.scss
body {
...
font-family: 'Montserrat', sans-serif;
}
app.component.ts
This file is also used to reload the app if there are any changes.
-
SwUpdate
: This object comes inside the@angular/pwa
package and it is used to detect changes and reload the page if needed.
...
import { SwUpdate } from '@angular/service-worker';
export class AppComponent implements OnInit {
...
constructor(updates: SwUpdate, private data: DataService) {
updates.available.subscribe((event) => {
updates.activateUpdate().then(() => document.location.reload());
});
}
...
}
Install Angular PWA package with ng add @angular/pwa --project=<name>
. As before substitute name
with basic-ng-pwa
.
The above command completes the following actions:
-
Adds the @angular/service-worker package to your project.
-
Enables service worker build support in the CLI.
-
Imports and registers the service worker in the app module.
-
Updates the
index.html
file:-
Includes a link to add the
manifest.json
file. -
Adds meta tags for theme-color.
-
Installs icon files to support the installed Progressive Web App (PWA).
-
Creates the service worker configuration file called
ngsw-config.json
, which specifies the caching behaviors and other settings.
-
manifest.json is a file that allows to control how the app is displayed in places where native apps are displayed.
Fields
name
: Name of the web application.
short_name
: Short version of name.
theme_color
: Default theme color for an application context.
background_color
: Expected background color of the web application.
display
: Preferred display mode.
scope
: Navigation scope of this web application’s application context.
start_url
: URL loaded when the user launches the web application.
icons
: Array of icons that serve as representations of the web app.
Additional information can be found here.
ngsw-config.json specifies which files and data URLs have to be cached and updated by the Angular service worker.
Fields
-
index: File that serves as index page to satisfy navigation requests.
-
assetGroups
: Resources that are part of the app version that update along with the app.-
name: Identifies the group.
-
installMode
: How the resources are cached (pre-fetch or lazy). -
updateMode
: Caching behavior when a new version of the app is found (pre-fetch or lazy). -
resources: Resources to cache. There are three groups.
-
files: Lists patterns that match files in the distribution directory.
-
urls
: URL patterns matched at runtime.
-
-
-
dataGroups
:UsefulIdentifies
the group. for API requests.-
name: Identifies the group.
-
urls
: URL patterns matched at runtime. -
version: Indicates that the resources being cached have been updated in a backwards-incompatible way.
-
cacheConfig
: Policy by which matching requests will be cached-
maxSize
: The maximum number of entries, or responses, in the cache. -
maxAge
: How long responses are allowed to remain in the cache.-
d: days. (5d = 5 days).
-
h: hours
-
m: minutes
-
s: seconds. (5m20s = 5 minutes and 20 seconds).
-
u: milliseconds
-
-
timeout: How long the Angular service worker will wait for the network to respond before using a cached response. Same
dataformat
asmaxAge
. -
strategy: Caching strategies (performance or freshness).
-
-
-
navigationUrls
: List of URLs that will be redirected to the index file.
Additional information can be found here.
manifest.json
Default configuration.
ngsw-config.json
At assetGroups → resources → urls
: In this field the google fonts API is added in order to use Montserrat font even without network.
"urls": [
"https://fonts.googleapis.com/**"
]
At the root of the json: A data group to cache API calls.
{
...
"dataGroups": [{
"name": "mythaistar-dishes",
"urls": [
"https://mts-devonfw-core.cloud.okteto.net/api/services/rest/dishmanagement/v1/dish/1"
],
"cacheConfig": {
"maxSize": 100,
"maxAge": "1h",
"timeout": "10s",
"strategy": "freshness"
}
}]
}
To check if an app is a PWA lets compare its normal behavior against itself but built for production. Run in the project’s root folder the commands below:
ng build --prod
to build the app using production settings.(nx build <name> --prod
in Nx CLI)
npm install http-server
to install an npm module that can serve your built application. Documentation here.
Go to the dist/basic-ng-pwa/
folder running cd dist/basic-ng-pwa
. In an Nx workspace, the path will be dist/apps/basic-ng-pwa
http-server -o
to serve your built app.
In another console instance run ng serve
(or nx serve basic-ng-pwa
for Nx) to open the common app (not built).
The first difference can be found on Developer tools → application, here it is seen that the PWA application (left) has a service worker and the common (right) one does not.
If the "offline" box is checked, it will force a disconnection from network. In situations where users do not have connectivity or have a slow, one the PWA can still be accessed and used.
Finally, browser extensions like Lighthouse can be used to test whether an application is progressive or not.