From c8da3d89c5f0471e2ba0a8583475baa8f631123d Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Tue, 12 Nov 2024 16:56:13 +1100 Subject: [PATCH] ServiceWorkerContainer.register() updates --- .../serviceworkercontainer/register/index.md | 120 +++++++++++++----- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/files/en-us/web/api/serviceworkercontainer/register/index.md b/files/en-us/web/api/serviceworkercontainer/register/index.md index 2bf797b8ececc48..ddafa507dec18fa 100644 --- a/files/en-us/web/api/serviceworkercontainer/register/index.md +++ b/files/en-us/web/api/serviceworkercontainer/register/index.md @@ -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 the service worker is installed only on the first registration of a particular scriptURL. +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 @@ -27,36 +34,38 @@ 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 a relative URL, which 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`). + Note that by default this 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. @@ -67,15 +76,31 @@ 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`. + For `scriptURL` it may also happen because the URL cannot be validated using the [Trusted Types API](/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. -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`. +### 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`. ```js if ("serviceWorker" in navigator) { @@ -94,7 +119,10 @@ 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. +### Register a service worker with a scope + +The code below is almost identical, except we have specified the scope explicitly using `{ scope: "./" }`. +This scope happens to be the same as the default scope, so the registration applies to exactly the same pages as the example above. ```js if ("serviceWorker" in navigator) { @@ -112,7 +140,34 @@ 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. +Note that if we were to run this code after the previous example, browsers should recognise that we're updating an existing registration at the same scope. + +### Register a service worker from a different base URL + +In this example the service worker code is at `example.com/product/sw.js`, and the registration code at `example.com/product/description.html`. +The service worker applies to resources under `example.com/product`. Remember the scope, when included, uses the page's location as its base. + +```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."); +} +``` + +### 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`. @@ -132,7 +187,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.