Extending DevTools API are not supporting manifest v3 yet properly and we have deadline near by.

1,019 views
Skip to first unread message

Dev

unread,
Mar 13, 2022, 6:21:39 AM3/13/22
to Chromium Extensions
Hi Team,
I have an extension which opens as sidebar panel in DevTools.
Recently I migrated it too manifest v3 as dead line is near for manifest v2 but after updating I found that lots of APIs and functionality is not working properly. It's very weird like sometime it works and sometime not.
Here are my observation-
1- Port is getting disconnected after few minutes and it's throwing below error for chrome.runtime.connect while same code is working absolutely fine for manifest v2.

Uncaught Error: Attempting to use a disconnected port object

devtools-script.js
var connectBackgroundPage = browserType.runtime.connect({
    name: "devtools-page"
});

devtools.js
var connectBackgroundPage = browserType.runtime.connect({
        name: "devtools-page"
});


2- Sidebar panel is getting created some time and some time its not getting created. It's also not showing any error in console. It's very unusual. 

Also here in documentation, I found that Extending DevTools is not yet validated for manifest v3.

Can someone please help here-
1- If I am missing anything in the code
2- Is there any timeline by when manifest v3 will be validated for Extending DevTools.

Thank you in advance and appreciate your support.

Screenshot 2022-03-13 at 3.36.16 PM.png

wOxxOm

unread,
Mar 13, 2022, 11:20:57 AM3/13/22
to Chromium Extensions, Dev
MV3 service worker forcibly disconnects ports after 5 minutes because Chromium team claims (without any proof) that a persistent background script is bad for performance, so you'll have to redesign your extension to remove the need for the background script's persistence or prolong its lifetime by disconnecting the port explicitly and connecting again before these 5 minutes elapse e.g. every 250 seconds using setTimeout.

Dev

unread,
Mar 14, 2022, 5:04:13 AM3/14/22
to Chromium Extensions, wOxxOm, Dev
Thank you for your response and tip.
In background page I am doing the same 'disconnecting the port explicitly and connecting again' and its working fine.
Backgound.js-
browserType.runtime.onConnect.addListener(function(port) {
    port.onMessage.addListener(extensionListener);

    port.onDisconnect.addListener(function(port) {
        port.onMessage.removeListener(extensionListener);

        var tabs = Object.keys(connections);
        for (var i = 0, len = tabs.length; i < len; i++) {
            if (connections[tabs[i]] == port) {
                delete connections[tabs[i]]
                break;
            }
        }
    });
});


But I am facing issue in devtools-script and devtools.js when using 

devtools-script.js (script for panel)
var connectBackgroundPage = browserType.runtime.connect({
    name: "devtools-page"
});

devtools.js (script to create the sidebar panel)
var connectBackgroundPage = browserType.runtime.connect({
        name: "devtools-page"
});

Could you please give some reference, how can use setTimeout here. Appreciate your help. Thank you.
I tried this way but it didn't work. 

setTimeout(function(){
        connectBackgroundPage = browserType.runtime.connect({
        name: "devtools-page"
    });
}, 250000);

wOxxOm

unread,
Mar 14, 2022, 5:21:31 AM3/14/22
to Chromium Extensions, Dev, wOxxOm
You need to disconnect it first, for example:

let port;
connect();
setInterval(connect, 250e3);
function connect() {
  port?.disconnect();
  port = chrome.runtime.connect();
}


Dev

unread,
Mar 14, 2022, 8:15:35 AM3/14/22
to Chromium Extensions, wOxxOm, Dev
Wow!! Thank you so much, this solved the disconnected port issue.

But now I am getting port closed when I am trying to receive message from contentScript to devtools-script. For first 5min, devtools-script able to get the response but after 5min, not able to receive the response. I have tried to apply same wait logic in background.js but no luck. 

I tried hard but not able to fix this issue, could please guide me here. Appreciate your help. Thank you.

"background.js:1 Uncaught (in promise) Error: The message port closed before a response was received."

devtools-script.js
let connectBackgroundPage;

