Programmatically update service worker if update() is not available - updates

How can I programmatically update service worker since ServiceWorkerRegistration.update() has not been implemented in Chrome yet? Is there an alternative?

I assume you got this by now but I think you want serviceWorker.skipWaiting()

From the spec.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw-test/sw.js', {scope: 'sw-test'}).then(function(registration) {
// registration worked
console.log('Registration succeeded.');
button.onclick = function() {
registration.update();
}
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
};

Thr best workaround seems to be to force update by changing checksum of the service worker file by some simple backend code (it can be like last commented line with microtime), which will be detected by browser

Related

net::ERR_CONNECTION_RESET with service worker in Chrome

I have a very simple service worker to add offline support. The fetch handler looks like
self.addEventListener("fetch", function (event) {
var url = event.request.url;
event.respondWith(fetch(event.request).then(function (response) {
//var cacheResponse: Response = response.clone();
//caches.open(CURRENT_CACHES.offline).then((cache: Cache) => {
// cache.put(url, cacheResponse).catch(() => {
// // ignore error
// });
//});
return response;
}).catch(function () {
// check the cache
return getCachedContent(event.request);
}));
});
Intermittently we are seeing a net::ERR_CONNECTION_RESET error for a particular script we load into the page when online. The error is not coming from the server as the service worker is picking up the file from the browser cache. Chrome's network tab shows the service worker has successfully fetched the file from the disk cache but the request from the browser to the service worker shows as (failed)
Does anyone know the underlying issue causing this? Is there a problem with my service worker implementation?
This is likely due to a bug in Chrome (and potentially other browsers as well) that could result in a garbage collection event removing a reference to the response stream while it's still being read.
Its fix in Chrome is being tracked at https://bugs.chromium.org/p/chromium/issues/detail?id=934386.

Meteor Dev Tools Auditor is marking collections as insecure

I use Meteor Dev Tools plugin in Chrome, and I’ve noticed a cool new feature, that is worrying me about the way I've coded my app.
The audit collection tool is telling me that some of my collections are insecure.
I am still using Meteor 1.2 with Blaze
1.
One of them is meteor_autoupdate_clientVersions
1.1. should I worry about this one?
1.2. How do I protect it?
Insert, Update and Remove are marked as insecure.
2.
Then I have a cycles collection, which has marked as insecure: update and remove
This collection is updated on the database now and then but not supposed to be accessed from the frontend, and is not meant to be related to any client interaction.
For this collection I have these allow/deny rules in a common folder (both client and server)
I've tried applying these rules only on the server side, but I didn't see a difference on the audit results.
2.1. Should these rules be only on the server side?
Cycles.allow({
insert: function () {
return false;
},
remove: function () {
return false;
},
update: function () {
return false;
}
});
Cycles.deny({
insert: function () {
return true;
},
remove: function () {
return true;
},
update: function () {
return true;
}
});
2.2. How do I protect this collection?
3.
And then, I also have another collection with an insecure check which is users, where remove is marked as insecure.
On this webapp I don't make any use of users, there is no login, etc.
I might want to implement this in the future, though.
3.1 Should I worry about this collection being insecure, since I don't use it at all?
3.2 How do I protect this collection?
You do not have to allow or deny. Just remove the insecure package from the meteor app.
Then you can use publish/subscribe and methods for data insert, update and delete.
Remove this please fo code from app:
Cycles.allow({
insert: function () {
return false;
},
remove: function () {
return false;
},
update: function () {
return false;
}
});
Cycles.deny({
insert: function () {
return true;
},
remove: function () {
return true;
},
update: function () {
return true;
}
});
For 1.1
This happens while the user is logging.
Basically, issue is not with this but with the login method.
see wait time: https://ui.kadira.io/pt/2fbbd026-6302-4a12-add4-355c0480f81d
why login method slow?
This happens when everytime, your app gets reconnected. So, after the sucessful login, it will re-run all the publications again. That's why you saw such a delay to login hence this publication.
There is no such remedy for this and but this is kind fine unless your app is having a lot of througput/subRate to this method/publication.
For 3.1 :
You do not have to worry about inscure anymore after removing allow/deny and insecure package. But make sure, you write secure methods.

How do I uninstall a Service Worker?

