So far I've always been patient enough to search SO until I found a working solution. However I am really stuck on this one.
I am trying to achieve the following:
- Display a chrome extension in a new tab instead of a popup
- Once a search button is clicked a new page should be opened
- A content script should read the DOM and return it
- The content should be displayed on the extension page
Whenever I click the search button a new page is opened. However, I never get back any response but an error telling me "Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.".
I assume there is an issue with the registration of the listener. I've seen questions where the issue was that a message has been sent before a listener has been registered. I can imagine something similar here but I have not yet been able to resolve it by searching answers on SO.
If anyone would have the patience to help some chrome extension newbie with this issue any help will be really appreciated!
manifest.json
{
"manifest_version": 3,
"name": "Test",
"version": "1",
"icons": {
"32": "images/favicon.png"
},
"action":
{
"default_title":"Test",
"default_popup": "ui/main.html"
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; script-src-elem 'self' 'unsafe-inline' http://code.jquery.com/jquery-latest.min.js;"
},
"background": {
"service_worker": "js/background.js"
},
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["js/content.js"]
}],
"permissions": [
"activeTab"
]
}
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="description" content="Test" />
<meta charset="utf-8">
<title>Trade Monitoring</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="">
<link rel="stylesheet" href="../css/style.css">
<script src="../js/main.js"></script>
</head>
<body>
<center>
<div >
<center>
<button id="search">Search</button>
<div id="result">
</div>
</center>
</div>
</center>
</body>
</html>
main.js
var link= "https://www.google.com";
var extensionTab = 0;
var pageTab = 0;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var currTab = tabs[0];
if (currTab) { // Sanity check
extensionTab = currTab.id;
}
});
document.addEventListener('DOMContentLoaded', function () {
var btn = document.getElementById('search');
btn.addEventListener('click', function() {
search();
});
});
function search(){
scrape();
}
async function scrape(){
await openPage();
getContent();
}
function openPage(){
return new Promise((resolve, reject) => {
try{
chrome.tabs.create({ url: link }, function (newTab){
pageTab = newTab.id;
resolve(pageTab);
});
}catch(e){
reject(e);
}
})
}
function getContent(){
chrome.tabs.sendMessage(pageTab, {method: 'get_dom'}, function (response) {
console.log(response);
});
//TODO: Display content on extension page
}
content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
alert("here");
if (request.name == "name") {
payload = request.payload;
}
});
background.js
chrome.tabs.create({url: '../ui/main.html'})
CodePudding user response:
chrome.tabs.create() returns to your code immediately, before the tab actually starts loading, so your message won't be delivered because messaging doesn't wait for future listeners.
You can either repeat sendMessage in 100ms intervals until it succeeds or you can reverse the direction of the communication and let the new tab's content script be an initiator:
main.js
async function scrape(url) {
const tab = await chrome.tabs.create({ url });
return new Promise(resolve => {
chrome.runtime.onMessage.addListener(function onMessage(msg, sender) {
if (msg.method === 'dom' && sender.tab.id === tab.id) {
resolve(msg.data);
chrome.runtime.onMessage.removeListener(onMessage);
}
});
});
}
content.js:
// analyze DOM
// ..........
chrome.runtime.sendMessage({ method: 'dom', data: ['whatever'] });
The returned data must be JSON-compatible (number, string, boolean, null, and objects/arrays consisting of these types). Attempting to return a DOM element or a Promise or Map/Set will produce an empty {}
.