Using browser.scripting.executeScript in event listeners while upgrading to Manifest V3

Hi all,

I have been working on upgrading my add-on from Manifest V2 to V3. However, I have been running in a few problems.

Context: My add-on is a simple pop-up that modifies JS on the webpage that it is opened on via content scripts. The add-on works in 2 steps:

  • Step 1: the scripts are all injected when the popup is opened.
  • Step 2: a checkbox input is used to allow the users to remove the visual modifications that the JS scripts added to the page, or to add them back.

I successfully updated my code for step 1 to work as shown below:

async function getCurrentTabId() {
    let queryOptions = {
        active: true,
        currentWindow: true
    };
    let [tab] = await browser.tabs.query(queryOptions);
    return await tab.id;
}

window.onload = async () => { // https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
    browser.scripting.executeScript({
        target: {tabId: await getCurrentTabId()},
        files: [
            "/browser-polyfill.min.js",
            "/content_scripts/create_total_cards_button.js",
            "/content_scripts/create_avg_cards_button.js",
            "/content_scripts/show_card_counters.js"
        ]
    });
};

However, for step 2, when trying to follow the same logic for the event listener, it didn’t seem to work as expected. My function was originally not an async function, but I had to transform it to an async one to be able to retrieve the current tab id:

document.addEventListener("click", async (e) => {
    let currentTabId = await getCurrentTabId();

    // Show the  number of Trello card in each column.
    if (e.target.checked === true) {
        browser.scripting.executeScript({
            target: {tabId: currentTabId},
            file: "/content_scripts/show_card_counters.js"
        });
    }

    // Hide the  number of Trello card in each column.
    if (e.target.checked === false) {
        browser.scripting.executeScript({
            target: {tabId: currentTabId},
            file: "/content_scripts/hide_card_counters.js"
        });
    }

});

Any idea what could be going wrong? Am I tackling this problem with the wrong logic?

Also, another small problem I ran into is when executing web-ext lint in the command line to make sure everything is fine with my add-on I get the following error:

Thanks in advance for the help!

You don’t need the “await” keyword in the last line.
This works:
return tab.id;

“await” is only needed for Promises.

1 Like

Firefox doesn’t support Manifest V3 just yet, but they promised to finish till the end of the year:

So if you want to release both now, you will need separate manifest file for each browser.
Additionally you need to use “feature detection” in your code to decide which script injection API to use. Something like:

if (browser.scripting) {...}

Hi hans_squared,

Thanks for your answer! I’ve removed the await keyword from the return statement, but I am still getting errors for the 2 browser.scripting.executeScript() function calls inside the event listener.

Any idea what else could be causing this?

I’ve tried on both Firefox and Chrome and getting the same error:

Thanks!

Hi again Juraj!

Ok I see, I thought that Manifest V3 was already supported on Firefox, so I was trying to upgrade to V3 to get a single extension for both Firefox and Chrome!

I’ll just keep 2 separate versions for now then!

Cheers :slight_smile:

I don’t know… but if you upload your extension somewhere, we have a better chance of diagnosing the problem.

You need to read errors more - “unexpected property ‘file’”. That should tell you that your call is not correct.
And then when you check the docs, you’ll see the scripting API uses different parameters:

MDN: https://developer.mozilla.org/en-US/docs/mozilla/add-ons/webextensions/api/scripting/executescript
Chrome dev: https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript

Sorry about that I was confused and thought the scripting API would be the same for Chrome and Firefox, as my goal was to write a single extension that would work for both browsers. Might just duplicate the extension’s code and just make it work for Chrome separately then!

Thanks for the help though, you’ve helped me learn a whole lot about cross-browser extensions and manifest V3! :slight_smile:

For sure don’t duplicate code for each browser, that would be maintenance hell :slight_smile:.

Also, “scripting” API is available in Firefox 101, so only ESR 91 doesn’t have it. But there is new ESR 102 being released in 3 weeks so soon all Firefox users will have that API.
https://developer.mozilla.org/en-US/docs/mozilla/add-ons/webextensions/api/scripting/executescript#browser_compatibility

If you need a change behavior in one browser and not other, use “feature detection” as I’ve mentioned before, for example:

if (browser.scripting) {
  // use scripting API
}
else {
  // use tabs.executeScript API
}

The only issue is the manifest file, it would be best to bundle Firefox and Chrome with a separate manifest files. You can write a simple “batch” script that copies files and folders into some “dist_chrome” and “dist_firefox” folder, each with own specific manifest file.

1 Like