I needed a Chrome extension that could open my single-page application and send any text field to it, and after editing, send the changes back to the field. Sounds simple, but it led me down many dead ends and complex APIs. The first catch was that chrome.windows.create can take a callback which gets a window object, but this is a https://developer.chrome.com/extensions/windows#type-Window object and not a ref to the actual new window, so all the StackOverflow posts saying you can set variables/functions on it didn’t work out. The second option I tried was chrome.tabs.executeScript, which let me manipulate the DOM in the new window, but not set variables on the window or anywhere. I could send the initial text via the DOM, but then there was no way to communicate changes back to my extension.

The best way to set up bi-directional comms is with https://developer.chrome.com/extensions/messaging#external-webpage. Let the SPA request the text when it’s ready, then send changes back via the same bus.

Background.js:

var selectedContent = null;
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    console.info("------------------------------- Got request", request);
    if (request.getSelectedContent) {
      sendResponse(selectedContent);        
    }
  });

Manifest.json:

The ids here are the extension IDs you wish to communicate with, can be “*” for all.

"externally_connectable": {
  "ids": ["naonkagfcedpnnhdhjahadkghagenjnc"],
  "matches": ["http://localhost:1338/*"]
},

Web app:

// extension ID is a hash generated from your extensions public key, so in development it’ll be generated when you load your unpacked extension, but when packaged it’ll be static

var extensionId = "naonkagfcedpnnhdhjahadkghagenjnc";
chrome.runtime.sendMessage(extensionId, {getSelectedContent: "true"},
  response => {
    console.info("----------------- Got response", response);
    if(response) {
      this.text = response;
    }
});

Leave a Reply