Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a web extension need to explicitly load content scripts?

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?

like image 230
lhk Avatar asked Sep 14 '17 14:09

lhk


1 Answers

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.

like image 96
Xan Avatar answered Oct 23 '22 05:10

Xan