Skip to content

Commit

Permalink
F133 ServiceWorker in Workers (#36726)
Browse files Browse the repository at this point in the history
* Minor tweaks

* tweak

* ServiceWorkerContainer.register() updates

* register - a bit more work

* Update files/en-us/web/api/serviceworkercontainer/register/index.md

* Update files/en-us/web/api/service_worker_api/using_service_workers/index.md

* Sideshowbarker typo suggestions (thanks)

Co-authored-by: sideshowbarker <[email protected]>

* Review feedback responses (wbamberg)

---------

Co-authored-by: sideshowbarker <[email protected]>
  • Loading branch information
hamishwillee and sideshowbarker authored Nov 22, 2024
1 parent 6f58b8a commit 5d29bef
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 40 deletions.
2 changes: 2 additions & 0 deletions files/en-us/web/api/navigator/serviceworker/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The **`serviceWorker`** read-only property of the {{domxref("Navigator")}} inter

The feature may not be available in private mode.

Note that a worker can similarly access the {{domxref("ServiceWorkerContainer")}} for a document using {{domxref("WorkerNavigator.serviceWorker")}}.

## Value

{{domxref("ServiceWorkerContainer")}}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ This could be for the following reasons:

After your service worker is registered, the browser will attempt to install then activate the service worker for your page/site.

The `install` event is fired when an installation is successfully completed. The `install` event is generally used to populate your browser's offline caching capabilities with the assets you need to run your app offline. To do this, we use Service Worker's storage API — [`cache`](/en-US/docs/Web/API/Cache) — a global object on the service worker that allows us to store assets delivered by responses, and keyed by their requests. This API works in a similar way to the browser's standard cache, but it is specific to your domain. The contents of the cache are kept until you clear them.
The `install` event is the first event that is fired on service worker installation or update.
It is emitted just once, immediately after registration is successfully completed, and is generally used to populate your browser's offline caching capabilities with the assets you need to run your app offline. To do this, we use Service Worker's storage API — [`cache`](/en-US/docs/Web/API/Cache) — a global object on the service worker that allows us to store assets delivered by responses, and keyed by their requests. This API works in a similar way to the browser's standard cache, but it is specific to your domain. The contents of the cache are kept until you clear them.

Here's how our service worker handles the `install` event:

Expand Down
3 changes: 2 additions & 1 deletion files/en-us/web/api/serviceworker/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ A `ServiceWorker` object is available via a number of properties:
- {{domxref("ServiceWorkerRegistration.installing")}} — when the service worker is in `installing` state
- {{domxref("ServiceWorkerRegistration.waiting")}} — when the service worker is in `installed` state

The `ServiceWorker` interface is dispatched a set of lifecycle events — `install` and `activate` — and functional events including `fetch`. A `ServiceWorker` object has an associated {{domxref("ServiceWorker.state")}}, related to its lifecycle.
The {{domxref("ServiceWorker.state")}} property and [`statechanged` event](/en-US/docs/Web/API/ServiceWorker/statechange_event) can be used to check and observe changes in the lifecycle-state of the object's associated service worker.
Related lifecycle events, such as [`install`](/en-US/docs/Web/API/ServiceWorkerGlobalScope/install_event) and [`activate`](/en-US/docs/Web/API/ServiceWorkerGlobalScope/activate_event) are fired at the service worker itself.

Service workers allow static import of [ECMAScript modules](/en-US/docs/Web/JavaScript/Guide/Modules), if supported, using [`import`](/en-US/docs/Web/JavaScript/Reference/Statements/import).
Dynamic import is disallowed by the specification — calling [`import()`](/en-US/docs/Web/JavaScript/Reference/Operators/import) will throw.
Expand Down
10 changes: 5 additions & 5 deletions files/en-us/web/api/serviceworkercontainer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The **`ServiceWorkerContainer`** interface of the [Service Worker API](/en-US/do

Most importantly, it exposes the {{domxref("ServiceWorkerContainer.register()")}} method used to register service workers, and the {{domxref("ServiceWorkerContainer.controller")}} property used to determine whether or not the current page is actively controlled.

Service workers can currently only be registered in the Window scope in some or all browsers, because the `ServiceWorkerContainer` object is not exposed to {{domxref("DedicatedWorkerGlobalScope")}} and {{domxref("SharedWorkerGlobalScope")}}. Check the [browser compatibility](#browser_compatibility) for information.
`ServiceWorkerContainer` objects are exposed in the Window scope through {{domxref("Navigator.serviceWorker")}} and in workers using {{domxref("WorkerNavigator.serviceWorker")}} (if supported — check [browser compatibility](#browser_compatibility)).

{{InheritanceDiagram}}

Expand All @@ -31,18 +31,18 @@ Service workers can currently only be registered in the Window scope in some or
- {{domxref("ServiceWorkerContainer.register()")}}
- : Creates or updates a {{domxref("ServiceWorkerRegistration")}} for the given `scriptURL`.
- {{domxref("ServiceWorkerContainer.startMessages()")}}
- : explicitly starts the flow of messages being dispatched from a service worker to pages under its control (e.g. sent via {{domxref("Client.postMessage()")}}). This can be used to react to sent messages earlier, even before that page's content has finished loading.
- : Explicitly starts the flow of messages being dispatched from a service worker to pages under its control (e.g. sent via {{domxref("Client.postMessage()")}}). This can be used to react to sent messages earlier, even before that page's content has finished loading.

## Events

- {{domxref("ServiceWorkerContainer/controllerchange_event", "controllerchange")}}
- : Occurs when the document's associated {{domxref("ServiceWorkerRegistration")}} acquires a new {{domxref("ServiceWorkerRegistration.active","active")}} worker.
- : Fired when the document's associated {{domxref("ServiceWorkerRegistration")}} acquires a new {{domxref("ServiceWorkerRegistration.active","active")}} worker.
- {{domxref("ServiceWorkerContainer/error_event", "error")}} {{Deprecated_Inline}} {{Non-standard_Inline}}
- : Fired whenever an error occurs in the associated service workers.
- {{domxref("ServiceWorkerContainer/message_event", "message")}}
- : Occurs when incoming messages are received by the `ServiceWorkerContainer` object (e.g. via a {{domxref("MessagePort.postMessage()")}} call).
- : Fired when incoming messages are received by the `ServiceWorkerContainer` object (e.g. via a {{domxref("MessagePort.postMessage()")}} call).
- {{domxref("ServiceWorkerContainer/messageerror_event", "messageerror")}}
- : Occurs when incoming messages can not deserialized by the `ServiceWorkerContainer` object (e.g. via a {{domxref("MessagePort.postMessage()")}} call).
- : Fired when incoming messages can not deserialized by the `ServiceWorkerContainer` object (e.g. via a {{domxref("MessagePort.postMessage()")}} call).

## Examples

Expand Down
131 changes: 98 additions & 33 deletions files/en-us/web/api/serviceworkercontainer/register/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ browser-compat: api.ServiceWorkerContainer.register

{{APIRef("Service Workers API")}}{{SecureContext_Header}}{{AvailableInWorkers}}

The **`register()`** method of the
{{domxref("ServiceWorkerContainer")}} interface creates or updates a
{{domxref("ServiceWorkerRegistration")}} for the given `scriptURL`.
The **`register()`** method of the {{domxref("ServiceWorkerContainer")}} interface creates or updates a {{domxref("ServiceWorkerRegistration")}} for the given scope.
If successful, the registration associates the provided script URL to a _scope_, which is subsequently used for matching documents to a specific service worker.

If successful, a service worker registration ties the provided script URL to a
_scope_, which is subsequently used for navigation matching. You can call this
method unconditionally from the controlled page. I.e., you don't need to first check
whether there's an active registration.
A single registration is created for each unique scope.
If `register()` is called for a scope that has an existing registration, the registration is updated with any changes to the scriptURL or options.
If there are no changes, then the existing registration is returned.
Note that calling `register()` with the same scope and `scriptURL` does not restart the installation process.
You can therefore call this method unconditionally from a controlled page: you don't need to first check whether there's an active registration or service worker.

A document can potentially be within the scope of several registrations with different service workers and options.
The browser will associate the document with the matching registration that has the most specific scope.
This ensures that only one service worker runs for each document.

> [!NOTE]
> It is generally safer not to define registrations that have overlapping scopes.
## Syntax

Expand All @@ -27,36 +34,39 @@ register(scriptURL, options)
### Parameters

- `scriptURL`
- : The URL of the service worker script. The registered service worker file needs to
have a valid [JavaScript MIME type](/en-US/docs/Web/HTTP/MIME_types#textjavascript).
- : The URL of the service worker script.
The registered service worker file needs to have a valid [JavaScript MIME type](/en-US/docs/Web/HTTP/MIME_types#textjavascript).
- `options` {{optional_inline}}

- : An object containing registration options. Currently available options are:

- `scope`
- : A string representing a URL that defines a
service worker's registration scope; that is, what range of URLs a service worker
can control. This is usually a relative URL. It is relative to the base URL of the
application. By default, the `scope` value for a service worker
registration is set to the directory where the service worker script is located (by resolving `./` against `scriptURL`).
See the [Examples](#examples) section for more information on how it
works.

- : A string representing a URL that defines a service worker's registration scope; that is, what range of URLs a service worker can control.

This is usually specified as a URL that is relative to the base URL of the site (e.g. `/some/path/`), so that the resolved scope is the same irrespective of what page the registration code is called from.
By default, the `scope` value for a service worker registration is set to the directory where the service worker script is located (by resolving `./` against `scriptURL`).

The scope must specify documents that are in the same directory or more deeply nested than the service worker (if you need a broader scope, this can be permitted via the HTTP `Service-Worker-Allowed` header).

See the [Examples](#examples) section for more information on how it works.

- `type`

- : A string
specifying the type of worker to create. Valid values are:
- : A string specifying the type of worker to create.
Valid values are:

- `'classic'`
- : The loaded service worker is in a standard script. This is the default.
- : The loaded service worker is in a standard script.
This is the default.
- `'module'`
- : The loaded service worker is in an
[ES module](/en-US/docs/Web/JavaScript/Guide/Modules)
and the import statement is available on
worker contexts. For ES module compatibility info, see the [browser compatibility data table for the `ServiceWorker` interface](/en-US/docs/Web/API/ServiceWorker#browser_compatibility).
- : The loaded service worker is in an [ES module](/en-US/docs/Web/JavaScript/Guide/Modules) and the import statement is available on worker contexts.
For ES module compatibility info, see the [browser compatibility data table for the `ServiceWorker` interface](/en-US/docs/Web/API/ServiceWorker#browser_compatibility).

- `updateViaCache`

- : A string indicating how the HTTP cache is used for service worker scripts resources during updates. Note: This only refers to the service worker script and its imports, not other resources fetched by these scripts.
- : A string indicating how the HTTP cache is used for service worker scripts resources during updates.
Note: This only refers to the service worker script and its imports, not other resources fetched by these scripts.

- `'all'`
- : The HTTP cache will be queried for the main script, and all imported scripts. If no fresh entry is found in the HTTP cache, then the scripts are fetched from the network.
Expand All @@ -67,21 +77,38 @@ register(scriptURL, options)

### Return value

A {{jsxref("Promise")}} that resolves with a {{domxref("ServiceWorkerRegistration")}}
object.
A {{jsxref("Promise")}} that resolves with a {{domxref("ServiceWorkerRegistration")}} object.

### Exceptions

- `TypeError`

- : The `scriptURL` or `scope URL` is a failure.
This can happen if the URL can't be resolved to a valid URL or uses a scheme that is not `http:` or `https`.
It may also happen if `scriptURL` is not a {{domxref("TrustedScriptURL")}}, and this is a requirement of the site's [Trusted Types Policy](/en-US/docs/Web/API/Trusted_Types_API).

The exception is also raised if the `scriptURL` or `scope URL` path contains the case-insensitive ASCII "%2f" (`*`) or "%5c" (`=`)

- `SecurityError` {{domxref("DOMException")}}
- : The `scriptURL` is not a potentially trustworthy origin, such as `localhost` or an `https` URL.
The `scriptURL` and scope are not same-origin with the registering page.

## Examples

The examples described here should be taken together to get a better understanding of
how service workers scope applies to a page.
The examples described here should be taken together to get a better understanding of how service workers scope applies to a page.

### Register a service worker with default scope

The following example uses the default value of `scope` (by omitting it). Suppose the service worker code is at `example.com/sw.js`, and the registration code at `example.com/index.html`. The service worker code will control `example.com/index.html`, as well as pages underneath it, like `example.com/product/description.html`.
The following example uses the default value of `scope` (by omitting it), which sets it to be the same location as the script URL.

Suppose the service worker code is at `example.com/sw.js`, and the registration code at `example.com/index.html`.
The service worker code will control `example.com/index.html`, as well as pages underneath it, like `example.com/product/description.html`.

```js
if ("serviceWorker" in navigator) {
// Register a service worker hosted at the root of the
// site using the default scope.
navigator.serviceWorker.register("./sw.js").then(
navigator.serviceWorker.register("/sw.js").then(
(registration) => {
console.log("Service worker registration succeeded:", registration);
},
Expand All @@ -94,7 +121,40 @@ if ("serviceWorker" in navigator) {
}
```

The following code, with all code in the same place, would apply to exactly the same pages as the example above. Alternatively, if the service worker code is at `example.com/product/sw.js`, and the registration code at `example.com/product/description.html`. then the service worker would only apply to resources under `example.com/product`. Remember the scope, when included, uses the page's location as its base.
Note that we have registered the scriptURL relative to the site root rather than the current page.
This allows the same registration code to be used from any page.

### Register a service worker with an explicit default scope

The code below is almost identical, except we have specified the scope explicitly using `{ scope: "/" }`.
Again, we've specified the scope as site-relative so the same registration code can be used from anywhere in the site.

```js
if ("serviceWorker" in navigator) {
// declaring scope manually
navigator.serviceWorker.register("./sw.js", { scope: "/" }).then(
(registration) => {
console.log("Service worker registration succeeded:", registration);
},
(error) => {
console.error(`Service worker registration failed: ${error}`);
},
);
} else {
console.error("Service workers are not supported.");
}
```

This scope happens to be the same as the default scope, so the registration applies to exactly the same pages as the example above.
Note that if we were to run this code after the previous example, browsers should recognize that we're updating an existing registration rather than a new one.

### Register a service worker using page-relative URLs

There is nothing to stop you from using page-relative URLs except that this makes it harder to move your pages around, and it is easy to accidentally create unwanted registrations if you do so.

In this example the service worker code is at `example.com/product/sw.js`, and the registration code at `example.com/product/description.html`.
We're using URLs that are relative to the current directory for the scriptURL and the scope, where the current directory is the base URL of the page that is calling `register()` (`example.com/product/`).
The service worker applies to resources under `example.com/product/`.

```js
if ("serviceWorker" in navigator) {
Expand All @@ -112,7 +172,11 @@ if ("serviceWorker" in navigator) {
}
```

There is frequent confusion surrounding the meaning and use of _scope_. A service worker can't have a scope broader than its own location, unless the server specifies a broader maximum scope in a [Service-Worker-Allowed](https://w3c.github.io/ServiceWorker/#service-worker-allowed) header on the service worker script. Therefore you should use the `scope` option when you need a _narrower_ scope than the default.
### Using Service-Worker-Allowed to increase service worker scope

There is frequent confusion surrounding the meaning and use of _scope_.
A service worker can't have a scope broader than its own location, unless the server specifies a broader maximum scope in a [Service-Worker-Allowed](https://w3c.github.io/ServiceWorker/#service-worker-allowed) header on the service worker script.
Therefore you should use the `scope` option when you need a _narrower_ scope than the default.

The following code, if included in `example.com/index.html`, at the root of a site, would only apply to resources under `example.com/product`.

Expand All @@ -132,7 +196,8 @@ if ("serviceWorker" in navigator) {
}
```

As noted above, servers can change the default maximum scope by setting the `Service-Worker-Allowed` header on the service worker script. In this case, the `scope` option should specify a scope narrower than the header value, but potentially larger than the service worker's location.
As noted above, servers can change the default maximum scope by setting the `Service-Worker-Allowed` header on the service worker script.
In this case, the `scope` option should specify a scope narrower than the header value, but potentially larger than the service worker's location.

The following code, if included in `example.com/product/index.html`, would apply to all resources under `example.com` if the server set the `Service-Worker-Allowed` header to `/` or `https://example.com/` when serving `sw.js`. If the server doesn't set the header, the service worker registration will fail, as the requested `scope` is too broad.

Expand Down

0 comments on commit 5d29bef

Please sign in to comment.