connect();
setInterval(connect, 250e3);
function connect() {
    connectBackgroundPage?.disconnect();

    connectBackgroundPage = browserType.runtime.connect({
        name: "devtools-page"
    });
    connectBackgroundPage.postMessage({
        name: "init",
        tabId: browserType.devtools.inspectedWindow.tabId,
        contentScript: "../content-script/contentScript.js",
        contentCSS: "../content-script/contentScript.css"
    });
}

background.js
browserType.runtime.onConnect.addListener(function(port) {
    var extensionListener = function(message, sender, sendResponse) {
        if (message.name == "init") {
            connections[message.tabId] = port;
            return;

        }
    }
    port.onMessage.addListener(extensionListener);
    port.onDisconnect.addListener(function(port) {
        port.onMessage.removeListener(extensionListener);

        var tabs = Object.keys(connections);
        for (var i = 0, len = tabs.length; i < len; i++) {
            if (connections[tabs[i]] == port) {
                delete connections[tabs[i]]
                break;
            }
        }
    });
});

wOxxOm

unread,
Mar 14, 2022, 7:09:21 PM3/14/22
to Chromium Extensions, Dev, wOxxOm
Show your code for content script communication or even better upload the entire extension zip.

Dev

unread,
Mar 15, 2022, 12:00:26 AM3/15/22
to Chromium Extensions, wOxxOm, Dev
Thank you for your quick response and support.
I got this fix by add this code in background.js 

// ***********code for Keep live service worker***********
let lifeline;

keepAlive();

const currentTime = () => {
    var datetime = new Date().toLocaleString();
    return datetime;
}

chrome.runtime.onConnect.removeListener( () => { } );

chrome.runtime.onConnect.addListener( port => {
    if ( port.name === 'keepAlive' ) {
        lifeline = port;
        console.log( "onConnect.addListener", currentTime() );
        setTimeout( keepAliveForced, 295e3 ); // 5 minutes minus 5 seconds
        // setTimeout(keepAliveForced, 60000); // 5 minutes minus 5 seconds
        port.onDisconnect.addListener( keepAliveForced );
    }
} );

function keepAliveForced() {
    let data = lifeline ? lifeline.disconnect() : "";
    lifeline = null;
    console.log( "keepAliveForced", currentTime() );
    keepAlive();
}

async function keepAlive() {
    if ( lifeline ) return;
    for ( const tab of await chrome.tabs.query( { url: '*://*/*' } ) ) {
        try {
            await chrome.scripting.executeScript( {
                target: { tabId: tab.id },
                function: () => chrome.runtime.connect( { name: 'keepAlive' } ),
                // `function` will become `func` in Chrome 93+
            } );
            chrome.tabs.onUpdated.removeListener( retryOnTabUpdate );
            return;
        } catch ( e ) { }
    }
    chrome.tabs.onUpdated.addListener( retryOnTabUpdate );
}

async function retryOnTabUpdate( tabId, info, tab ) {
    if ( info.url && /^(file|https?):/.test( info.url ) ) {
        keepAlive();
    }
}

// ***********code for alive***********


Message has been deleted
Message has been deleted

Dev

unread,
Mar 20, 2022, 1:38:59 AM3/20/22
to Chromium Extensions, Dev, wOxxOm
Unfortunately above code works only if extension is opened in one tab. If extension is opened for multiple tabs then service worker is getting disconnected after 5 minutes on all tabs.
I need your help to fix this issue, kindly help me here.
Please find the extension code attached. I have deleted the above code from the extension and have that code which was working in manifest v2.

Steps to use extension and reproduce the issue-
  1. After adding the extension, open DevTools. There will be a sidebar tab "TestDev", open that.
  2. For first time, it will ask for register, please below credentials-
    email- du...@gmail.com
    company- dummy
    pass- dummy123
  3. Here it will work for first 5min but after 5min service worker will disconnect. Please refer the attached screenshots.
Kindly let me know if you need any further information. Appreciate your help and thanks in advance.

Screenshot 2022-03-20 at 10.59.59 AM.png

Screenshot 2022-03-20 at 11.00.15 AM.png


Screenshot 2022-03-20 at 11.00.51 AM.png

Message has been deleted
Message has been deleted
Message has been deleted

Dev

