Content script fails to get installed

I find it very discouraging developing firefox extensions! Nothing ever works! It’s so complicated to get things right.

I declared the content scripts in the manifest.json as follows:

"content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["/scripts/selection.js", "/scripts/sort.js", "/scripts/exif.js", "/scripts/RGraph.svg.common.core.js", "/scripts/RGraph.svg.line.js", "/scripts/search_results.js", "/scripts/exif_tags.js"]
    }
  ]

I’m most concerned with the selection.js script at present. It should be receiving a message from the background script, but instead I’m getting the following error msg:

Error: “Could not establish connection. Receiving end does not exist.”

Furthermore, looking at the web console under the various open tabs I see no console logs at all. Yet, I have placed some console.logs in the script. It’s like something is preventing the content script from being loaded.

As per the MDN documentation, I then tried adding the following code to get the content script to load by calling register() if the value of registered is null:

async function register() {
    registered = await browser.contentScripts.register({
        matches: ["<all_urls>"],
        js: [{file: "/scripts/selection.js"}],
        runAt: "document_end"
    });
}

but that doesn’t seem to work either! Help!..

So a couple of things that I wonder about based on this description:

  • Where are you testing this? Your script will only load in remote websites.
  • Are you waiting for your content script to be loaded before you send the message in the background script or just blind fire based on some event?
  • The console should show your logs if the script was loaded, so something may not have matched up there. You can easily find out by looking for your content scripts in the debugger or in the frame selector.

I’m testing with the Addon debugger. Occasionally, I would click the ‘Reload’ button whilst some tabs are open, as shown in this screenshot below.

At first, I was just blind firing, then I used the register code above just before sending messages from the bg script to the content script.

Can you see your content scripts in the page’s web dev tools? They should show up there while they are running.

Oh, also, register doesn’t guarantee that the content script is actually running after it resolves, since the script will only be executed once the page is idle, as you specified and it will attach to any and all tabs, so it can’t know if the script is running yet.

I don’t see the content script anywhere. There should be a selection.js file showing, but it’s clearly missing so I believe it’s not getting loaded at all.

Aside from that, I only send a message to the content script after having .then (ed) register().

Btw, thanks for helping out!

That will not work at all in most cases. A much more robust protocol would be to send a message from the content script that the bg replies to, since every tab (and frame!) gets its own instance that may load at various times.

Does the content script attach any listeners or similar? If it doesn’t have anything that should hang around, it won’t. Other than that, make sure it doesn’t have syntax errors, you have the permissions (so <all_urls>) and that the path is correct (I’d personally use browser.runtime.getURL). I don’t see any obvious reason why else it wouldn’t load based on what you’ve shown.

Hi Martin, I found what is causing the problem, but I haven’t found why!

When the following code is added to my content script selection.js, none of the content scripts get loaded, and that is even without calling the function! Merely adding this function to the content script prevents all content scripts from being loaded!

Here is the function which is supposed to convert any ‘url’, namely relative, to an absolute url: (‘base’ represents the tab url and ‘url’ an image url)

function absoluteUrl(base, url) {
    // If the url is absolute, i.e. begins withh either'http' or 'https', there's nothing to do!
    if (/^(https?\:\/\/)/.test(url)) return url;
    // If url begins with '//'
    if (/^(\/\/)/.test(url)) {
        return 'https:' + url;
    }
    // If url begins with '/' (and not '//' handled above)
    if (/^\//.test(url)) {
        let parts = url.split("/");
        parts.unshift(domain);
        return parts.join("/");
    }
    // If url begins with an alphanumerical character
    if (/^([a-zA-Z0-9]))/.test(url) && /^(?!file|gopher|ftp\:\/\/).+/.test(url)) {
        return domain + "/" + url;
    }
    // If url begins with './' or '../'
    if (/^(\.\/|\.\.\/)/.test(url)) {
        let stack = base.split("/");
        let parts = url.split("/");
        stack.pop(); // remove current file name (or empty string)
                    // (omit if "base" is the current folder without trailing slash)
        for (let i=0; i<parts.length; i++) {
            if (parts[i] == ".") continue;
            if (parts[i] == "..") {
                stack.pop();
            } else {
                stack.push(parts[i]);
            }
        }
        return stack.join("/");
    }
}

eslint says that you have an unmatched ) in the regexp /^([a-zA-Z0-9]))/. After that we still get a couple of errors, but none that would prevent execution of the script (just it potentially misbehaving).

Hi Martin,
A BIG THANK YOU for your precious help. I wasn’t familiar with eslint. I really have to learn to use that debugging tool in VS Code. Removing the ) fixed things. It’s crazy that a simple ) can prevent all content scripts from loading. I then encountered another issue because I used a variable with the name pathName. That actually prevented one of my background scripts from loading, for some reason!?! Anyway, I got that fixed as well.
Thanks to your help I’ll soon be able to release a new update to my extension. Sadly, I wasn’t able to find a solution to present search results in the sidebar when using the grid of favicons.
Would be nice to have your feedback if you have the time to give it a try…

I had the same issue. No content_scripts was loading with no warning and no error in the developer console of firefox but I could find my issue by adding “–v” (verbose) argument to web-ext (web-ext run --source-dir ./dist -v) in develop mode.

Note: The extensions works fine chrome but not in Firefox.