SOLVED: see my answer below
I am attempting to learn how to pass data between files in a Chrome Extension. My goal is to query data from the dom of a site when a particular url loads. Then display the queried data in a popup. I am having trouble with passing information the order of message events for the content, popup, background script.
What I believe is the right course of action:
- Background script determines if tab is the correct site via url comparison
- Background sends message to content script, via
chrome.tab.message
- Content script receives message via
chrome.runtime.onMessage.addListener()
, and performs information gathering from the site's dom. - Content script sends results via
chrome.runtime.sendMessage
to popup script to populate information in popup.html
I can see the console.log of the background.js by inspecting the popup. However, I get Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.
and no further console.logs in either the web page or popup dev tools console.
file structure
root/
├─ manifest.json
├─ background.js
├─ popup/
│ ├─ popup.html
│ ├─ popup.js
└─ scripts/
└─ content.js
manifest.json
{
"manifest_version": 3,
"name": "Plex File Name Generator",
"version": "0.0.1",
"description": "Generate file name for Plex from IMDb",
"permissions": ["tabs"],
"host_permissions": ["https://*.imdb.com/tt*"],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["https://*.imdb.com/tt*"],
"js": ["scripts/content.js"]
}
],
"action": {
"default_icon": {
"16": "assets/ext-icon.png",
"24": "assets/ext-icon.png",
"32": "assets/ext-icon.png"
},
"default_title": "Plex File Name Generator",
"default_popup": "popup/popup.html"
}
}
popup.html
<script type="module" src="popup.js"></script>
<div class="container">
<div class="title">Plex File Name Generator</div>
</div>
popup.js
chrome.runtime.onMessage.addListener((obj, sender, response) => {
const { type, movieTitle, imdbId } = obj;
if (type === "displayMovieTitle") {
console.log("popup", movieTitle, imdbId);
}
});
content.js
(() => {
chrome.runtime.onMessage.addListener((request, sender, response) => {
const { type, imdbId } = request;
if (type === "getMovieInfo") {
const titleSpan = document.querySelector(
'h1[data-testid="hero__pageTitle"] > span'
);
const movieTitle = titleSpan?.innerText?.trim() || "";
chrome.runtime.sendMessage({ type: "displayMovieTitle", movieTitle, imdbId });
}
return true;
});
})();
background.js
chrome.tabs.onUpdated.addListener((tabId, tab) => {
if (tab.url?.includes("imdb.com/title/tt")) {
chrome.tabs.onUpdated.addListener((nextTabId, nextTab) => {
if (tabId === nextTabId && nextTab.status === "complete") {
const imdbId = tab.url.match(/tt\d+/g)?.[0] || "";
chrome.tabs.sendMessage(tabId, {
type: "getMovieInfo",
imdbId,
});
}
});
}
});