docs(service-worker): improve docs related to SwUpdate APIs (#46960)

This commit improves documentation related to recently improved or
deprecated `SwUpdate` APIs in the following ways:

- Update [check-for-update.service.ts][1] to make use of the return
  value of [SwUpdate#checkForUpdate()][2].
- Update [prompt-update.service.ts][3] to not call
  [SwUpdate#activateUpdate()][4] and just reload the page.
- Update the [SwUpdate#activateUpdate()][4] API docs to explain that it
  is only useful if you want to update a client without reloading and
  that it can easily lead to version skew.
- Update [a code-snippet][5] to no longer be [hard-coded][6].

[1]: 9d9d05911d/aio/content/examples/service-worker-getting-started/src/app/check-for-update.service.ts (L16)
[2]: https://angular.io/api/service-worker/SwUpdate#checkForUpdate
[3]: 9d9d05911d/aio/content/examples/service-worker-getting-started/src/app/prompt-update.service.ts (L15)
[4]: https://angular.io/api/service-worker/SwUpdate#activateUpdate
[5]: 96c6139c9a/packages/service-worker/src/update.ts (L44-L54)
[6]: https://angular.io/guide/docs-style-guide#hard-coded-snippets

Fixes #43665

PR Close #46960
This commit is contained in:
George Kalpakas 2022-08-26 21:26:22 +03:00 committed by Andrew Kushnir
parent f8e78e3f9b
commit c905da12e2
4 changed files with 66 additions and 28 deletions

View file

@ -13,6 +13,13 @@ export class CheckForUpdateService {
const everySixHours$ = interval(6 * 60 * 60 * 1000);
const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
everySixHoursOnceAppIsStable$.subscribe(() => updates.checkForUpdate());
everySixHoursOnceAppIsStable$.subscribe(async () => {
try {
const updateFound = await updates.checkForUpdate();
console.log(updateFound ? 'A new version is available.' : 'Already on the latest version.');
} catch (err) {
console.error('Failed to check for updates:', err);
}
});
}
}

View file

@ -1,20 +1,40 @@
// #docplaster
import { Injectable } from '@angular/core';
import { SwUpdate, UpdateAvailableEvent } from '@angular/service-worker';
// #docregion sw-replicate-available
import { filter, map } from 'rxjs/operators';
// #enddocregion sw-replicate-available
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
function promptUser(event: UpdateAvailableEvent): boolean {
function promptUser(event: VersionReadyEvent): boolean {
return true;
}
// #docregion sw-activate
// #docregion sw-version-ready
@Injectable()
export class PromptUpdateService {
constructor(updates: SwUpdate) {
updates.available.subscribe(event => {
if (promptUser(event)) {
updates.activateUpdate().then(() => document.location.reload());
}
});
constructor(swUpdate: SwUpdate) {
swUpdate.versionUpdates
.pipe(filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'))
.subscribe(evt => {
if (promptUser(evt)) {
// Reload the page to update to the latest version.
document.location.reload();
}
});
// #enddocregion sw-version-ready
// #docregion sw-replicate-available
// ...
const updatesAvailable = swUpdate.versionUpdates.pipe(
filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'),
map(evt => ({
type: 'UPDATE_AVAILABLE',
current: evt.currentVersion,
available: evt.latestVersion,
})));
// #enddocregion sw-replicate-available
// #docregion sw-version-ready
}
}
// #enddocregion sw-activate
// #enddocregion sw-version-ready

View file

@ -64,16 +64,20 @@ Alternatively, you might want to define a different [registration strategy](api/
</div>
### Forcing update activation
### Updating to the latest version
If the current tab needs to be updated to the latest application version immediately, it can ask to do so with the `activateUpdate()` method:
You can update an existing tab to the latest version by reloading the page as soon as a new version is ready.
To avoid disrupting the user's progress, it is generally a good idea to prompt the user and let them confirm that it is OK to reload the page and update to the latest version:
<code-example header="prompt-update.service.ts" path="service-worker-getting-started/src/app/prompt-update.service.ts" region="sw-activate"></code-example>
<code-example header="prompt-update.service.ts" path="service-worker-getting-started/src/app/prompt-update.service.ts" region="sw-version-ready"></code-example>
<div class="alert is-important">
Calling `activateUpdate()` without reloading the page could break lazy-loading in a currently running app, especially if the lazy-loaded chunks use filenames with hashes, which change every version.
Therefore, it is recommended to reload the page once the promise returned by `activateUpdate()` is resolved.
Calling {@link SwUpdate#activateUpdate SwUpdate#activateUpdate()} updates a tab to the latest version without reloading the page, but this could break the application.
Updating without reloading can create a version mismatch between the [application shell](guide/glossary#app-shell) and other page resources, such as [lazy-loaded chunks](guide/glossary#lazy-loading), whose filenames may change between versions.
You should only use `activateUpdate()`, if you are certain it is safe for your specific use case.
</div>

View file

@ -40,18 +40,11 @@ export class SwUpdate {
*
* @deprecated Use {@link versionUpdates} instead.
*
* The of behavior `available` can be rebuild by filtering for the `VersionReadyEvent`:
* ```
* import {filter, map} from 'rxjs/operators';
* // ...
* const updatesAvailable = swUpdate.versionUpdates.pipe(
* filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY'),
* map(evt => ({
* type: 'UPDATE_AVAILABLE',
* current: evt.currentVersion,
* available: evt.latestVersion,
* })));
* ```
* The behavior of `available` can be replicated by using `versionUpdates` by filtering for the
* `VersionReadyEvent`:
*
* {@example service-worker-getting-started/src/app/prompt-update.service.ts
* region='sw-replicate-available'}
*/
readonly available: Observable<UpdateAvailableEvent>;
@ -124,6 +117,20 @@ export class SwUpdate {
* Updates the current client (i.e. browser tab) to the latest version that is ready for
* activation.
*
* In most cases, you should not use this method and instead should update a client by reloading
* the page.
*
* <div class="alert is-important">
*
* Updating a client without reloading can easily result in a broken application due to a version
* mismatch between the [application shell](guide/glossary#app-shell) and other page resources,
* such as [lazy-loaded chunks](guide/glossary#lazy-loading), whose filenames may change between
* versions.
*
* Only use this method, if you are certain it is safe for your specific use case.
*
* </div>
*
* @returns a promise that
* - resolves to `true` if an update was activated successfully
* - resolves to `false` if no update was available (for example, the client was already on the