In the update
Tip: try to use Chrome incognito mode when testing the application to ensure that the Service Worker does not read data from the previous residual state!!
1. PWA initialization on Angular 6 projects:
After sudo ng new pwa creates a new project, run sudo ng add @angular/pwa in the root directory of the project, and the Service Worker files, manifest. json files, and icon files of various sizes will be automatically added. Angular PWA Chinese portal
2. Update the PWA program
Import {SwUpdate} from ‘@angular/service-worker’ in app.component.ts; To load the update module of SW, every time the PWA program has an update, you can use the SwUpdate module here to get the update, and use the following code to achieve the update operation of the program:
export class AppComponent {
update: boolean;
constructor(updates: SwUpdate, private data: DataService) {
updates.available.subscribe( event= > {
this.update = true;
updates.activateUpdate().then((a)= >
document.location.reload() ); }); } title ='PWA';
}
Copy the code
SwUpdate Document portal
Then use an *ngIf in the HTML to determine whether it is updated or not (if it is, text is displayed, if it is not) :
<span *ngIf="update">There's an update associated with your progressive web application!</span>
Copy the code
Build the production program again each time you update the program, run sudo ng build –prod in the root directory, then go to CD Dist /PWA, and finally run http-server-o to run the updated program on the server.
Because ng serve does not work with Service workers, you must test the project locally with a separate HTTP server. You can use any HTTP server; I used the HTTP-server package from NPM. You can also customize ports to prevent port collisions:
http-server -p 8080 -c-1 dist/<project-name>
Copy the code
Note: If you want to update the PWA regularly, that is, to create a periodic polling method using interval, you need to make the process of the application registering the Aervice worker enter a stable state first, and then let it start the polling process. If you keep polling updates (such as calling interval()), the application will be prevented from reaching the stable state. ServiceWorker scripts will never be registered in the browser. Also: the various polling performed in the application prevents it from reaching a stable state
constructor(appRef: ApplicationRef, updates: SwUpdate) {
// Allow the app to stabilize first, before starting polling for updates with `interval()`.
const appIsStable$ = appRef.isStable.pipe(first(isStable= > isStable === true));
const everySixHours$ = interval(6 * 60 * 60 * 1000);
const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
everySixHoursOnceAppIsStable$.subscribe((a)= > updates.checkForUpdate());
}
Copy the code
So a summary of the use of the auto-update module:
constructor(appRef: ApplicationRef, updates: SwUpdate, private data: DataService) {
const appIsStable$ = appRef.isStable.pipe(first(isStable= > isStable === true));
const everySixHours$ = interval(6 * 1000);
const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
everySixHoursOnceAppIsStable$.subscribe((a)= > {
updates.checkForUpdate();
// console.log('check update in Service Worker');
});
updates.available.subscribe(event= > {
console.log('gotta new version here', event.available);
updates.activateUpdate().then((a)= > document.location.reload());
});
}
Copy the code
Check the updated version every 6 seconds, if no updates.activateUpdate().then(() => document.location.reload()); It simply reminds not to refresh and update the program when a new version is detected. When testing, you need to re-run the HTTP server ng build –prod and http-server -p 8080-C-1 dist/PWA. You will see a notification of the new version on the console on the original page.
When a new build of the application is published, the Service Worker treats it as a new version of the application, determined by the contents of the ngsw.json file, which contains hashes of all known content. If any cached file changes, the file’s hash changes in ngsw.json, causing the Angular Service Worker to treat the active file collection as a new version.)
3. How to cache files and API addresses and other items?
Json file. For example, if you want to cache Google Montserrat fonts and API addresses, all the code in this file is in glob format, i.e. :
- ‘**’ matches 0 to multisegment paths
- ‘*’ matches zero or more characters other than /
- ? Matches a character other than /
- ! The prefix indicates that the pattern is inverse, meaning that only files that do not match the pattern are included
Such as:
- /**/*.html Specifies all HTML files
- /*.html specifies only the HTML file in the root directory
- ! /**/*.map excludes all source mapping files
Do this in real code:
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
Copy the code
Add to the created assetGroups:
"urls": [
"https://fonts.googleapis.com/**"
]
Copy the code
AssetGroup follows TypeScript interface rules:
interface AssetGroup {
name: string; installMode? :'prefetch' | 'lazy';
// Prefetch tells the Angular Service Worker to fetch each listed resource when caching the current version of the app. This is a bandwidth-intensive pattern, but ensures that these resources are available when requested, even when the browser is offline
// Lazy does not pre-cache any resources. In contrast, the Angular Service Worker only caches resources that it receives requests for. This is an on-demand caching pattern. Resources that are never requested are never cached. This is useful for resources like images that are served at different resolutions, so that the Service Worker only caches the right resources for a particular screen and device orientation.updateMode? :'prefetch' | 'lazy';
// Prefetch tells the Service Worker to download and cache the updated resource immediately
Lazy tells the Service Worker not to cache these resources, but to treat them as unrequested and wait until they are requested again to update them.The lazy updateMode is valid only if installMode is also lazy. resources: { files? :string[];
/** @deprecated As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead. */versionedFiles? :string[]; urls? :string[];
};
}
Copy the code
Create the dataGroups cache API address below:
"dataGroups": [
{
"name": "jokes-api",
"urls": [
"https://api.chucknorris.io/jokes/random"
],
"cacheConfig": {
"strategy": "freshness",
"maxSize": 20,
"maxAge": "1h",
"timeout": "5s"
}
}
]
Copy the code
The dataGroups configuration follows the following interface:
export interface DataGroup {
name: string;
urls: string[]; version? :number;
cacheConfig: {
maxSize: number;
maxAge: string; timeout? :string; strategy? :'freshness' | 'performance';
};
}
Copy the code
The items in the cache setup are:
- “strategy” :
- Performance, the default, optimized for quick response. If a resource exists in the cache, this cached version is used. It allows resources to be somewhat stale (depending on maxAge) in exchange for better performance. This works for resources that do not change often, such as user avatars.
- Freshness optimizes for data immediacy, preferentially fetching requested data from the network. Only when the network times out will the request fall back into the cache according to timeout. This is useful for resources that change frequently, such as account balances.
- “MaxSize” : (required) maximum number of entries or responses in the cache. The open cache can grow indefinitely and eventually exceed the storage quota. It is recommended to clear it timely.
- “MaxAge” : d (required) The maxAge parameter indicates how long a response is allowed to remain in the cache before it is cleared due to invalidation. (D: days, h: hours, M: minutes, S: seconds, u: microseconds)
- “Timeout” : The duration string is used to specify the network timeout. If configured, the Angular Service Worker waits for a network response before using the cache, which is the network timeout.