I am currently attempting to create a Google Chrome extension in Manifest V3 and keep encountering the following error:
Uncaught TypeError: Cannot read properties of undefined (reading 'id')
I've searched far and wide and every solution I've found just leads me to stumble into a slightly different error. I'm still pretty new with Javascript, so I'm sure this is just a super noob mistake I'm making, but here is all of my code anyways:
index.html
<html>
<head>
<link rel="stylesheet" href="styles.css">
<link rel="chart" href="Chart/setup.js">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<script type="js/main.js" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="donutchart" style="width: 900px; height: 500px;"></div>
<h4>GOOGLE CALENDAR</h4>
<h5>Time Tracker</h5>
<hr></hr>
</body>
</html>
manifest.json
{
"manifest_version": 3,
"name": "Google Calendar Time Tracker",
"description": "Base Level Extension",
"version": "1.0",
"action": {
"default_popup": "index.html",
"default_icon": "hello_extensions.png"
},
"background": {
"service_worker": "js/main.js"
},
"permissions": [
"scripting",
"tabs",
"https://*/*",
"http://*/*"
]
}
main.js
function getTabId() {
let tabs = chrome.tabs.query({currentWindow: true, active : true});
return tabs[0].tabId;
}
chrome.scripting.executeScript({
target: {tabId: getTabId()},
files : ["chart.js"],
})
.then(() => console.log("Script injected"));
chart.js
google.charts.load("current", { packages: ["corechart"] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['Work', 11],
['Eat', 2],
['Commute', 2],
['Watch TV', 2],
['Sleep', 7]
]);
var options = {
title: 'My Daily Activities',
pieHole: 0.4,
};
var chart = new google.visualization.PieChart(document.getElementById('donutchart'));
chart.draw(data, options);
}
Any other suggestions for improvements are more than welcome! As of now, all I'm trying to do is import the Google Charts library successfully, and have a pi chart display within my extension. I didn't include the stylesheet in the code above, since I didn't think it would be necessary.
I've tried changing id to tabId, and tried with promises as well, and none of that has worked and I've just had errors being thrown left, right, and center. It seems like the id / tabId variable just isn't being recognized at all, but all solutions I saw online utilized it. What am I missing here?
The main problem is that you don't need main.js and executeScript because its purpose is to inject scripts into the web page, whereas you need the script in the action popup, which is neither a web page nor related to it. The action popup is a separate page shown in a separate window with its own URL like chrome-extension://id/popup.html.
To load scripts in the popup you simply write a script
tag with src
:
<script src="chart.js"></script>
<script src="popup.js" defer></script>
background
from manifest.json.Other problems:
permissions
in manifest.json to host_permissions
.https://www.gstatic.com/charts/loader.js
script because ManifestV3 extensions can't run external scripts in their pages. If you still need this feature you'll have to do it inside a sandboxed page or frame.Problems in the no longer necessary main.js:
tab
object return by chrome.tabs.query doesn't have tabId
property, it's just id
.await
it or use inside then
.chrome://extensions
tab for an unpacked extension or on the web store page; both disallow injection. As a rule of thumb, if your background script doesn't add event listeners for chrome
events like chrome.tabs.onUpdated
or chrome.runtime.onMessage
you don't need the background script at all.