Chrome Extension: Uncaught ReferenceError: function is not defined

Viewed 896

I am writing a Chrome Extension and I have this page:

<html>
  <body>
    <button id="changeColor"></button>
    <script src="popup.js"></script>
  </body>
</html>

With this JS (popup.js):

let changeColor = document.getElementById("changeColor");

chrome.storage.sync.get("color", ({ color }) => {
  changeColor.style.backgroundColor = color;
});

changeColor.addEventListener("click", async () => {
    let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      function: setPageBackgroundColor,
    });

});
  
function setPageBackgroundColor() {
  chrome.storage.sync.get("color", ({ color }) => {
    document.body.style.backgroundColor = color;
  });
  // Here, it says: Uncaught ReferenceError: getElementByXpath is not defined
  console.log(getElementByXpath("xpath").textContent);
}
  
function getElementByXpath(path) {
  return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

Why?

1 Answers

Problem: the code of outer functions isn't injected.

Here's what executeScript does:

  • it takes the function's code as plain text IIFE i.e. (function foo() { ... })(),
  • it transfers the text to the web page,
  • it selects the "isolated world" environment where all content scripts of your extension run,
  • it executes that text as JavaScript code.

Solution: put all necessary code and functions inside the function you inject.

In your case getElementByXpath definition should be moved inside setPageBackgroundColor.

P.S. Naturally, the injected code can also use global variables/functions of previously injected content scripts via manifest.json's content_scripts (assuming their run_at already occurred) or executeScript.

Related