After deleting /serviceworker.js from my root directory, Chrome still runs the service worker that I removed from my webroot. How do I uninstall the service worker from my website and Chrome so I can log back into my website?
I've tracked the issue down to Service Work's cache mechanism and I just want to remove for now until I have time to debug it. The login script that I'm using redirects to Google's servers for them to login to their Google account. But all I get from the login.php page is an ERR_FAILED message.
Removing Service Workers Programmatically:
You can remove service workers programmatically like this:
navigator.serviceWorker.getRegistrations().then(function(registrations) {
for(let registration of registrations) {
registration.unregister();
}
});
Docs: getRegistrations, unregister
Removing Service Workers Through The User Interface
You can also remove service workers under the Application tab in Chrome Devtools.
You can also go to the URL: chrome://serviceworker-internals/ and unregister a serviceworker from there.
You can do this through Chrome Developer Tool as well as Programatically.
Find all running instance or service worker by typing
chrome://serviceworker-internals/
in a new tab and then select the serviceworker you want to unregister.
Open Developer Tools (F12) and Select Application. Then Either
Select Clear Storage -> Unregister service worker
or
Select Service Workers -> Choose Update on Reload
Programatically
if(window.navigator && navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations()
.then(function(registrations) {
for(let registration of registrations) {
registration.unregister();
}
});
}
In Google Chrome, you can go to Developer tools (F12) -> Application -> Service worker and unregister the service workers from the list for that specific domain.
This method is effective in development mode of a site and mostly they run on localhost which is you may need for other project's development.
FYI, in case you are using MacOS Safari browser, there is one way to forcibly unregister a service worker (steps and images for Safari 12.1):
Safari > Preferences... > Privacy > Manage Website Data…
Enter domain name (ex. 'localhost'), click "Remove"
Note: In addition to service workers, this also will erase all caches, cookies, and databases for this domain.
In addition to the already correct answers given, if you want also to delete the SW cache you can invoke the following method:
if ('caches' in window) {
caches.keys()
.then(function(keyList) {
return Promise.all(keyList.map(function(key) {
return caches.delete(key);
}));
})
}
More in this article (Paragraph: "Unregister a service worker")
Another possibility, via Browser, is by accessing the "Cache Storage" section and click on the "Clear Site Data" button:
You should detecte two API in your devices: getRegistrations and getRegistration. The service-worker not has a unique set of APIs in all platforms. For example, some browsers only have a navigator.serviceWorker.getRegistration, no navigator.serviceWorker.getRegistrations. So you should consider with both.
safely uninstall Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (const registration of registrations) {
// unregister service worker
console.log('serviceWorker unregistered');
registration.unregister();
}
});
}
to detect service worker:
navigator.serviceWorker.controller
Code to for deletion of service worker:
navigator.serviceWorker.getRegistrations()
.then(registrations => {
registrations.forEach(registration => {
registration.unregister();
})
});
navigator.serviceWorker.getRegistrations().then(function(registrations) {
for(let registration of registrations) {
registration.unregister()
} })
if(window.navigator && navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations()
.then(function(registrations) {
for(let registration of registrations) {
registration.unregister();
}
});
}
if ('caches' in window) {
caches.keys()
.then(function(keyList) {
return Promise.all(keyList.map(function(key) {
return caches.delete(key);
}));
})
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (const registration of registrations) {
// unregister service worker
console.log('serviceWorker unregistered');
registration.unregister();
setTimeout(function(){
console.log('trying redirect do');
window.location.replace(window.location.href); // because without redirecting, first time on page load: still service worker will be available
}, 3000);
}
});
}
IF your service worker don't let you update your files. You will need to replace serviceworker file (sw.js / ServiceWorker.js) with the next code:
self.addEventListener('install', function(e) {
self.skipWaiting();
});
self.addEventListener('activate', function(e) {
self.registration.unregister()
.then(function() {
return self.clients.matchAll();
})
.then(function(clients) {
clients.forEach(client => client.navigate(client.url))
});
});
Source here
as for me , i just use a new nonexistent scope service worker to replace old one,
ServiceWorker: {
events: true,
// what range of URLs a service worker can control. Use a nonexistent path to disable ServiceWorker
scope: '/disable-service-worker/',
},
as for the app.js, i add below code to unregister old sw:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => {
for (const registration of registrations) {
// keep only serviceWorker which scope is /disable-service-worker/, The purpose is to make serviceWorker useless
if (registration.scope.includes('/disable-service-worker/') === false) {
registration.unregister()
}
}
});
// clear cache of service worker
caches.keys().then(keyList => {
return Promise.all(
keyList.map(key => {
return caches.delete(key);
}),
);
});
}
It can also be done in Chrome through application tab:
This code is compatible with Internet Explorer:
if (navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations().then(
function(registrations) {
for (let idx in registrations) {
registrations[idx].unregister()
}
})
}
IE doesn't support 'for...of' and 'for...of' construction may lead to "'SCRIPT1004: Expected ';'" error
The other answers all add code to the live website to remove the service worker. However I didn't want to leave that live code running forever so I developed a solution that works from within the service worker itself. The steps are below, I posted more detail and explanation on my blog.
Delete the code that registers the service worker.
Replace the service worker script with the following file. The new code must be available from the same URL the previous service worker was at. If you had multiple service worker URLs in the past you should duplicate the code at all of them.
console.log("Cleanup Service Worker Starting");
caches.keys()
.then(keys =>
Promise.all(
keys.map(async key => console.log("caches.delete", key, await caches.delete(key)))))
.then(async () => {
console.log("registration.unregister", await registration.unregister());
})
.then(() => console.log("DONE"))
.catch(console.error);
This code is fairly straight forward. First it deletes all the caches, then it unregisters itself.
Users' browsers will automatically check for an updated service worker the next time they load your website, or the next event 24h after the last service worker check. This means that existing users will run this cleanup on their next visit.
If You want to unregister all of the registered service workers in Browser,
you can do it by opening ex.
Chrome: chrome://serviceworker-internals/
Brave brave://serviceworker-internals/
open DevTools > Console and paste this:
$$('.unregister').forEach(b => b.click())
Open this page: chrome://serviceworker-internals and click to unregister button.
If you want to unregister all service worker open the developer tools and run this code on above page.
document.querySelectorAll("button.unregister").forEach(item=>{ item.click()})
Open in Chrome
chrome://serviceworker-internals/?devtools
then F12 in Console
$$('.unregister').forEach(b => b.click())
Typical JavaScript loop thats compatible with everything:
navigator.serviceWorker.getRegistrations().then(function(registrations) {
var registrationslength = registrations.length;
for (var i = 0; i < registrationslength; i++) {
registrations[i].unregister();
}
})

