Does a web extension need to explicitly load content scripts?
Asked Answered
C

2

6

I'm trying to write a simple Web Extension. Currently I'm following the various tutorials and trying to understand the architecture.

Interaction with specific tabs is done with content_scripts that are injected into the source code of a website. It seems to me, as if content_scripts are loaded automatically: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Content_scripts

A tutorial on MDN makes this even more clear:

This script will be loaded into the pages that match the pattern given in the content_scripts manifest.json key. The script has direct access to the document, just like scripts loaded by the page itself.

My extension is supposed to offer a context menu on every text selection. As a starting point, I found a useful sample extension for chrome. You can find it here https://developers.chrome.com/extensions/samples, it is called "speak selection"

This extension is reading selected text with a tts engine. But one part of the sourcecode is confusing: They have an explicit function to run content_scripts in tabs. This code is executed as part of an Init() function in one of their background scripts:

function loadContentScriptInAllTabs() {
  chrome.windows.getAll({'populate': true}, function(windows) {
    for (var i = 0; i < windows.length; i++) {
      var tabs = windows[i].tabs;
      for (var j = 0; j < tabs.length; j++) {
        chrome.tabs.executeScript(
            tabs[j].id,
            {file: 'keycodes.js', allFrames: true});
        chrome.tabs.executeScript(
            tabs[j].id,
            {file: 'content_script.js', allFrames: true});
      }
    }
  });
}

As far as I can see, the code is executed as soon as the browser starts. Isn't that redundant ?

Their manifest.json should take care of the content_script execution, here is the relevant code:

"content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "all_frames": true,
      "js": [
        "keycodes.js",
        "content_script.js"
      ]
    }
  ],

What is the proper way to inject a script into every open tab?

Chavey answered 14/9, 2017 at 14:23 Comment(0)
B
8

Short answer: it's needed in Chrome but not Firefox.


Chrome does not load content scripts into matching pages at extension load (which includes extension updates, not just initial load).

So if you want content script functionality in tabs open at extension load (as opposed to future navigations), this code (or similar) is needed.

You can modernize this code a bit with chrome.tabs.query.


Firefox is incompatible with Chrome in this regard: it does automatically inject content script in everything that matches at load time. So you should employ some browser detection and/or inject-only-once guard code.

I wish they didn't introduce that as a breaking change. It would make sense to at least provide a manifest key to choose the behaviour for ease of transition.


Note: in an extension reload scenario content scripts from old instance continue to exist (but extension APIs will fail); it's your responsibility to handle that gracefully.

Bennington answered 14/9, 2017 at 14:33 Comment(1)
thanks for the quick answer. and the link you included to your previous answer is incredibly helpfulChavey
C
0

You can explicitly load content (foreground) pages into any tab, or create a tab then load a content page. Do this from the background script. You don't need entries in the manifest file other than requiring active tab permission.

browser.tabs.executeScript(null,{file:"/content.js"}).then(NextAction);
function NextAction(Array of last evaluated statement of foreground script in each frame)
   {...}
Contiguity answered 27/12, 2018 at 13:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.