Thordax Thordax - 9 days ago 5
Javascript Question

Firefox WebExtension : check if extension already exists

I'm porting my Chrome extension to a Firefox WebExtension, so far so good, I manage to communicate smoothly with my content, background scripts and my executable.

I would like now to check the existence of my extension. This is actually the way I do it :


Browser script


// browser-script.js

var isExtensionHere = false;

$("#is-extension-here").click(function(){

console.log("Check the existence of the extension");

window.postMessage({
direction: "from-page-script",
message: "areYouThere"
}, "*");
});

window.addEventListener("message", function(event) {
if (event.source == window &&
event.data.direction &&
event.data.direction == "from-content-script") {
if(event.data.message == "OK") {
isExtensionHere = true;
}
}
});



Content Script


// content-script.js

window.addEventListener("message", function(event) {
if (event.source == window &&
event.data.direction &&
event.data.direction == "from-page-script") {

if(event.data.message == "areYouThere") {
window.postMessage({
direction: "from-content-script",
message: "OK"
}, "*");
}
}
});


It works fine when the extension is here. But when it is not, obviously I don't get an answer from my extension. How can I know then how to trigger a popup or a message when the extension is not here ?

Xan Xan
Answer
  1. You can reverse the logic: make the page listen for a ping from the extension. You need to be mindful of when scripts execute (e.g. depending on run_at parameter) in relation to each other, so that you don't accidentally send a message before the page starts listening.

  2. You can use another method of announcing presence to the page: a content script can add an invisible DOM element with a known ID, and you can check for its presence from the page.

  3. If you want to keep the current approach, you can set a timer for the response to happen. Something like, say, 200ms should be more than enough.

    You can implement this as a Promise, since it can only be resolved once:

    var isExtensionHere = new Promise((resolve, reject) => {
      const listener = (event) => {
        if (
          event.source == window && event.data.direction
          && event.data.direction == "from-content-script"
          && event.data.message == "OK"
        ) {
          resolve(true);
        }
      }
    
      setTimeout(() => {
        window.removeEventListener("message", listener);
        resolve(false); // Will have no effect if already called with true
      }, 200);
    
      window.addEventListener("message", listener);
    
      window.postMessage({
        direction: "from-page-script",
        message: "areYouThere"
      }, "*");
    });
    
    // Sometime later
    isExtensionHere.then((result) => { /* ... */ });
    

    If you want to dynamically re-check, make isExtensionHere a function that returns a new Promise every time.

Comments