unread,
Mar 20, 2022, 1:44:07 AM3/20/22
to Chromium Extensions, Dev, wOxxOm
Its not allowing me to attach the zip folder here.

Could you please share your email or some other way so that i can share the code.
Screenshot 2022-03-20 at 11.13.08 AM.png

wOxxOm

unread,
Mar 20, 2022, 1:49:12 AM3/20/22
to Chromium Extensions, Dev, wOxxOm
There are many ways to share a file.

Dev

unread,
Mar 20, 2022, 2:19:24 AM3/20/22
to Chromium Extensions, wOxxOm, Dev
my bad, asked such a silly question :(
Please find the code here

wOxxOm

unread,
Mar 20, 2022, 2:34:01 AM3/20/22
to Chromium Extensions, Dev, wOxxOm
You need to reconnect all ports that are connected to the background script regularly, for example every 250 seconds as shown in my earlier comment. You have such ports in devtools-script.js (connectBackgroundPage), devtools.js (connectBackgroundPage), popup.js (port).

Dev

unread,
Mar 20, 2022, 2:55:27 AM3/20/22
to Chromium Extensions, wOxxOm, Dev
Thank you for checking this, i am trying this way and will update you.

Dev

unread,
Mar 21, 2022, 4:24:27 PM3/21/22
to Chromium Extensions, Dev, wOxxOm
I tried a lot and all the things which understood from your suggestion but unfortunately I am not able to fix this issue.
Could you help me with the solution. Appreciate your help.

Issue with the below code is that devtools-script is not able to receive the message from contentScript.
Please find the code here (same what you downloaded last time), I have deleted my code which I tried to fix it. Now extension has that code which is working for manifest v2.

I tried the below code and a lot more experiments I did but nothing worked. :(

devtools-script.js
let connectBackgroundPage;
connect();
setInterval(connect, 50e3);
function connect() {
    connectBackgroundPage?.disconnect();
    connectBackgroundPage = chrome.runtime.connect({

        name: "devtools-page"
    });
}
connectBackgroundPage.postMessage({
    name: "init",
    tabId: browserType.devtools.inspectedWindow.tabId,
    contentScript: "../content-script/contentScript.js",
    contentCSS: "../content-script/contentScript.css"
});

devtools.js
let connectBackgroundPage;
connect();
setInterval(connect, 50e3);
function connect() {
    connectBackgroundPage?.disconnect();
    connectBackgroundPage = chrome.runtime.connect({
        name: "devtools-page"
    });
}


wOxxOm

unread,
Mar 21, 2022, 4:38:55 PM3/21/22
to Chromium Extensions, Dev, wOxxOm
When you reconnect the port you also should update your "port routing table" that you use to map tabId and content scripts to a port.

wOxxOm

unread,
Mar 21, 2022, 5:04:53 PM3/21/22
to Chromium Extensions, wOxxOm, Dev
Actually, you shouldn't need the background script at all for this task if your extension is intended to work only when devtools is open. In that case you should use your devtools page to keep the state and track all the ports without the need to reconnect anything.

Dev

unread,
Mar 22, 2022, 3:13:03 AM3/22/22
to Chromium Extensions, wOxxOm, Dev
Thank you for the help.
1- I am not able to update "port routing table" and not getting how to do it. Could you please share any reference code if possible.
2- Extension also work from context menu even if devtools is closed. Is there any code reference for this solution?

wOxxOm

unread,
Mar 22, 2022, 3:30:42 AM3/22/22
to Chromium Extensions, Dev, wOxxOm
In case you need ports, you should already have a "port routing table" like this. I didn't analyze your code, so I don't know how you send messages from your content script and if you actually need to use ports, maybe chrome.runtime.sendMessage and chrome.tabs.sendMessage would be sufficient. As for the context menu, you need the background script to register a listener for the menu, but it doesn't mean you need a port here or a persistent background script.

Anyway, this is not trivial, even if theoretically possible, so currently your extension is yet another victim of the ill-advised decision to remove the background pages that didn't take such complex scenarios into account.

Dev

unread,
Mar 22, 2022, 4:48:36 AM3/22/22
to Chromium Extensions, wOxxOm, Dev
thank you for helping, I am debugging with this solution.
Reply all
Reply to author
Forward
0 new messages