I got a error; the worbox precaching my Static files,for example js or css;At this time I setted workbox.routing.registerRoute is don't work;
If I delete workbox precaching (must sure server worker cache file),After the refresh file is from cache;
Responses won't come from the service worker until the registered service worker takes control of the current page. Depending on how you're testing things, that might not happen until you've closed all of your previously open tabs for your origin.
You can learn more at "The Service Worker Lifecycle".
I'd recommend starting from scratch by using a Chrome Incognito window, going through the SW registration, and then reloading that Incognito tab. At that point, the newly registered SW should be in control of the page, and you should see your precached JavaScript being used to satisfy the subresource request.
In general, if you are using Workbox precache and runtime routing in the same service worker, and you list you call to precaching first (which is what you're doing), then precaching will take precedence.
Related
I have a problem, much like this question, which is a few years old now.
The problem I have is [a] new JS to the app code to unregister the ServiceWorker or skip-waiting is not being parsed because the app code is being served by the old ServiceWorker, and [b] I have full control of the server, but using the Clear-Site-Data: response header isn't working because all of the app's files are being served from the ServiceWorker or cache. It's never seeing that header. The only fresh requests are being made to an API on a different subdomain.
There are users out in the world using this application. What can I do to get clients with the old serviceWorker installed and running in their browser to observe new updates?
The request for the underlying service worker script file during an update check should always bypass both the HTTP cache and the existing service worker's fetch handler.
You should be able to add the Clear-Site-Data: header to the response for the underlying service worker script file returned by your web server and recover in that manner.
Additionally, you should be able to include code in the service worker script file along the lines of what's in that "kill switch" example and it will be run whenever a browser makes an update check, since again, that update check will bypass caches and go against the web server.
When creating a react app, service worker is invoked by default. Why service worker is used? What is the reason for default invoking?
You may not need a service worker for your application. If you are creating a project with create-react-app it is invoked by default
Service workers are well explained in this article. To Summarise from it
A service worker is a script that your browser runs in the
background, separate from a web page, opening the door to features
that don't need a web page or user interaction. Today, they already
include features like push notifications and background sync and have
ability to intercept and handle network requests, including
programmatically managing a cache of responses.
In the future, service workers might support other things like
periodic sync or geofencing.
According to this PR to create-react-app
Service workers are introduced with create-react-app via
SWPrecacheWebpackPlugin.
Using a server worker with a cache-first strategy offers performance
advantages, since the network is no longer a bottleneck for fulfilling
navigation requests. It does mean, however, that developers (and
users) will only see deployed updates on the "N+1"
visit to a page, since previously cached resources are updated in the
background.
The call to register service worker is enabled by default in new apps but you can always remove it and then you’re back to regular behaviour.
In simple and plain words, it’s a script that browser runs in the background and has whatsoever no relation with web pages or the DOM, and provide out of the box features. It also helps you cache your assets and other files so that when the user is offline or on slow network.
Some of these features are proxying network requests, push notifications and background sync. Service workers ensure that the user has a rich offline experience.
You can think of the service worker as someone who sits between the client and server and all the requests that are made to the server pass through the service worker. Basically, a middle man. Since all the request pass through the service worker, it is capable to intercept these requests on the fly.
I'd like to add 2 important considerations about Service Workers to take into account:
Service Workers require HTTPS. But to enable local testing, this restriction doesn't apply to localhost. This is for security reasons as a Service Worker acts like a man in the middle between the web application and the server.
With Create React App Service Worker is only enabled in the production environment, for example when running npm run build.
Service Worker is here to help developing a Progressive Web App. A good resource about it in the context of Create React App can be found in their website here.
I'd like to use two service workers on my site: one to provide a classic offline cache (/sw.js) for my PWA and another for something like a local database "server" which uses background sync and push (/sw-db.js). Since the latter tends to do heavy work (blocking the event loop for a few ms) it's better to keep it separate.
Since the database sw is not used for fetch requests, I would give it a dummy scope, whereas sw.js is scoped for the whole domain.
Does the first, which responds to "fetch" events, also serve the code/URL for /sw-db.js (keeping it somewhat in-sync with site updates) or are service workers always updated via network.
The sw.js script URL that you pass in to navigatior.serviceWorker.register('/path/to/sw.js') will always be fetched bypassing any other service workers when it's time to check for updates. So to answer your question, the other service worker's fetch handler won't be triggered.
The HTTP cache does come into play whenever there's an update check for a service worker script. So you should make sure you're setting proper HTTP cache control headers for your use case.
Usually, a service worker update check is triggered due to a navigation to a page controlled by a service worker, but if you have a service worker with a "dummy" scope, it won't end up controlling any pages. That being said, when a service worker handlers sync or push events you'll also end up triggering the update check. I'm not sure if every sync or push triggers the check, or just a subset of them, such as the ones which cause a new service worker to spawn. But it will happen at least some of the time.
To register a service worker, I can call
navigator.serviceWorker.register('/worker.js')
Every time the page loads it checks for an updated version of worker.js. If an update is found, the new worker won't be used until all the page's tabs are closed and then re-opened. The solution I read was:
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim());
});
I can understand the skipWaiting part, but what exactly does clients.claim() do? I've done some simple tests and it seems to work as expected even without it.
I'm excerpting the following from a guide to the service worker lifecycle:
clients.claim
You can take control of uncontrolled clients by calling
clients.claim() within your service worker once it's activated.
Here's a variation of the demo above which calls clients.claim() in
its activate event. You should see a cat the first time. I say
"should", because this is timing sensitive. You'll only see a cat if
the service worker activates and clients.claim() takes effect before
the image tries to load.
If you use your service worker to load pages differently than they'd
load via the network, clients.claim() can be troublesome, as your
service worker ends up controlling some clients that loaded without
it.
Note: I see a lot of people including clients.claim() as boilerplate,
but I rarely do so myself. It only really matters on the very first
load, and due to progressive enhancement the page is usually working
happily without service worker anyway.
Service worker takes controls from the next page-reload after its registration. By using self.skipWaiting() and self.clients.claim(), you can ask the client to take control over service worker on the first load itself.
e.g
Let's say I cache a files hello.txt, and again If I make a call for hello.txt it will have make server call even though I have resource in my cache. This is the scenario when I don't use self.clients.claim(). However on making a server call for hello.txt on next page reloads, it will be serving the resource from the cache.
To tackle this problem, I have to use combination of self.skipWaiting() and self.clients.claim() so that service worker starts serving content as soon as it is activated.
P.S:
next page-reload means page revisit.
first load signifies the moment when page is visited for the first time.
I had trouble wrapping my head around clients.claim as well and none of the explanations made any sense to me so hopefully this answer helps anyone struggling as well.
To understand Clients.claim we have to look at the worker lifecycle.
Installing; This is the first phase after registration. When the oninstall handler completes, the service worker is considered installed.
Installed; The service worker is waiting for clients using other service workers to be closed.
Activating; There are no clients controlled by other service workers. When the onactive handler completes, the service worker is considered activated.
Activated; The service worker now controls the page.
skipWaiting and Clients.claim are designed to solve different problems.
Clients.claim ONLY has an effect on the very first time your webpage goes from an uncontrolled webpage to a controlled (by a service worker) webpage by registering a service worker.
skipWaiting is exactly what it says. It skips the waiting phase and moves directly to activating. Once activated it is now the active service worker for all clients. Clients being any window or tab that has a webpage open that is within the scope of your service worker.
So why do we need Clients.claim then?
This confused me and I bet it confused you too. The answer is best described in an example.
Imagine your webpage DOES NOT register a service worker and is therefor uncontrolled. You have two tabs (clients) of your webpage open. You make an update to your webpage so that it will now register a service worker.
You decide to reload the first tab (client), it will now fetch the script that registers the service worker and it will start to install. Once installed it notices that no other client is being controlled by a service worker so it does not have to wait and it can immediately safely activate the service worker and any fetch of a resource will now go through your service worker.
However, here is the catch, your other tab (client) will also have an active service worker now, BUT, it is not yet being controlled. Meaning any fetch will not go through the service worker yet. You need to reload any other tab (client) in order for it to be controlled by the active service worker. This is confusing, since if any new service worker hereafter becomes active by forcing it with skipWaiting, the other tabs (clients) will immediately be controlled by the new active service worker. So I emphasize the reload part is needed ONLY when an uncontrolled webpage becomes controlled.
Enter Clients.claim. When you call self.clients.claim() in the first service worker when it becomes activated, like so:
self.addEventListener('activate', event => {
event.waitUntil(clients.claim());
});
It will make sure the other tabs (clients) that were uncontrolled, but have an active service worker, will get controlled by the active service worker. Meaning any fetch to a resource will now go through the active service worker. Without Clients.claim the service worker is not used until the page is reloaded.
Again, if all the webpages are being controlled by a service worker already. If a NEW service worker is detected and installed, it normally waits until all tabs with the webpage (clients) are closed. The next time you visit the webpage it will have activated the new service worker and the webpage is being controlled by it.
However, if you don't close all the clients and you force the new service worker by using skipWaiting it will immediately become active for all clients and also controlled. Meaning any new fetch for a resource from ANY of the clients will now immediately go through your new service worker. Now you don't need to use Clients.claim in order for the other clients to start using your new service worker.
This was my attempt, hopefully it helped someone.
Clients.claim() makes the service worker take control of the page when you first register a service worker. If there is already a service worker on the page, it will make no difference. skipWaiting() makes a new service worker replace an old one. Without it, you would have to close the page (and any other open tabs containing a page in the same scope) before the new service worker was activated.
A hard reload or hard refresh (e.g., shift-reload in Chrome) appears to bypass the service worker.
For example, loading a service-worker controlled page such as https://airhorner.com/ or https://wiki-offline.jakearchibald.com/, setting the network to "offline" in devtools, and then hard reloading the page leads to a broken "there is no internet connection" page. (A regular reload shows the cached page, as expected.)
Is there a way to prevent this, or use the service worker as a fallback in the event that the device is offline?
This is behavior is explicitly called out as part of the service worker specification:
navigator.serviceWorker.controller returns null if the request is a
force refresh (shift+refresh). The ServiceWorker objects returned from
this attribute getter that represent the same service worker are the
same objects.
So it's not just a browser implementation detail.
If you felt like there was a strong reason why a service worker shouldn't behave that way, the best approach would be to bring up your concerns in the spec's issue tracker.