2

My chrome extension uses long-lived 'Port' object for message passing between 'content script' and 'popup' page. The 'popup' is able to send a message to the 'content script' event listener. But, the 'Port' object in the 'content script' is unable to send message to the 'popup' page.

var port = chrome.extension.connect({"name":"swap"});

// listener for incoming connections
chrome.extension.onConnect.addListener(function( incomingPort ){

    // listener on incoming messages
    incomingPort.onMessage.addListener(function( msg ){

        if( msg.command === 'get_scripts' ){
            //do work

        }

        var scrs = { 'scripts' : 'name' };
        var result = port.postMessage( scrs );

    });
});

When executing 'port.postMessage(Object obj)' , the plugin throws the following Error,

Error in event handler for 'undefined': Attempting to use a disconnected port object   Error: Attempting to use a disconnected port object
at PortImpl.postMessage (miscellaneous_bindings:54:5)
at chrome-extension://loiamkgdhfjdlkcpehnebipeinpcicfj/swap.js:27:31
at [object Object].dispatch (event_bindings:203:41)
at Object.<anonymous> (miscellaneous_bindings:250:22) event_bindings:207

I have tried using 'Port' object and 'incomingPort' object, both throw the same 'Error'. It feels like it has to do with the scope of the pre-created 'Port' object.

The plugin code is available at this git repository https://github.com/snambi/chrome_plugin/tree/master/src/chrome

What is wrong in this plugin?

Nambi
  • 2,688
  • 8
  • 28
  • 37

1 Answers1

8

I've looked through your code, and it makes no sense to me:

  • Did you know that a port has an onMessage and postMessage method at both sides? One single port is sufficient to communicate in both directions.
  • Communicating between a popup and a content script in your way is going to be terribly hard. It's hard to launch the content script and the pop-up simultaneously.

Since your extension has no background page, and a relatively useless content script, I assume that your extension's core is the browser action popup window. Instead of injecting a content script by default, you can also use the following flow:

  1. User clicks on browser action
  2. popup.html and popup.js are executed.

I've also seen that you're using port == null to check whether a port valid or not. If you do that, make sure that the comparison makes sense, by voiding the variable when the port is disconnected:

var port;
chrome.runtime.onConnect.addListener(function(_port) {
    // ...optional validation of port.name...

    port = _port;
    port.onMessage.addListener(function(message) { /* .. logic .. */});
    port.onDisconnect.addListener(function() {
        port = null;
    });
});
Rafique Mohammed
  • 3,666
  • 2
  • 38
  • 43
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • thanks for going through the code and showing a way. I have tried the one 'Port' method with a 'callback'. Please see the https://github.com/snambi/chrome_plugin/blob/master/src/chrome/popup1.js and https://github.com/snambi/chrome_plugin/blob/master/src/chrome/swap1.js . But, I get the same error in this case too? – Nambi Aug 02 '12 at 22:43
  • @Nambi You're still executing the content script via the manifest file. Make sure thaty ou follow all steps in my answer. – Rob W Aug 02 '12 at 22:45
  • your suggestion works. Now that the plugin works, I would like to use proper messaging between the plugin-popup and content script. Is it bad design? or not a preferred design patter for chrome plugins? – Nambi Aug 02 '12 at 23:48
  • @Nambi Why would it be bad design? It's a solid solution which is working properly. – Rob W Aug 03 '12 at 08:01
  • When the page loads the 'content script' gets executed, tries to send a message and fails. Ofcourse, chrome handles this error. But, it is not an optimal design but it works. if the content script can find the state of the 'Port' ( disconnected , connected etc ), it can be handled better. Is it possible? – Nambi Aug 03 '12 at 19:00
  • @Nambi I don't think that you've followed all of my steps. In your extension, you shouldn't inject content scripts using the manifest file, but using `chrome.tabs.executeScript` in the popup. Then, you'll hardly ever get the error (in rare cases, closing the popup *may* cause a disconnected port error). – Rob W Aug 03 '12 at 19:47
  • chrome.extension.onConnect ? there is no onConnect method in chrome.extension. The onConnect method is in chrome.runtime so it shud be chrome.runtime.onConnect() [https://developer.chrome.com/extensions/runtime#event-onConnect ] – Rafique Mohammed Oct 24 '15 at 10:01
  • 1
    @RafiqueMohammed There is a `chrome.extension.onConnect`, but `chrome.runtime.onConnect` is recommended (for history on this API, see https://stackoverflow.com/a/11811936/938089). The absence of documentation is a bug: https://code.google.com/p/chromium/issues/detail?id=495052 – Rob W Oct 24 '15 at 10:03