0

I have a chrome extension with a button. Whenever the button is clicked, I want it to console.log("here") on the webpage. Currently it will only log on the extension popup page. Why is it doing this and how may I make it so that whenever the user presses a button it will console.log on the webpage not just the popup.

console.log("test")// this will log in both the extension popup and webpage
window.onload=function(){
button.addEventListener('click',function(){ 
jump()
});
}

function jump(){
  
  console.log("here")// this will only log in the extension popup
}
John Thomas
  • 29
  • 1
  • 4
  • [Use executeScript.](https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript) – Norio Yamamoto Nov 18 '22 at 22:13
  • Also don't load the same js file in popup and in content_scripts as they run in different pages. – wOxxOm Nov 18 '22 at 22:20
  • The best way to do this is to set up a content script with a message listener. When the user clicks the button in the popup, you can send a message to the active tab by using chrome.tabs.query to get the active tab, then use chrome.tabs.sendMessage() to send it. You could also do something similar with executeScript, though I recommend using message listeners instead. – Jridyard Nov 18 '22 at 22:35
  • @Jridyard Why do you prefer message listeners vs executeScript? – John Thomas Nov 18 '22 at 23:59
  • @JohnThomas The `scripting` permission is required with executeScript, but you do not need any raised privileges to use messages. executeScript is good if you need to run something in page context to get a window/scoped variable but outside of that, if you can do it in a content script, you should do it in a content script. Also, when you get into building larger projects, you'll want it do be done through messages so it's easier to read/maintain. – Jridyard Nov 19 '22 at 00:41

2 Answers2

2

This sample writes console.log to the popup and webpage when the button is clicked.

enter image description here

manifest.json

{
  "name": "executeScript",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "scripting"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

popup.js

const func = () => {
  console.log("executeScript");
}

document.getElementById("button").onclick = () => {
  console.log("popup");
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
    chrome.scripting.executeScript({
      target: { tabId: tabs[0].id },
      func: func
    });
  });
}

popup.html

<html>

<body>
  <input type="button" id="button" value="button">
  <script src="popup.js"></script>
</body>

</html>
Norio Yamamoto
  • 1,495
  • 2
  • 3
  • 10
  • 1
    This solution requires the `scripting` permission whereas it can be accomplished equally well with messages w/o the need for any raised permissions. I appreciate that you provided an additional answer, but executeScript is really not an optimal solution unless absolutely necessary as it requires a raised permission. This is also not the best way to teach a beginner as a lot of new extension devs end up doing everything out of executeScript instead of using content scripts. – Jridyard Nov 19 '22 at 00:35
  • @Jridyard, no, `scripting` doesn't "raise" permissions, it's the same as using `matches` in `content_scripts`. Also, it's a perfectly valid method for anyone including the beginners, because it injects a content script (by default) and is one of the two equally useful injection methods (declarative/programmatic) described everywhere including the official documentation. Another reason executeScript may be better is [Chrome extension content script re-injection after upgrade or install](https://stackoverflow.com/q/10994324) – wOxxOm Nov 19 '22 at 07:27
  • @wOxxOm Re-injection is only a problem while testing locally and a fairly small one at that. Your comment to my response is helpful though, that seems like a good solution. When I say that beginners get stuck on executeScript it's because a friend of mine who was getting into building extensions had a project where he used ES to run every single thing in his extension and when he asked for my help it was a total, total mess. After refactoring to content scripts instead it was much easier to read/modify. – Jridyard Nov 19 '22 at 18:23
  • Reinjection may be a big problem especially for a beginner because content scripts don't work right after installation in Chrome. As for messing up, a beginner can mess up absolutely everything. – wOxxOm Nov 19 '22 at 18:31
  • @wOxxOm Agreed, beginners have a knack for that sort of thing (lol). However, can you read the OP's new thread he just posted - https://stackoverflow.com/questions/74503188/how-to-use-executescript-like-a-content-script-in-chrome-extension ... can we agree that what he's proposing here makes more sense as a content script? – Jridyard Nov 19 '22 at 20:15
1

Here is a full working solution for you.

---manifest.json---
{
    "name": "Popup to Content",
    "version": "1.0.0",
    "manifest_version": 3,
    "content_scripts": [{
        "matches": ["https://*/*"],
        "js": ["content_script.js"]
    }],
    "permissions": [],
    "action": {
      "default_popup": "popup.html"
    }
}
---popup.html---
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="example"></button>
    <script src="popup.js"></script>
</body>
</html>
---popup.js---
const exampleButton = document.querySelector("#example")
exampleButton.addEventListener("click", function(){
    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
        const activeTabId = tabs[0].id;
        chrome.tabs.sendMessage(activeTabId, {"message": "This worked!"});
    });
});
---content_script.js---
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    // receive message here...
    console.log(request.message)
});

This will get the message to log in the console of the page instead of the popup window.

It works by querying the active tab (i.e. the one the user has open) and sends a message to that tab. The content script has a message listener that receives the message and once the message is received, logs it to the console of the active tab.

Please make sure you refresh the page after refreshing the extension or the page will not have the content script inserted and will therefore not log the message.

Jridyard
  • 761
  • 3
  • 9
  • Note that in Chrome this won't work right after installation and after reloading/updating the extension. See [Chrome extension content script re-injection after upgrade or install](https://stackoverflow.com/q/10994324) for a workaround. – wOxxOm Nov 19 '22 at 07:30
  • That's correct. Thanks for sharing this, that is a great solution! – Jridyard Nov 19 '22 at 18:20