window.onerror not working in chrome

I am trying to add an onerror event to my website.
window.onerror = function() {
alert("an error");
}
But all I receive is:
notThere();
ReferenceError: notThere is not defined
What am I missing?
Browser: Chrome 26.0.1410.64 m
Steps to reproduce:
add the code to the console.
add notThere() to the console
window.onerror is not triggered when the console directly generates an error. It can be triggered via setTimeout though, e.g., setTimeout(function() { notThere(); }, 0);
Possible duplicate: Chrome: Will an error in code invoked from the dev console trigger window.onerror?
The window.onerror works in Chrome (see jsfiddle - http://jsfiddle.net/PWSDF/), but apparently not in the console - which makes some sense.
Some other reasons that you may not be able to handle errors in window.onerror (apart from the mentioned ones):
Another library sets window.onerror after you.
If you are using Angular, errors wont pass through window.onerror. You have to handle them using this factory:
.factory('$exceptionHandler', function() {
return function errorCatcherHandler(exception, cause) {
console.error(exception);
if (window.OnClientError) window.OnClientError(exception);
};
})
See:
https://docs.angularjs.org/api/ng/service/$exceptionHandler
http://bahmutov.calepin.co/catch-all-errors-in-angular-app.html

How to investigate webScoket failures on Safari?

I just started learning WebSockets today. I am using Safari and the following C# as my WebSocket server (http://www.codeproject.com/KB/webservices/c_sharp_web_socket_server.aspx).
My client is as simple as the following:
<script type="text/javascript">
try{
var socket = new WebSocket('ws://localhost:8181');
alert(socket.readyState);
socket.onopen = function() {
alert('opened...');
};
socket.onclose = function() {
alert('closed');
};
socket.onerror = function(){
alert('error!');
}; }
catch(exception){
alert(exception);
}
</script>
On Safari, am getting the message "Closed" which means the event onclose was raised before the onopen(). I suspecting that the server is closing the connection, any idea? Also, what's the best way to investigate issues like this? any error or reason code?
Thanks!
I guess I figured it out. On Safari you can enable Developer Tools and I was getting missing Sec-WebSocket-Origin header so I went ahead and changed the following:
WebSocket-Origin changed to Sec-WebSocket-Origin