We can make the connection hub out of the devtools_page
itself. This hidden page runs inside devtools for the current tab, it doesn't unload while devtools is open, and it has full access to all of chrome
API same as the background script.
manifest.json:
"devtools_page": "devtools.html",
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start"
}]
devtools.html:
<script src="devtools.js"></script>
devtools.js:
let portDev, portTab;
const tabId = chrome.devtools.inspectedWindow.tabId;
const onDevMessage = msg => portTab.postMessage(msg);
const onTabMessage = msg => portDev.postMessage(msg);
chrome.runtime.onConnect.addListener(port => {
if (+port.name !== tabId) return;
portDev = port;
portDev.onMessage.addListener(onDevMessage);
portTab = chrome.tabs.connect(tabId, {name: 'dev'});
portTab.onMessage.addListener(onTabMessage);
});
// chrome.devtools.panels.create...
panel.js:
const port = chrome.runtime.connect({
name: `${chrome.devtools.inspectedWindow.tabId}`,
});
port.onMessage.addListener(msg => {
// This prints in devtools-on-devtools: https://stackoverflow.com/q/12291138
// To print in tab's console see `chrome.devtools.inspectedWindow.eval`
console.log(msg);
});
self.onclick = () => port.postMessage('foo');
content.js:
let portDev;
const onMessage = msg => {
console.log(msg);
portDev.postMessage('bar');
};
const onDisconnect = () => {
portDev = null;
};
chrome.runtime.onConnect.addListener(port => {
if (port.name !== 'dev') return;
portDev = port;
portDev.onMessage.addListener(onMessage);
portDev.onDisconnect.addListener(onDisconnect);
});
P.S. Regarding the 5-minute timer reset trick, if you still need the background script to be persistent, in this case it is reasonably reliable because the tab is guaranteed to be open while devtools for this tab is open.