Codezilla
Codezilla

Reputation: 95

Chrome extension messages firing multiple times

I'm making my first chrome extension and noticed that messages being sent from my popup.html page were getting duplicated in my content.js message event listener. I've console logged "sending message" before every message send and "message received" before every message, and I don't understand how the messages are being duplicated. I've also checked the chrome dev docs for sendMessage and onMessage and it specifies that the onMessage listener should only be fired once per sendMessage event.

Any help would be appreciated.

popup.html

<!DOCTYPE html>
<html>
<head>
    <title>Messaging Practice</title>
</head>
<body>
    <h1>Messaging Practice</h1>

    <input type="button" id="send-message" value="Button">
    <script src="popup.js"></script>
</body>
</html>

content.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        console.log('message received')
        console.log(request);
    }
);

popup.js

var messageButton = document.querySelector("#send-message");

messageButton.onclick = function() {
    chrome.tabs.query({currentWindow: true, active: true},
    function(tabs) {
        chrome.tabs.executeScript(
            tabs[0].id, {file: "content.js"}
        )
        console.log("sending message")
        chrome.tabs.sendMessage(tabs[0].id, "string message")
    });
}

background.js

chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
  chrome.declarativeContent.onPageChanged.addRules([{
    conditions: [new chrome.declarativeContent.PageStateMatcher({
      pageUrl: {hostEquals: 'stackoverflow.com'},
    })],
        actions: [new chrome.declarativeContent.ShowPageAction()]
  }]);
});

manifest.json

{
    "name": "Send Messages Practice",
    "version": "1.0",
    "manifest_version": 2,
    "description": "Simple messaging practice with the chrome api",
    "permissions": ["declarativeContent", "activeTab"],
    "background": {
        "scripts": ["background.js"],
        "persistant": true
    },

    "page_action": {
        "default_popup": "popup.html",
        "scripts": ["content.js"],
        "matches": ["http://*/*","https://*/*"]
    }

}

Upvotes: 6

Views: 4048

Answers (4)

Raad Altaie
Raad Altaie

Reputation: 1241

I think this happens because the webpage into which you injected content.js has iframes, to which content.js will also be injected. To solve this, all you need to do is listen for messages only in the main window.


// Check if the current window is top-level and not in an iframe
if (window.self === window.top && window.frameElement === null) {
    // listen to messages from background
    chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {

        // Handle the received message
    });
}

Upvotes: 0

Manu Arya
Manu Arya

Reputation: 101

Please make sure to inject the script only once—the script that contains chrome.runtime.onMessage.addListener().

The mistake I was making was that every time I sent a message, I was also injecting the script repeatedly, like this:

ChromeService.execInActiveTab((tab) => {
  // @ts-ignore
  chrome.scripting.executeScript({
    target: {tabId: tab.id},
    files: ["assets/js/autofill.js"],
  }, () => {
    // @ts-ignore
    chrome.tabs.sendMessage(tab.id, {setDropdownValue: {fieldId: fieldId, fieldValue: value}});
  });
});

Simply separating the logic for script injection and message sending resolved the issue for me.

Upvotes: 0

srnitk
srnitk

Reputation: 41

Adding "return true;" to event handlers will prevent your code from firing again and again:

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request.action == "show_alert") {
    alert(request.alert);
    return true;
  }
});

Upvotes: 4

Jianwu Chen
Jianwu Chen

Reputation: 6033

Get the same problem when I run my extension with multiple frames. @Wayne Smallman solution works for me:

recommending that all_frames be set to false in the manifest file

Upvotes: 3

Related Questions