docs(aio): add service worker guide content and update nav (#20021)
PR Close #20021
This commit is contained in:
parent
b841e0d530
commit
48300067fb
|
@ -0,0 +1,42 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -0,0 +1,27 @@
|
|||
# SwExample
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.0-beta.2.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
|
@ -0,0 +1,14 @@
|
|||
import { AppPage } from './app.po';
|
||||
|
||||
describe('sw-example App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"description": "Angular Service Worker",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<div style="text-align:center">
|
||||
<h1>
|
||||
Welcome to {{title}}!
|
||||
</h1>
|
||||
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
||||
</div>
|
||||
<h2>Here are some links to help you start: </h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'app'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('app');
|
||||
}));
|
||||
it('should render title in a h1 tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'app';
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
// #docregion sw-import
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
import { environment } from '../environments/environment';
|
||||
// #enddocregion sw-import
|
||||
|
||||
import { CheckForUpdateService } from './check-for-update.service';
|
||||
import { LogUpdateService } from './log-update.service';
|
||||
import { PromptUpdateService } from './prompt-update.service';
|
||||
|
||||
// #docregion sw-module
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : []
|
||||
],
|
||||
providers: [
|
||||
CheckForUpdateService,
|
||||
LogUpdateService,
|
||||
PromptUpdateService,
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion sw-module
|
|
@ -0,0 +1,17 @@
|
|||
import { SwUpdate } from '@angular/service-worker';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/interval';
|
||||
|
||||
function promptUser(event): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
// #docregion sw-check-update
|
||||
export class CheckForUpdateService {
|
||||
|
||||
constructor(updates: SwUpdate) {
|
||||
Observable.interval(6 * 60 * 60).subscribe(() => updates.checkForUpdate());
|
||||
}
|
||||
}
|
||||
// #enddocregion sw-check-update
|
|
@ -0,0 +1,17 @@
|
|||
import { SwUpdate } from '@angular/service-worker';
|
||||
|
||||
// #docregion sw-update
|
||||
export class LogUpdateService {
|
||||
|
||||
constructor(updates: SwUpdate) {
|
||||
updates.available.subscribe(event => {
|
||||
console.log('current version is', event.current);
|
||||
console.log('available version is', event.available);
|
||||
});
|
||||
updates.activated.subscribe(event => {
|
||||
console.log('old version was', event.previous);
|
||||
console.log('new version is', event.current);
|
||||
});
|
||||
}
|
||||
}
|
||||
// #enddocregion sw-update
|
|
@ -0,0 +1,18 @@
|
|||
import { SwUpdate } from '@angular/service-worker';
|
||||
|
||||
function promptUser(event): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
// #docregion sw-activate
|
||||
export class PromptUpdateService {
|
||||
|
||||
constructor(updates: SwUpdate) {
|
||||
updates.available.subscribe(event => {
|
||||
if (promptUser(event)) {
|
||||
updates.activateUpdate().then(() => document.location.reload());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// #enddocregion sw-activate
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SwExample</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
{
|
||||
"index": "/index.html",
|
||||
"assetGroups": [{
|
||||
"name": "app",
|
||||
"installMode": "prefetch",
|
||||
"resources": {
|
||||
"files": [
|
||||
"/favicon.ico",
|
||||
"/index.html"
|
||||
],
|
||||
"versionedFiles": [
|
||||
"/*.bundle.css",
|
||||
"/*.bundle.js",
|
||||
"/*.chunk.js"
|
||||
]
|
||||
}
|
||||
}, {
|
||||
"name": "assets",
|
||||
"installMode": "lazy",
|
||||
"updateMode": "prefetch",
|
||||
"resources": {
|
||||
"files": [
|
||||
"/assets/**"
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
|||
# Communicating with service workers
|
||||
|
||||
Importing `ServiceWorkerModule` into your `AppModule` doesn't just register the service worker, it also provides a few services you can use to interact with the service worker and control the caching of your app.
|
||||
|
||||
## `SwUpdate` service
|
||||
|
||||
The `SwUpdate` service gives you access to events that indicate when the service worker has discovered an available update for your app, or when it has activated such an update, meaning it is now serving content from that update to your app.
|
||||
|
||||
The `SwUpdate` service supports four separate operations:
|
||||
* Getting notified of *available* updates. These are new versions of the app which will be loaded if the page is refreshed.
|
||||
* Getting notified of update *activation*. This is when the service worker starts serving a new version of the app immediately.
|
||||
* Asking the service worker to check the server for new updates.
|
||||
* Asking the service worker to activate the latest version of the app for the current tab.
|
||||
|
||||
### Available & activated updates
|
||||
|
||||
The two update events are `Observable` properties of `SwUpdate`:
|
||||
|
||||
<code-example path="service-worker-getstart/src/app/log-update.service.ts" linenums="false" title="log-update.service.ts" region="sw-update"> </code-example>
|
||||
|
||||
|
||||
You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date.
|
||||
|
||||
### Checking for updates
|
||||
|
||||
It's possible to ask the service worker to check if any updates have been deployed to the server. You might choose to do this if you have a site that changes frequently or want updates to happen on a schedule.
|
||||
|
||||
Do this with the `checkForUpdate()` method:
|
||||
|
||||
<code-example path="service-worker-getstart/src/app/check-for-update.service.ts" linenums="false" title="check-for-update.service.ts" region="sw-check-update"> </code-example>
|
||||
|
||||
|
||||
This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `SwUpdate.available` event will indicate availability of a new version of the app.
|
||||
|
||||
### Forcing update activation
|
||||
|
||||
If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the `SwUpdate.activateUpdate()` method:
|
||||
|
||||
<code-example path="service-worker-getstart/src/app/prompt-update.service.ts" linenums="false" title="prompt-update.service.ts" region="sw-activate"> </code-example>
|
||||
|
||||
Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version.
|
|
@ -0,0 +1,161 @@
|
|||
{@a glob}
|
||||
|
||||
# Reference: Configuration file
|
||||
|
||||
The `src/ngsw-config.json` configuration file specifies which files and data URLs the Angular
|
||||
service worker should cache, and how it should update the cached files and data. The
|
||||
CLI processes the configuration file during `ng build --prod`. Manually, you can process
|
||||
it with the `ngsw-config` tool:
|
||||
|
||||
```sh
|
||||
$ ngsw-config dist src/ngswn-config.json /base/href
|
||||
```
|
||||
|
||||
The configuration file uses the JSON format. All file paths must begin with `/`, which is the deployment directory—usually `dist` in CLI projects).
|
||||
|
||||
Patterns use a limited glob format:
|
||||
|
||||
* `**` matches 0 or more path segments.
|
||||
* `*` matches exactly one path segment or filename segment.
|
||||
* The `!` prefix marks the pattern as being negative, meaning that only files that don't match the pattern will be included.
|
||||
|
||||
Example patterns:
|
||||
|
||||
* `/**/*.html` specifies all HTML files.
|
||||
* `/*.html` specifies only HTML files in the root.
|
||||
* `!/**/*.map` exclude all sourcemaps.
|
||||
|
||||
Each section of the configuration file is described below.
|
||||
|
||||
## `appData`
|
||||
|
||||
This section enables you to pass any data you want that describes this particular version of the app.
|
||||
The `SwUpdate` service includes that data in the update notifications. Many apps use this section to provide additional information for the display of UI popups, notifying users of the available update.
|
||||
|
||||
## `index`
|
||||
|
||||
Specifies the file that serves as the index page to satisfy navigation requests. Usually this is `/index.html`.
|
||||
|
||||
## `assetGroups`
|
||||
|
||||
*Assets* are resources that are part of the app version and they update along with the app. They can include resources loaded from the page's origin, as well as third-party resources loaded from CDNs and other external URLs. Not all such external URLs may be known at build time; URL patterns can be matched.
|
||||
|
||||
This field contains an array of asset groups, each of which defines a set of asset resources and the policy by which they are cached.
|
||||
|
||||
```json
|
||||
{
|
||||
"assetGroups": [{
|
||||
...
|
||||
}, {
|
||||
...
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Each asset group specifies both a group of resources and a policy that governs them. This policy determines when the resources are fetched and what happens when changes are detected.
|
||||
|
||||
Asset groups follow the Typescript interface shown here:
|
||||
|
||||
```typescript
|
||||
interface AssetGroup {
|
||||
name: string;
|
||||
installMode?: 'prefetch' | 'lazy';
|
||||
updateMode?: 'prefetch' | 'lazy';
|
||||
resources: {
|
||||
files?: string[];
|
||||
versionedFiles?: string[];
|
||||
urls?: string[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `name`
|
||||
|
||||
A `name` is mandatory. It is used to identify this particular group of assets between versions of the configuration.
|
||||
|
||||
### `installMode`
|
||||
|
||||
The `installMode` determines how these resources are initially cached. The `installMode` can be either of two values:
|
||||
|
||||
* `prefetch` tells the Angular service worker to fetch every single listed resource that it can while it's caching the current version of the app. This is bandwidth-intensive but ensures resources are available whenever they're requested, even if the browser is currently offline.
|
||||
|
||||
* `lazy` does not cache any of the resources up front. Instead, the Angular service worker only caches resources for which it receives requests. This is an on-demand caching mode. Resources that are never requested will not be cached. This is useful for things like images at different resolutions, so the service worker only caches the correct assets for the particular screen and orientation.
|
||||
|
||||
### `updateMode`
|
||||
|
||||
For resources already in the cache, the `updateMode` determines the caching behavior when a new version of the app is discovered. Any resources in the group that have changed since the previous version are updated in accordance with `updateMode`.
|
||||
|
||||
* `prefetch` tells the service worker to download and cache the changed resources immediately.
|
||||
|
||||
* `lazy` tells the service worker to not cache those resources. Instead it treats them as unrequested and waits until they're requested again before updating them. An `updateMode` of `lazy` is only valid if the `installMode` is also `lazy`.
|
||||
|
||||
### `resources`
|
||||
|
||||
This section describes the resources to cache, broken up into three groups.
|
||||
|
||||
* `files` lists patterns that match files in the distribution directory. These can be single files or glob-like patterns that match a number of files.
|
||||
|
||||
* `versionedFiles` is like `files`, but should be used for build artifacts that already include a hash in the filename, which is used for cache busting. The Angular service worker can optimize some aspects of its operation if it can assume file contents are immutable.
|
||||
|
||||
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.
|
||||
|
||||
## `dataGroups`
|
||||
|
||||
Unlike asset resources, data requests are not versioned along with the app. They're cached according to manually-configured policies that are more useful for situations such as API requests and other data dependencies.
|
||||
|
||||
Data groups follow this Typescript interface:
|
||||
|
||||
```typescript
|
||||
export interface DataGroup {
|
||||
name: string;
|
||||
urls: string[];
|
||||
version?: number;
|
||||
cacheConfig: {
|
||||
maxSize: number;
|
||||
maxAge: string;
|
||||
timeout?: string;
|
||||
strategy?: 'freshness' | 'performance';
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `name`
|
||||
Similar to `assetGroups`, every data group has a `name` which uniquely identifies it.
|
||||
|
||||
### `urls`
|
||||
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.
|
||||
|
||||
### `version`
|
||||
Occasionally APIs change formats in a way that is not backward-compatible. A new version of the app may not be compatible with the old API format, and thus may not be compatible with existing cached resources from that API.
|
||||
|
||||
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries—those from previous versions—should be discarded.
|
||||
|
||||
`version` is an integer field, and it defaults to `0`.
|
||||
|
||||
### `cacheConfig`
|
||||
This section defines the policy by which matching requests will be cached.
|
||||
|
||||
#### `maxSize`
|
||||
(required) The maximum number of entries, or responses, in the cache. Open-ended caches can grow in unbounded ways and eventually exceed storage quotas, calling for eviction.
|
||||
|
||||
#### `maxAge`
|
||||
(required) The `maxAge` paramter indicates how long responses are allowed to remain in the cache before being considered invalid and evicted. `maxAge` is a duration string, using the following unit suffixes:
|
||||
|
||||
* `d`: days
|
||||
* `h`: hours
|
||||
* `m`: minutes
|
||||
* `s`: seconds
|
||||
* `u`: milliseconds
|
||||
|
||||
For example, the string `3d12h` will cache content for up to three and a half days.
|
||||
|
||||
#### `timeout`
|
||||
This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so.
|
||||
|
||||
#### `strategy`
|
||||
|
||||
The Angular service worker can use either of two caching strategies for data resources.
|
||||
|
||||
* `performance`, the default, optimizes for responses that are as fast as possible. If a resource exists in the cache, the cached version is used. This allows for some staleness, depending on the `maxAge`, in exchange for better performance. This is suitable for resources that don't change often; for example, user avatar images.
|
||||
|
||||
* `freshness` optimizes for currency of data, preferentially fetching requested data from the network. Only if the network times out, according to `timeout`, does the request fall back to the cache. This is useful for resources that change frequently; for example, account balances.
|
|
@ -0,0 +1,198 @@
|
|||
# DevOps: Angular service worker in production
|
||||
|
||||
This section is for anyone who is responsible for deploying and supporting production apps that use the Angular service worker. It explains how the Angular service worker fits into the larger production environment, the service worker's behavior under various conditions, and available recourses and failsafes if the service worker's behavior becomes problematic.
|
||||
|
||||
## Service worker and caching of app resources
|
||||
|
||||
Conceptually, you can imagine the Angular service worker as a forward cache or a CDN edge that is installed in the end user's web browser. The service worker's job is to satisfy requests made by the Angular app for resources or data from a local cache, without needing to wait for the network. Like any cache, it has rules for how content is expired and updated.
|
||||
|
||||
{@a versions}
|
||||
|
||||
### Versions of apps
|
||||
|
||||
In the context of an Angular service worker, a "version" is a collection of resources that represent a specific build of the Angular app. Whenever a new build of the app is deployed, the service worker treats that build as a new version of the app. This is true even if only a single file was updated. At any given time, the service worker may have multiple versions of the app in its cache, and it may be serving them simultaneously. For more information, see the [App tabs](guide/service-worker-devops#tabs) section below.
|
||||
|
||||
To preserve app integrity, the Angular service worker groups all files into a version together. The files grouped into a version usually includes application's HTML, JS, and CSS files. Grouping of these files is essential for integrity because HTML, JS, and CSS files frequently refer to each other and depend on specific content. For example, an `index.html` file might have a `<script>` tag that references `bundle.js`, and it might attempt to call a function `startApp()` from within that script. Any time this version of the index file is served, the corresponding `bundle.js` must be served with it. For example, assume that the `startApp()` function is renamed to `runApp()` in both files. In this scenario, it is not valid to serve the old index (which calls `startApp()`) along with the new bundle (which defines `runApp()`).
|
||||
|
||||
In Angular apps, this file integrity is especially important due to lazy loading. A JS bundle may reference many lazy chunks, and the filenames of the lazy chunks are unique to the particular build of the app. If a running app at version X attempts to load a lazy chunk, but the server has updated to version X + 1 already, the lazy loading operation will fail.
|
||||
|
||||
The version identifier of the app is determined by the contents of all resources, and it changes if any of them change. In practice, the version is determined by the contents of the `ngsw.json` file, which includes hashes for all known content. If any of the cached files change, the file's hash will change in `ngsw.json`, causing the Angular service worker to treat the active set of files as a new version.
|
||||
|
||||
With the versioning behavior of the Angular service worker, an application server can ensure that the Angular app always has a consistent set of files.
|
||||
|
||||
#### Update checks
|
||||
|
||||
Every time the Angular service worker starts, it checks for updates to the app by looking for updates to the `ngsw.json` manifest.
|
||||
|
||||
Note that the service worker starts periodically throughout the usage of the app because the web browser terminates the service worker if the page is idle beyond a given timeout.
|
||||
|
||||
### Resource integrity
|
||||
|
||||
One of the potential side effects of long caching is inadvertently caching an invalid resource. In a normal HTTP cache, a hard refresh or cache expiration limits the negative effects of caching an invalid file. A service worker ignores such constraints and effectively long caches the entire app. It is essential, then, that the service worker get the correct content.
|
||||
<!-- JF--In case my edit of "gets" to "get" needs clarification (it may not, but playing it safe): the subordinate clause here has to be in the subjunctive because the main clause is an imposition of necessity. -->
|
||||
|
||||
To ensure that it gets the correct content, the Angular service worker validates the hashes of all resources for which it has a hash. Typically for a CLI app, this is everything in the `dist` directory covered by the user's `src/ngsw-config.json` configuration.
|
||||
|
||||
If a particular file fails validation, the Angular service worker attempts to re-fetch the content using a "cache-busting" URL parameter to eliminate the effects of browser or intermediate caching. If that content also fails validation, the service worker considers the entire version of the app to be invalid, and it stops serving the app. If necessary, the service worker enters a safe mode where requests fall back on the network, opting not to use its cache if the risk of serving invalid, broken, or outdated content is high.
|
||||
|
||||
Hash mismatches can occur for a variety of reasons:
|
||||
|
||||
* Caching layers in between the origin server and the end user could serve stale content.
|
||||
* A non-atomic deployment could result in the Angular service worker having visibility of partially updated content.
|
||||
* Errors during the build process could result in updated resources without `ngsw.json` being updated, or the reverse (updated `ngsw.json` without updated resources).
|
||||
|
||||
#### Unhashed content
|
||||
|
||||
The only resources that have hashes in the `ngsw.json` manifest are resources that were present in the `dist` directory at the time the manifest was built. Other resources, especially those loaded from CDNs, have content that is unknown at build time or updates more frequently than the app is deployed.
|
||||
|
||||
If the Angular service worker does not have a hash to validate a given resource, it will still cache its contents, but it will honor the HTTP caching headers by using a policy of "stale while revalidate." That is, when HTTP caching headers for a cached resource indicate that the resource has expired, the Angular service worker continues to serve the content, and it attempts to refresh the resource in the background. This way, broken unhashed resources do not remain in the cache beyond their configured lifetimes.
|
||||
|
||||
{@a tabs}
|
||||
|
||||
### App tabs
|
||||
|
||||
It can be problematic for an app if the version of resources it's receiving changes suddenly or without warning. See the [Versions](guide/service-worker-devops#versions) section above for a description of such issues.
|
||||
|
||||
The Angular service worker provides a guarantee: a running app will continue to run the same version of the app. If another instance of the app is opened in a new web browser tab, then the most current version of the app is served. As a result, that new tab can be running a different version of the app than the original tab.
|
||||
|
||||
It's important to note that this guarantee is **stronger** than that provided by the normal web deployment model. Without a service worker, there is no guarantee that code lazily loaded later in a running app is from the same version as the initial code for the app.
|
||||
|
||||
There are a few limited reasons why the Angular service worker might change the version of a running app. Some of them are error conditions:
|
||||
|
||||
* The current version becomes invalid due to a failed hash.
|
||||
* An unrelated error causes the service worker to enter safe mode (temporary deactivation).
|
||||
|
||||
The Angular service worker is aware of which versions are in use at any given moment, and it will clean up versions when no tab is using them.
|
||||
|
||||
Others are normal events:
|
||||
|
||||
* The page is reloaded/refreshed.
|
||||
* The page requests an update be immediately activated via the `SwUpdate` service.
|
||||
|
||||
### Service worker updates
|
||||
|
||||
The Angular service worker is a small script that runs in end user web browsers. From time to time, it will be updated with bug fixes and feature improvements.
|
||||
|
||||
The Angular service worker is downloaded when the app is first opened and when the app is accessed after a period of inactivity. If the service worker has changed, the service worker will be updated in the background.
|
||||
|
||||
Most updates to the Angular service worker are transparent to the app—the old caches are still valid, and content is still served normally. However, occasionally a bugfix or feature in the Angular service worker requires the invalidation of old caches. In this case, the app will be refreshed transparently from the network.
|
||||
|
||||
|
||||
## Debugging the Angular service worker
|
||||
|
||||
Occasionally, it may be necessary to examine Angular service worker in a running state, to investigate issues, or to ensure that it is operating as designed. Browsers provide built-in tools for debugging service workers, and the Angular service worker itself includes useful debugging features.
|
||||
|
||||
### Locating and analyzing debugging information
|
||||
|
||||
The Angular service worker exposes debugging information under the `ngsw/` virtual directory. Currently the single exposed URL is `ngsw/state`. Here is an example of this debug page's contents:
|
||||
|
||||
```
|
||||
NGSW Debug Info:
|
||||
|
||||
Driver state: NORMAL ((nominal))
|
||||
Latest manifest hash: eea7f5f464f90789b621170af5a569d6be077e5c
|
||||
Last update check: never
|
||||
|
||||
=== Version eea7f5f464f90789b621170af5a569d6be077e5c ===
|
||||
|
||||
Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100f65
|
||||
|
||||
=== Idle Task Queue ===
|
||||
Last update tick: 1s496u
|
||||
Last update run: never
|
||||
Task queue:
|
||||
* init post-load (update, cleanup)
|
||||
|
||||
Debug log:
|
||||
```
|
||||
|
||||
#### Driver state
|
||||
|
||||
The first line indicates the driver state:
|
||||
|
||||
```
|
||||
Driver state: NORMAL ((nominal))
|
||||
```
|
||||
|
||||
`NORMAL` indicates that the service worker is operating normally, and is not in a degraded state.
|
||||
|
||||
There are two possible degraded states:
|
||||
|
||||
* `EXISTING_CLIENTS_ONLY`: the service worker does not have a clean copy of the latest known version of the app. Older cached versions are safe to use, so existing tabs continue to run from cache, but new loads of the app will be served from network.
|
||||
|
||||
* `SAFE_MODE`: the service worker cannot guarantee the safety of using cached data. Either an unexpected error occurred or all cached versions are invalid. All traffic will be served from the network, running as little service worker code as possible.
|
||||
|
||||
In both cases, the parenthetical annotation provides the error that caused the service worker to enter the degraded state.
|
||||
|
||||
|
||||
#### Latest mainfest hash
|
||||
|
||||
```
|
||||
Latest manifest hash: eea7f5f464f90789b621170af5a569d6be077e5c
|
||||
```
|
||||
|
||||
This is the SHA1 hash of the most up-to-date version of the app that the service worker knows about.
|
||||
|
||||
|
||||
#### Last update check
|
||||
|
||||
```
|
||||
Last update check: never
|
||||
```
|
||||
|
||||
This indicates the last time the service worker checked for a new version (an update) of the app. `never` indicates that the service worker has never checked for an update.
|
||||
|
||||
In this example debug file, the update check is currently scheduled, as explained the next section.
|
||||
|
||||
#### Version
|
||||
|
||||
```
|
||||
=== Version eea7f5f464f90789b621170af5a569d6be077e5c ===
|
||||
|
||||
Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100f65
|
||||
```
|
||||
|
||||
In this example, the service worker has one version of the app cached, being used to serve two different tabs. Note that this version hash is the "latest manifest hash" listed above. Both clients are on the latest version. Each client is listed by its ID from the `Clients` API in the browser.
|
||||
|
||||
|
||||
#### Idle task queue
|
||||
|
||||
```
|
||||
=== Idle Task Queue ===
|
||||
Last update tick: 1s496u
|
||||
Last update run: never
|
||||
Task queue:
|
||||
* init post-load (update, cleanup)
|
||||
```
|
||||
|
||||
The Idle Task Queue is the queue of all pending tasks that happen in the background in the service worker. If there are any tasks in the queue, they are listed with a description. In this example, the service worker has one such task scheduled, a post-initialization operation involving an update check and cleanup of stale caches.
|
||||
|
||||
The last update tick/run counters give the time since specific events happened related to the idle queue. The "Last update run" counter shows the last time idle tasks were actually executed. "Last update tick" shows the time since the last event after which the queue might be processed.
|
||||
|
||||
|
||||
#### Debug log
|
||||
|
||||
```
|
||||
Debug log:
|
||||
```
|
||||
|
||||
Errors that occur within the service worker will be logged here.
|
||||
|
||||
|
||||
### Developer Tools
|
||||
|
||||
Browsers such as Chrome provide developer tools for interacting with service workers. Such tools can be powerful when used properly, but there are a few things to keep in mind.
|
||||
|
||||
* When using developer tools, the service worker is kept running in the background and never restarts. For the Angular service worker, this means that update checks to the app will generally not happen.
|
||||
|
||||
* If you look in the Cache Storage viewer, the cache is frequently out of date. Right click the Cache Storage title and refresh the caches.
|
||||
|
||||
Stopping and starting the service worker in the Service Worker pane triggers a check for updates.
|
||||
|
||||
## Failsafe
|
||||
|
||||
Like any complex system, bugs or broken configurations can cause the Angular service worker to act in unforeseen ways. While its design attempts to minimize the impact of such problems, the Angular service worker contains a failsafe mechanism in case an administrator ever needs to deactivate the service worker quickly.
|
||||
|
||||
To deactivate the service worker, remove or rename the `ngsw-config.json` file. When the service worker's request for `ngsw.json` returns a `404`, then the service worker removes all of its caches and unregisters itself, essentially self-destructing.
|
||||
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
# Getting started
|
||||
|
||||
Beginning in Angular 5.0.0, you can easily enable Angular service worker support in any CLI project. This document explains how to enable Angular service worker support in new and existing projects. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
|
||||
|
||||
You can run the example <live-example>live in the browser </live-example>.
|
||||
|
||||
|
||||
## Adding a service worker to a new application
|
||||
|
||||
If you're generating a new CLI project, you can instruct the CLI to set up the Angular service worker as part of creating the project. To do so, add the `--service-worker` flag to the `ng new` command:
|
||||
|
||||
```sh
|
||||
$ ng new --service-worker
|
||||
```
|
||||
|
||||
To learn about what the `--service-worker` flag does to enable Angular service workers, see the following section about adding a service worker to an existing application. The `--service-worker` flag performs those steps for you as part of setting up the new CLI project.
|
||||
|
||||
## Adding a service worker to an existing application
|
||||
|
||||
To add a service worker to an existing application:
|
||||
|
||||
1. Add the service worker package.
|
||||
2. Enable service worker build support in the CLI.
|
||||
3. Import and register the service worker.
|
||||
4. Create the service worker configuration file, which specifies the caching behaviors and other settings.
|
||||
5. Build the project.
|
||||
|
||||
These steps are explained in more detail below.
|
||||
|
||||
|
||||
#### Step 1: Add the service worker package
|
||||
|
||||
Add the package `@angular/service-worker`, using the yarn utility as shown here:
|
||||
|
||||
```sh
|
||||
$ yarn add @angular/service-worker
|
||||
```
|
||||
|
||||
#### Step 2: Enable service worker build support in the CLI
|
||||
|
||||
To enable the Angular service worker, the CLI must generate an Angular service worker manifest at build time. To cause the CLI to generate the manifest for an existing project, set the `serviceWorker` flag to `true` in the project's `.angular-cli.json` file as shown here:
|
||||
|
||||
```sh
|
||||
$ ng set apps.0.serviceWorker=true
|
||||
```
|
||||
|
||||
#### Step 3: Import and register the service worker
|
||||
|
||||
To import and register the Angular service worker:
|
||||
|
||||
1. Open `src/app/app.module.ts` in an editor. This is the application's root module.
|
||||
|
||||
2. At the top of the file, add an instruction to import `ServiceWorkerModule`.
|
||||
|
||||
<code-example path="service-worker-getstart/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-import"> </code-example>
|
||||
|
||||
|
||||
3. Add `ServiceWorkerModule` to the `@NgModule` imports section.
|
||||
|
||||
It's better to do this with a conditional so that the service worker is only registered for a production application.
|
||||
|
||||
Use the `register()` helper to take care of registering the service worker for you.
|
||||
|
||||
<code-example path="service-worker-getstart/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-module"> </code-example>
|
||||
|
||||
|
||||
The file `ngsw-worker.js` is the name of the prebuilt service worker script, which the CLI copies into `dist/` to deploy along with your server.
|
||||
|
||||
#### Step 4: Create the configuration file, ngsw-config.json
|
||||
|
||||
The Angular CLI needs a service worker configuration file, called `ngsw-config.json`. The configuration file controls how the service worker caches files and data
|
||||
resources.
|
||||
|
||||
You can begin with the boilerplate version from the CLI, which configures sensible defaults for most applications.
|
||||
|
||||
Alternately, save the following as `src/ngsw-config.json`:
|
||||
|
||||
<code-example path="service-worker-getstart/src/ngsw-config.json" linenums="false" title="src/ngsw-config.json"> </code-example>
|
||||
|
||||
#### Step 5: Build the project
|
||||
|
||||
Finally, build the project:
|
||||
|
||||
```sh
|
||||
$ ng build --prod
|
||||
```
|
||||
|
||||
The CLI project is now set up to use the Angular service worker.
|
||||
|
||||
|
||||
## Service worker in action: a tour
|
||||
|
||||
This section demonstrates a service worker in action,
|
||||
using an example application.
|
||||
|
||||
### Serving with http-server
|
||||
|
||||
After building the project, it's time to serve it.
|
||||
|
||||
`ng serve` does not work with service workers, you must use a real HTTP server to test your project locally. It's a good idea to test on a dedicated port.
|
||||
|
||||
```sh
|
||||
$ cd dist
|
||||
$ http-server -p 8080
|
||||
```
|
||||
|
||||
### Initial load
|
||||
|
||||
With the server running, you can point your browser at http://localhost:8080/. Your application should load normally.
|
||||
|
||||
Tip: When testing Angular service workers, it's a good idea to use an incognito or private window in your browser, to ensure the service worker doesn't end up reading from a previous leftover state, which can cause unexpected behavior.
|
||||
|
||||
### Simulating a network issue
|
||||
|
||||
To simulate a network issue, disable network interaction for your application. In Chrome:
|
||||
|
||||
1. Select **Tools** > **Developer Tools** (from the Chrome menu located at thte top-right corner).
|
||||
2. Go to the **Network tab**.
|
||||
3. Check the **Offline box**.
|
||||
|
||||
!["The offline checkbox in the Network tab is checked"](generated/images/guide/service-worker/offline-checkbox.png)
|
||||
|
||||
|
||||
Now the app has no access to network interaction.
|
||||
|
||||
For applications that do not use the Angular service worker, refreshing now would display Chrome's Internet disconnected page that says "There is no Internet connection.".
|
||||
|
||||
With the addition of an Angular service worker, the application behavior changes. On a refresh, the page loads normally.
|
||||
|
||||
If you look at the Network tab, you can verify that the service worker is active.
|
||||
![Requests are marked as "from Service Worker"](generated/images/guide/service-worker/sw-active.png)
|
||||
|
||||
Notice that under the "Size" column, the requests state is `(from ServiceWorker)`. This means that the resources are not being loaded from the network. Instead, they are being loaded from the service worker's cache.
|
||||
|
||||
|
||||
### What's being cached?
|
||||
|
||||
Notice that all of the files the browser needs to render this application are cached. The `ngsw-config.json` boilerplate configuration is set up to cache the specific resources used by the CLI:
|
||||
|
||||
* index.html.
|
||||
* favicon.ico.
|
||||
* Build artifacts (JS & CSS bundles).
|
||||
* Anything under `assets`.
|
||||
|
||||
### Making changes to your application
|
||||
|
||||
Now that you've seen how service workers cache your application, the
|
||||
next step is understanding how updates work.
|
||||
|
||||
1. If you're testing in an incognito window, open a second blank tab. This will keep the incognito and the cache state alive during your test.
|
||||
|
||||
2. Close the application tab (but not the window). This should also close the Developer Tools.
|
||||
|
||||
3. Shut down `http-server`.
|
||||
|
||||
Next, make a change to the application, and watch the service worker install the update.
|
||||
|
||||
4. Open `src/app/app.component.html` for editing.
|
||||
|
||||
5. Change the text `Welcome to {{title}}!` to `Bienvenue à {{title}}!`.
|
||||
|
||||
6. Build and run the server again:
|
||||
|
||||
```sh
|
||||
$ ng build --prod
|
||||
$ cd dist
|
||||
$ http-server -p 8080
|
||||
```
|
||||
|
||||
### Updating your application in the browser
|
||||
|
||||
Now look at how the browser and service worker handle the updated application.
|
||||
|
||||
1. Open http://localhost:8080 again in the same window. What happens?
|
||||
|
||||
![It still says "Welcome to app!](generated/images/guide/service-worker/welcome-msg-en.png)
|
||||
|
||||
What went wrong? Nothing, actually. The Angular service worker is doing its job and serving the version of the application that it has **installed**, even though there is an update available. The service worker doesn't wait to check for updates before it serves the application that it has cached, because that would be slow.
|
||||
|
||||
If you look at the `http-server` logs, you can see the service worker requesting `/ngsw.json`. This is how the service worker checks for updates.
|
||||
|
||||
2. Refresh the page.
|
||||
|
||||
![The text has changed to say "Bienvenue à app!"](generated/images/guide/service-worker/welcome-msg-fr.png)
|
||||
|
||||
The service worker installed the updated version of your app *in the background*, and the next time the page was loaded or reloaded, the service worker switched to the latest version.
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# Introduction to Angular service workers
|
||||
|
||||
Service workers augment the traditional web deployment model and empower applications to deliver a user experience with the reliability and performance on par with natively-installed code.
|
||||
|
||||
At its simplest, a service worker is a script that runs in the web browser and manages caching for an application.
|
||||
|
||||
Service workers function as a network proxy. They intercept all outgoing HTTP requests made by the application and can choose how to respond to them. For example, they can query a local cache and deliver a cached response if one is available. Proxying isn't limited to requests made through programmatic APIs, such as `fetch`; it also includes resources referenced in HTML and even the initial request to `index.html`. Service worker-based caching is thus completely programmable and doesn't rely on server-specified caching headers.
|
||||
|
||||
Unlike the other scripts that make up an application, such as the Angular app bundle, the service worker is preserved after the user closes the tab. The next time that browser loads the application, the service worker loads first, and can intercept every request for resources to load the application. If the service worker is designed to do so, it can *completely satisfy the loading of the application, without the need for the network*.
|
||||
|
||||
Even across a fast reliable network, round-trip delays can introduce significant latency when loading the application. Using a service worker to reduce dependency on the network can significantly improve the user experience.
|
||||
|
||||
|
||||
## Service workers in Angular
|
||||
|
||||
Angular applications, as single-page applications, are in a prime position to benefit from the advantages of service workers. Starting with version 5.0.0, Angular ships with a service worker implementation. Angular developers can take advantage of this service worker and benefit from the increased reliability and performance it provides, without needing to code against low-level APIs.
|
||||
|
||||
Angular's service worker is designed to optimize the end user experience of using an application over a slow or unreliable network connection, while also minimizing the risks of serving outdated content.
|
||||
|
||||
The Angular service worker's behavior follows that design goal:
|
||||
|
||||
* Caching an application is like installing a native application. The application is cached as one unit, and all files update together.
|
||||
* A running application continues to run with the same version of all files. It does not suddenly start receiving cached files from a newer version, which are likely incompatible.
|
||||
* When users refresh the application, they see the latest fully cached version. New tabs load the latest cached code.
|
||||
* Updates happen in the background, relatively quickly after changes are published. The previous version of the application is served until an update is installed and ready.
|
||||
* The service worker conserves bandwidth when possible. Resources are only downloaded if they've changed.
|
||||
|
||||
To support these behaviors, the Angular service worker loads a *manifest* file from the server. The manifest describes the resources to cache and includes hashes of every file's contents. When an update to the application is deployed, the contents of the manifest change, informing the service worker that a new version of the application should be downloaded and cached. This manifest is generated from a user-provided configuration file called `ngsw-config.json`, by using a build tool such as the Angular CLI.
|
||||
|
||||
Installing the Angular service worker is as simple as including an `NgModule`. In addition to registering the Angular service worker with the browser, this also makes a few services available for injection which interact with the service worker and can be used to control it. For example, an application can ask to be notified when a new update becomes available, or an application can ask the service worker to check the server for available updates.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To use Angular service workers, you must have the following Angular and CLI versions:
|
||||
|
||||
* Angular 5.0.0 or later.
|
||||
* Angular CLI 1.6.0 or later.
|
||||
|
||||
Your application must run in a web browser that supports service workers. Currently, the latest versions of Chrome and Firefox are supported. To learn about other browsers that are service worker ready, see the [Can I Use](http://caniuse.com/#feat=serviceworkers) page.
|
||||
|
||||
## Related resources
|
||||
|
||||
For more information about service workers in general, see [Service workers: an Introduction](https://developers.google.com/web/fundamentals/primers/service-workers/).
|
||||
|
||||
For more information about browser support, see the [browser support](https://developers.google.com/web/fundamentals/primers/service-workers/#browser_support) section of [Service workers: an Introduction](https://developers.google.com/web/fundamentals/primers/service-workers/), Jake Archibald's [Is Serviceworker ready](https://jakearchibald.github.io/isserviceworkerready/), and
|
||||
[Can I Use](http://caniuse.com/#feat=serviceworkers).
|
||||
|
||||
The remainder of this Angular documentation specifically addresses the Angular implementation of service workers.
|
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
|
@ -276,6 +276,38 @@
|
|||
"title": "Routing & Navigation",
|
||||
"tooltip": "Discover the basics of screen navigation with the Angular Router."
|
||||
},
|
||||
{
|
||||
"title": "Service Workers",
|
||||
"tooltip": "Angular service workers: Controlling caching of application resources.",
|
||||
"children": [
|
||||
{
|
||||
"url": "guide/service-worker-intro",
|
||||
"title": "Introduction",
|
||||
"tooltip": "Angular's implementation of service workers improves user experience with slow or unreliable network connectivity."
|
||||
},
|
||||
{
|
||||
"url": "guide/service-worker-getstart",
|
||||
"title": "Getting Started",
|
||||
"tooltip": "Enabling the service worker in a CLI project and observing behavior in the browser."
|
||||
},
|
||||
{
|
||||
"url": "guide/service-worker-comm",
|
||||
"title": "Communication",
|
||||
"tooltip": "Services that enable you to interact with an Angular service worker."
|
||||
},
|
||||
{
|
||||
"url": "guide/service-worker-devops",
|
||||
"title": "Service Workers in Production",
|
||||
"tooltip": "Information about running applications with service workers, including application update management, debugging, and killing applications."
|
||||
},
|
||||
{
|
||||
"url": "guide/service-worker-configref",
|
||||
"title": "Reference: Configuration File",
|
||||
"tooltip": "The ngsw-config.json configuration file controls service worker caching behavior."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"url": "guide/testing",
|
||||
"title": "Testing",
|
||||
|
|
Loading…
Reference in New Issue