The Complete Guide to Service Worker and PWA in Angular

Angular service worker introduction

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. Adding a service worker to an Angular application is one of the steps for turning an application into a Progressive Web App (also known as a PWA).

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 CLI-generated configuration file called ngsw-config.json.

Installing the Angular service worker is as simple as including an [NgModule](https://angular.io/api/core/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 make use of all the features of Angular service worker, use the latest versions of Angular and the Angular CLI.

In order for service workers to be registered, the app must be accessed over HTTPS, not HTTP. Browsers ignore service workers on pages that are served over an insecure connection. The reason is that service workers are quite powerful, so extra care needs to be taken to ensure the service worker script has not been tampered with.

There is one exception to this rule: to make local development easier, browsers do not require a secure connection when accessing an app on localhost.

Browser support

To benefit from the Angular service worker, your app must run in a web browser that supports service workers in general. Currently, service workers are supported in the latest versions of Chrome, Firefox, Edge, Safari, Opera, UC Browser (Android version) and Samsung Internet. Browsers like IE and Opera Mini do not support service workers.

If the user is accessing your app via a browser that does not support service workers, the service worker is not registered and related behavior such as offline cache management and push notifications does not happen. More specifically:

  • The browser does not download the service worker script and ngsw.json manifest file.
  • Active attempts to interact with the service worker, such as calling [SwUpdate.checkForUpdate()](https://angular.io/api/service-worker/SwUpdate#checkForUpdate), return rejected promises.
  • The observable events of related services, such as [SwUpdate.available](https://angular.io/api/service-worker/SwUpdate#available), are not triggered.

It is highly recommended that you ensure that your app works even without service worker support in the browser. Although an unsupported browser ignores service worker caching, it will still report errors if the app attempts to interact with the service worker. For example, calling [SwUpdate.checkForUpdate()](https://angular.io/api/service-worker/SwUpdate#checkForUpdate) will return rejected promises. To avoid such an error, you can check whether the Angular service worker is enabled using [SwUpdate.isEnabled](https://angular.io/api/service-worker/SwUpdate#isEnabled)().


Getting started with service workers

This document explains how to enable Angular service worker support in projects that you created with the Angular CLI. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.

Adding a service worker to your project

To set up the Angular service worker in your project, use the CLI command ng add @angular/pwa. It takes care of configuring your app to use service workers by adding the service-worker package along with setting up the necessary support files.

ng add @angular/pwa --project *project-name*

The above command completes the following actions:

  1. Adds the @angular/service-worker package to your project.
  2. Enables service worker build support in the CLI.
  3. Imports and registers the service worker in the app module.
  4. Updates the index.html file:
  • Includes a link to add the manifest.json file.
  • Adds meta tags for theme-color.
  1. Installs icon files to support the installed Progressive Web App (PWA).
  2. Creates the service worker configuration file called [ngsw-config.json](https://angular.io/guide/service-worker-config), which specifies the caching behaviors and other settings.

Now, build the project:

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

Because ng serve does not work with service workers, you must use a separate HTTP server to test your project locally. You can use any HTTP server. The example below uses the http-server package from npm. To reduce the possibility of conflicts and avoid serving stale content, test on a dedicated port and disable caching.

To serve the directory containing your web files with http-server, run the following command:

http-server -p 8080 -c-1 dist/<project-name>

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.

Note: If you are not using HTTPS, the service worker will only be registered when accessing the app on localhost.

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 the top right corner).
  2. Go to the Network tab.
  3. Check the Offline box.

The offline checkbox in the Network tab is checked

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 ServiceWorker

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 and CSS bundles).
  • Anything under assets.
  • Images and fonts directly under the configured outputPath (by default ./dist/<project-name>/) or resourcesOutputPath. See [ng build](https://angular.io/cli/build) for more information about these options.

Pay attention to two key points:

  1. The generated ngsw-config.json includes a limited list of cachable fonts and images extentions. In some cases, you might want to modify the glob pattern to suit your needs.
  2. If resourcesOutputPath or assets paths are modified after the generation of configuration file, you need to change the paths manually in ngsw-config.json.

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.
  4. Next, make a change to the application, and watch the service worker install the update.
  5. Open src/app/app.component.html for editing.
  6. Change the text Welcome to {{title}}! to Bienvenue à {{title}}!.
  7. Build and run the server again:
ng build --prod
http-server -p 8080 -c-1 dist/<project-name>

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 Service Workers!

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. In the interest of speed, the service worker doesn’t wait to check for updates before it serves the application that it has cached.

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.

  1. Refresh the page.

The text has changed to say Bienvenue à app!

The service worker installed the updated version of your app in the background, and the next time the page is loaded or reloaded, the service worker switches to the latest version.


App shell

App shell is a way to render a portion of your application via a route at build time. It can improve the user experience by quickly launching a static rendered page (a skeleton common to all pages) while the browser downloads the full client version and switches to it automatically after the code loads.

This gives users a meaningful first paint of your application that appears quickly because the browser can simply render the HTML and CSS without the need to initialize any JavaScript.

Step 1: Prepare the application

You can do this with the following CLI command:

      ng new my-app --routing

For an existing application, you have to manually add the [RouterModule](https://angular.io/api/router/RouterModule) and defining a <[router-outlet](https://angular.io/api/router/RouterOutlet)> within your application.

Step 2: Create the app shell

Use the CLI to automatically create the app shell.

      ng generate app-shell
  • client-project takes the name of your client application.

After running this command you will notice that the angular.json configuration file has been updated to add two new targets, with a few other changes.

"server": {
  "builder": "@angular-devkit/build-angular:server",
  "options": {
    "outputPath": "dist/my-app-server",
    "main": "src/main.server.ts",
    "tsConfig": "tsconfig.server.json"
  }
},
"app-shell": {
  "builder": "@angular-devkit/build-angular:app-shell",
  "options": {
    "browserTarget": "my-app:build",
    "serverTarget": "my-app:server",
    "route": "shell"
  },
  "configurations": {
    "production": {
      "browserTarget": "my-app:build:production",
      "serverTarget": "my-app:server:production"
    }
  }
}

Step 3: Verify the app is built with the shell content

Use the CLI to build the app-shell target.

      ng run my-app:app-shell

Or to use the production configuration.

      ng run my-app:app-shell:production

To verify the build output, open dist/my-app/index.html. Look for default text app-shell works! to show that the app shell route was rendered as part of the output.


Service worker communication

Importing [ServiceWorkerModule](https://angular.io/api/service-worker/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](https://angular.io/api/service-worker/SwUpdate) service supports four separate operations:

  • Getting notified of available updates. These are new versions of the app to 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 and activated updates

The two update events, available and activated, are Observable properties of [SwUpdate](https://angular.io/api/service-worker/SwUpdate):

log-update.service.ts

@Injectable()
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);
    });
  }
}

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:

check-for-update.service.ts

import { ApplicationRef, Injectable } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { concat, interval } from 'rxjs';
import { first } from 'rxjs/operators';

@Injectable()
export class CheckForUpdateService {

  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(() => updates.checkForUpdate());
  }
}

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 available event will indicate availability of a new version of the app.

In order to avoid negatively affecting the initial rendering, [ServiceWorkerModule](https://angular.io/api/service-worker/ServiceWorkerModule) will by default wait for the app to stabilize, before registering the ServiceWorker script. Constantly polling for updates, e.g. with interval(), will prevent the app from stabilizing and the ServiceWorker script will never be registered with the browser.

You can avoid that by waiting for the app to stabilize first, before starting to poll for updates (as shown in the example above).

Note that this is true for any kind of polling done by your application. Check the isStable documentation for more information.

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 activateUpdate() method:

prompt-update.service.ts

@Injectable()
export class PromptUpdateService {

  constructor(updates: SwUpdate) {
    updates.available.subscribe(event => {
      if (promptUser(event)) {
        updates.activateUpdate().then(() => document.location.reload());
      }
    });
  }
}

Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version.


Service worker in production

This page is a reference 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 resources and fail-safes.

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.

App versions

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 is 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 section below.

To preserve app integrity, the Angular service worker groups all files into a version together. The files grouped into a version usually include 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 index.html 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.html, which calls startApp(), along with the new bundle, which defines runApp().

This file integrity is especially important when lazy loading modules. 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 user opens or refreshes the application, the Angular service worker checks for updates to the app by looking for updates to the ngsw.json manifest. If an update is found, it is downloaded and cached automatically, and will be served the next time the application is loaded.

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. Consequently, it is essential that the service worker gets the correct content.

To ensure resource integrity, the Angular service worker validates the hashes of all resources for which it has a hash. Typically for an app created with the Angular CLI, 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. The reverse could also happen resulting in an 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 are updated more frequently than the app is deployed.

If the Angular service worker does not have a hash to validate a given resource, it still caches its contents but it honors 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.

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 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; that is, temporary deactivation.

The Angular service worker is aware of which versions are in use at any given moment and it cleans up versions when no tab is using them.

Other reasons the Angular service worker might change the version of a running app are normal events:

  • The page is reloaded/refreshed.
  • The page requests an update be immediately activated via the [SwUpdate](https://angular.io/api/service-worker/SwUpdate) service.

Service worker updates

The Angular service worker is a small script that runs in web browsers. From time to time, the service worker 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.

Bypassing the service worker

In some cases, you may want to bypass the service worker entirely and let the browser handle the request instead. An example is when you rely on a feature that is currently not supported in service workers (e.g. reporting progress on uploaded files).

To bypass the service worker you can set ngsw-bypass as a request header, or as a query parameter. (The value of the header or query parameter is ignored and can be empty or omitted.)

Debugging the Angular service worker

Occasionally, it may be necessary to examine the 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](https://angular.io/api/animations/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 the network. The service worker will try to recover from this state when a new version of the application is detected and installed (that is, when a new ngsw.json is available).
  • 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.

Both states are temporary; they are saved only for the lifetime of the ServiceWorker instance. The browser sometimes terminates an idle service worker to conserve memory and processor power, and creates a new service worker instance in response to network events. The new instance starts in the NORMAL mode, regardless of the state of the previous instance.

Latest manifest 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, or 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 and 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. This can cause behavior with Dev Tools open to differ from behavior a user might experience.
  • 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.

Service Worker Safety

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 several failsafe mechanisms in case an administrator ever needs to deactivate the service worker quickly.

Fail-safe

To deactivate the service worker, remove or rename the ngsw.json file. When the service worker’s request for ngsw.json returns a 404, then the service worker removes all of its caches and de-registers itself, essentially self-destructing.

Safety Worker

Also included in the @angular/service-worker NPM package is a small script safety-worker.js, which when loaded will unregister itself from the browser. This script can be used as a last resort to get rid of unwanted service workers already installed on client pages.

It’s important to note that you cannot register this worker directly, as old clients with cached state may not see a new index.html which installs the different worker script. Instead, you must serve the contents of safety-worker.js at the URL of the Service Worker script you are trying to unregister, and must continue to do so until you are certain all users have successfully unregistered the old worker. For most sites, this means that you should serve the safety worker at the old Service Worker URL forever.

This script can be used both to deactivate @angular/service-worker as well as any other Service Workers which might have been served in the past on your site.

Changing your app’s location

It is important to note that service workers don’t work behind redirect. You may have already encountered the error The script resource is behind a redirect, which is disallowed.

This can be a problem if you have to change your app’s location. If you setup a redirect from the old location (for example example.com) to the new location (for example www.example.com) the worker will stop working. Also, the redirect won’t even trigger for users who are loading the site entirely from Service Worker. The old worker (registered at example.com) tries to update and sends requests to the old location example.com which get redirected to the new location www.example.com and create the error The script resource is behind a redirect, which is disallowed.


Service worker configuration

The 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 Angular CLI processes the configuration file during ng build --prod. Manually, you can process it with the ngsw-config tool (where <project-name> is the name of the project being built):

      ./node_modules/.bin/ngsw-config ./dist/<project-name> ./ngsw-config.json [/base/href]

The configuration file uses the JSON format. All file paths must begin with /, which corresponds to the deployment directory—usually dist/<project-name> in CLI projects.

Unless otherwise noted, patterns use a limited glob format:

  • ** matches 0 or more path segments.
  • * matches 0 or more characters excluding /.
  • ? matches exactly one character excluding /.
  • 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](https://angular.io/api/service-worker/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 that 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. As 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.

{
  "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:

interface AssetGroup {
  name: string;
  installMode?: 'prefetch' | 'lazy';
  updateMode?: 'prefetch' | 'lazy';
  resources: {
    files?: string[];
    urls?: string[];
  };
}

name

A name is mandatory. It identifies 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 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.

Defaults to prefetch.

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.

Defaults to the value installMode is set to.

resources

This section describes the resources to cache, broken up into the following 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.
  • 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.
  • (Negative glob patterns are not supported and _?_ will be matched literally; i.e. it will not match any character other than _?_.)

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:

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 are cached according to this data group’s policy. Only non-mutating requests (GET and HEAD) are cached.

  • Negative glob patterns are not supported.
  • ? is matched literally; that is, it matches only the character ?.

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 defaults to 1.

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 parameter 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. timeout is a duration string, using the following unit suffixes:

  • d: days
  • h: hours
  • m: minutes
  • s: seconds
  • u: milliseconds

For example, the string 5s30u will translate to five seconds and 30 milliseconds of network timeout.

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, and no network request is made. 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.

navigationUrls

This optional section enables you to specify a custom list of URLs that will be redirected to the index file.

Handling navigation requests

The ServiceWorker will redirect navigation requests that don’t match any asset or data group to the specified index file. A request is considered to be a navigation request if:

  1. Its mode is navigation.
  2. It accepts a text/html response (as determined by the value of the Accept header).
  3. Its URL matches certain criteria (see below).

By default, these criteria are:

  1. The URL must not contain a file extension (i.e. a .) in the last path segment.
  2. The URL must not contain __.

Matching navigation request URLs

While these default criteria are fine in most cases, it is sometimes desirable to configure different rules. For example, you may want to ignore specific routes (that are not part of the Angular app) and pass them through to the server.

This field contains an array of URLs and glob-like URL patterns that will be matched at runtime. It can contain both negative patterns (i.e. patterns starting with !) and non-negative patterns and URLs.

Only requests whose URLs match any of the non-negative URLs/patterns and none of the negative ones will be considered navigation requests. The URL query will be ignored when matching.

If the field is omitted, it defaults to:

[
  '/**',           // Include all URLs.
  '!/**/*.*',      // Exclude URLs to files.
  '!/**/*__*',     // Exclude URLs containing `__` in the last segment.
  '!/**/*__*/**',  // Exclude URLs containing `__` in any other segment.
]

Build your First Angular PWA from Scratch (Angular 6 PWA Tutorial)

Today’s Question: Have you or are you planning on building a PWA?
– In this Angular 6 PWA tutorial, I’m going to show you how to create a PWA (Progressive Web App) based on Angular 6. PWA’s are awesome, in that they allow your apps to work offline, and they bypass the app stores; users can install them on their home screens! Hang tight, as I will be covering more PWA related content soon.

Github project for this lesson: https://github.com/designcourse/angular-6-pwa


Angular Service Worker | Progressive Web Apps Development

A service worker is a script that browser runs in the background, separate from a web page. With the help of the service worker, we can also implement push notification and background sync. Service workers can store files or responses in cache storage so it allows developers to create an offline experience for the user.

Service Worker in angular can be achieved by adding @angular/pwa package, this will going to handle lots of boilerplate code for us like registering a service worker, installing a service worker, and activating the service worker and lots more.

GitHub: https://github.com/funOfheuristic/angular-pwa

#angular #web-development #pwa #javascript

The Complete Guide to Service Worker and PWA in Angular
220.60 GEEK