Understanding Service Worker scope
Asked Answered
S

4

74

I am trying to implement a Service Worker in a test page. My end goal is an application that operates offline. The folder structure is below

/myApp
  ...
  /static
    /mod
      /practice
        service-worker.js
        worker-directives.js
        foopage.js
  /templates
    /practice
      foopage.html

I am registering a service worker as shown below (within service-worker.js):

navigator.serviceWorker.register('../static/mod/practice/service-worker.js').then(function(reg) {
    console.log('Registration succeeded. Scope is ' + reg.scope);
    ...
}

and in the console I see

Registration succeeded. Scope is https://example.com/static/mod/practice/

If my page is located at https://example.com/practice/foopage, do I need to make sure that my service worker scope is https://example.com/practice/foopage?

If I try to define the scope in the register function call like

navigator.serviceWorker.register('../static/mod/practice/service-worker.js', { scope: '/practice/foopage/' }).then(function(reg) {
    ...
}

I get the error

Registration failed with SecurityError: Failed to register a ServiceWorker: The path of the provided scope ('/practice/foopage/') is not under the max scope allowed ('/static/mod/practice/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.

Question is: What exactly does scope refer to? Is it the collection of URLs that the service worker will eventually control? Do I need to move service-workers.js somewhere else? If so, where?

Skate answered 3/3, 2016 at 18:44 Comment(1)
Take a look at: #75533152. I get to configure it for angular v15.2.0.Unfortunate
P
79

Service workers are basically a proxy between your web application and the internet, so it can intercept calls to the network if so desired.

Scope in this instance refers to the path that the service worker will be able to intercept network calls from. The scope property can be used explicitly define the scope it will cover. However:

Service workers can only intercept requests originating in the scope of the current directory that the service worker script is located in and its subdirectories. Or as MDN states:

The service worker will only catch requests from clients under the service worker's scope.

The max scope for a service worker is the location of the worker.

As your service worker is located in /static/mod/practice/, it's not allowed to set its scope to /practice/foopage/. Requests to other hosts, e.g. https://stackoverflow.com/foo, can be intercepted in any case.

The easiest way to ensure that your service worker can intercept all the calls it needs to, would be to place it in the root directory of your web app (/). You can also override the default restrictions using an http header and manually setting the scope (see Ashraf Sabry's answer).

Procora answered 3/3, 2016 at 19:3 Comment(4)
I didn't think a js file in the root directory was ever something that would be done. But with new concepts come new paradigms I guessSkate
I think it is mainly for security reasons. If you only have access to /static, but not to the root (/) for example, your service worker shouldn't be able to intercept requests to the root.Procora
This is only partly correct—the scope determines which pages are controlled by the service worker. Once a page is controlled by a service worker, all HTTP requests originating from the page, regardless of the request URL, will trigger the service worker's fetch event. So if a controlled page makes an AJAX request for https://thirdpartyapi.com/api/test, your service worker will have a chance to intercept that.Arnie
the scope determines which pages are controlled by the service worker - this REALLY tripped me up, so thanks for the tip @JeffPosnickNutrition
O
62

Leave the service worker file in whatever directory imposed by your project structure and set the scope option to / and add the Service-Worker-Allowed HTTP header to the response of your service worker file.

I'm using IIS, so I would add the following to web.config file:

<location path="static/mod/practice/service-worker.js">
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Service-Worker-Allowed" value="/" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</location>

And register the worker by:

navigator.serviceWorker.register('/static/mod/practice/service-worker.js', { scope: '/' })
        .then(function (registration)
        {
          console.log('Service worker registered successfully');
        }).catch(function (e)
        {
          console.error('Error during service worker registration:', e);
        });

Tested on Firefox and Chrome.

Refer to the examples in Service worker specification

Obese answered 2/1, 2018 at 22:28 Comment(1)
I was setted http response to Service-Worker-Allowed : / but still it does not works for me. It register SW and just after 1 sec unregister that service worker automatically. Can you please check at demo3.icubes.orgLingonberry
P
14

For the people who are using nginx it couldn't be any simpler:

# Given that /static is your route to assets
location /static {
        # using / as root scope
        add_header Service-Worker-Allowed /;
....
Poleaxe answered 9/8, 2018 at 0:1 Comment(1)
My service worker was not registering. I thought the issue was with the scope. I gave your solution a try and now the service worker registers successfully. Thanks!Grunberg
V
3

Just in case if the scope changes between development & production environment, as often we use local subdirectories for projects, using "./" for the scope may save the day (& make it dynamic).

navigator.serviceWorker.register(
    `./service-worker.js`, 
    {
        scope: `./`
    }
);
Vitta answered 7/3, 2023 at 21:11 Comment(1)
Adding the scope to my service worker this way did the trick.Edisonedit

© 2022 - 2024 — McMap. All rights reserved.