Reputation: 50
I know I'm a little late to the game and have only just started porting my own extension from manifest v2 to v3, but I'm wondering why no one has pointed this out yet. At least I haven't found anything.
My extension has several features that can be enabled/disabled by the user and the settings are stored in storage.sync. And some event listeners are only needed if a certain feature is enabled by the user. With manifest v2 and its persistent background script, I could register the event listeners only when needed, based on the user settings retrieved from the asynchronous storage.sync. But with manifest v3, which uses non-persistent service workers, the event listeners need to be registered in the first synchronous run to fire correctly.
So with manifest v3 I have to register all listeners and can only determine in the callback function if the listener was needed at all. This looks so stupid and is bad programming in my opinion.
I know there are hacks to make service workers run persistently so I could still register the listeners asynchonously. But I nevertheless think that the requirement for event listeners to be registered synchronously, while the storage API is asynchronous, is a major flaw.
Or do I miss something...?
Upvotes: 0
Views: 52
Reputation: 73766
ManifestV3 has many weaknesses, which were pointed out repeatedly, but Chromium team doesn't consider the extensions platform as a priority, judging by the fact only a handful of developers are working there for more than a decade, who naturally can't fix all those hundreds of problems.
This particular problem is discussed in WECG#501.
The workaround is to register the listener, read the storage, then unregister the listener so that it won't wake up the service worker next time.
let state = chrome.storage.sync.get().then(res => (state = res));
chrome.tabs.onCreated.addListener(async function onCreated(tab) {
if (state instanceof Promise)
await state;
if (!state.enabled) {
chrome.tabs.onCreated.removeListener(onCreated);
return;
}
// do something useful
});
You'll need to have at least one listener that wakes up the service worker when the options change, e.g. chrome.storage.sync.onChanged
.
One caveat is that onChanged may trigger too often if you change other values, so you may want to move those frequently changed values to the local
storage. Another approach would be to abandon the idea of immediate reaction to a change in storage and instead of onChanged use some dedicated event that will be triggered from your UI (popup, options, side panel) e.g. chrome.runtime.connect
or navigator.serviceWorker.controller.postMessage
in the UI and self.onmessage
in the service worker. This event will wake up the service worker, so it'll re-register the listeners.
Upvotes: 1