Search code examples
google-chrome-extensionchrome-extension-manifest-v3

Do lazy non-blocking chrome.webrequest event listeners still cannot survive service-worker inactive state under Manifest-V3?


Last month, this bug-fix made its way to Chrome stable channel release.
This theoretically allows the lazy registration of non-blocking webRequest event listeners even when the service-worker is put into inactive state, like:

chrome.webRequest.onBeforeSendHeaders(myHandler);

/**
 * @arg {chrome.webRequest.WebRequestDetails} details 
 */
function myHandler(details)
{
    // processing request's details …
}

The extension I am working on listens to requests sent from any tab of the active window and spots specific requests based on some criteria. To avoid unnecessary work, the extension exposes a on/off button within the popup page which, when clicked, will send the appropriate signal via chrome.runtime.sendMessage to the web-worker which in turn will attach/detach a given handler for webRequest.onBeforeSendHeaders event. As a consequence, the registration doesn't occur at the service-worker top level but within a message response handler.
So basically, the request listener is turned off by default and it can be started/stopped when needed.

Currently this works but only requests fired during the first few seconds are being intercepted, after the start signal has been triggered (10sec on average).
If I click the start button again, the same scenario takes place: a listener is getting attached and new requests are being intercepted but only for few seconds.
Now if the service-worker inspect view (console) is opened, requests interceptions are never stopped and all works as expected ...

It looks like the event listener is being teared down once the service-worker is put into inactive state, which doesn't happen when the inspect view is open because it probably keeps the service-worker alive.

Wasn't the bug-fix supposed to address this issue in the first place?
Unfortunately I could not think of any alternative/workaround.
Has anybody faced this scenario lately?


Solution

  • The "lazy" in the fix means the entire context as opposed to an "eager" persistent background script in MV2 or an open extension tab with webRequest listeners. It's quite possible that your scenario wasn't accounted for, so I think you should comment in the original bug report or open a new issue on https://crbug.com. If you look in chrome://serviceworker-internals you should see that SW stops and that's when the listener stops working whereas having a devtools open for SW keeps it running forever.

    One workaround is to always register the listener as shown in the other answer. The problem is that it wakes up the SW when the user doesn't need it, which is bad for performance as it may happen hundreds of times a day depending on the frequency of the event you observe.

    You can improve it by using a named (global) function for the listener and unregister it after reading the option value from storage at SW startup. This will limit the wasteful wake-ups to just one per browser launch.

    Another workaround might be to have two background scripts - one with the listener and one without - and register the appropriate one in the popup UI via navigator.serviceWorker then import the common code. It didn't work in my test though.