Reputation: 1219
The background.js mechanism was removed in manifest v3 and I'm looking for how one does periodic operations in the background now that it's gone.
This upgrade guide says to use the chrome alarm api: https://developer.chrome.com/docs/extensions/mv3/migrating_to_service_workers/
Specifically it says:
Instead, we can use the Alarms API. Like other listeners, alarm listeners should be registered in the top level of your script.
It's not clear which script it needs to be the top level of, but when using the entry point of my chrome extension, "popup.js" it does periodically execute, but only when the chrome popup is actually open. I need it to execute in the background even when the popup is closed. A side note is that I get undefined for chrome.alarms until I add "alarms" to permissions in the manifest file and then it doesn't choke, but I still have the problem of it not running the background.
Since the above article is in the context of a service worker, I assume you instead need to put the alarm listener at the top level of the service-worker.js file. Only this doesn't work. I get undefined for chrome.alarms here (even with the "alarms" permission granted):
service-worker.js
console.log("inside service worker")
// getting chrome.alarms undefined here
chrome.alarms.create("alarm", { periodInMinutes: 1 });
Putting it in the install event listener doesn't help either:
self.addEventListener('install', event => {
console.log("Installing service worker")
// still getting chrome.alarms undefined here
chrome.alarms.create("alarm", { periodInMinutes: 1 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === "alarm") {
let milliseconds = new Date().getTime();
console.log(milliseconds)
chrome.action.setTitle({
title: "Hello "+ milliseconds
});
}
});
});
Out of desperation I added the "background" permission to the manifest as well, but that didn't help either.
Any clue how to run something periodically in the background in manifest v3? Seems like the alarms api should be how you do it, but it's apparently inaccessible from a service worker?
Upvotes: 5
Views: 4184
Reputation: 73826
The migration guide is just terribly confusing because it's written by a web developer. What it doesn't say is that using the extension's service worker is 99% the same as the ManifestV2 event page minus DOM-related API which isn't available in workers. So the changes you need to make are essentially the same as switching to event pages in ManifestV2.
Since the above article is in the context of a service worker
It's just the same background service worker script that you declared in background
section of manifest.json.
alarm listeners should be registered in the top level of your script.
In addition to creating an alarm you need to add a listener that will be called when the alarm event fires in your background script. The "top level" was intended to be a simplification for what really is "the event listener should be registered in the first task of the event loop each time the background script is executed when it wakes up". So you can put it anywhere you want e.g. inside other functions or even inside a Promise that resolves in the same first task. For more info see JavaScript event loop.
Alarms are remembered by the browser so if you need a periodic one you should create it just once when the extension is installed. Currently you recreate the alarm each time the service worker wakes up, which resets its timing. Good thing you were specifying an id parameter, otherwise a new alarm would be added each time.
getting chrome.alarms undefined here
To use most of chrome
API you need to add its name to permissions
in manifest.json. Note that you need to click the reload button on extension's card in chrome://extensions
page after editing manifest or the background script.
manifest.json:
"manifest_version": 3,
"background": { "service_worker": "bg.js" },
"permissions": [ "alarms" ],
bg.js:
chrome.alarms.onAlarm.addListener(a => {
console.log('Alarm! Alarm!', a);
});
chrome.runtime.onInstalled.addListener(() => {
chrome.alarms.get('alarm', a => {
if (!a) {
chrome.alarms.create('alarm', {periodInMinutes: 1});
}
});
});
self.addEventListener('install',
is not necessary because the extension's service worker is internally registered when the extension is installed. None of the service worker lifecycle events are necessary for MV3 and most/all won't even work.
Upvotes: 11