1

I am trying to load a frame script following this tutorial:

mm.loadFrameScript("chrome://myextension/content/content.js", true);

My extension is an Add-on SDK type. The tutorial says I need to specify content in chrome.manifest first. I did not even have that file (only package.json and index.js). So I've created myextension/chrome.manifest with a single line:

content content.js

And created a file myextension/content/content.js:

console.log("content script executed");

The problem is, when mm.loadFrameScript("chrome://myextension/content/content.js", true); is executed in index.js, I get error:

No chrome package registered for chrome://myextension/content/content.js

I guess it is because the manifest file is wrong or not being registered all together? But I couldn't find any clues to my problem on the chrome registration page.

Makyen
  • 31,849
  • 12
  • 86
  • 121
alandarev
  • 8,349
  • 2
  • 34
  • 43

2 Answers2

2

That tutorial is generally targeted towards XUL or restartless/bootstrap add-ons. A more appropriate tutorial in that hierarchy is: Multiprocess Firefox and the SDK. The gist of that page is that if you stay with the Add-on SDK APIs your extension should just work in multiprocess Firefox, and that if it doesn't then it is a bug in the Add-on SDK.

In general, Add-on SDK extensions will use one of the High Level APIs to load content scripts. The primary APIs which would be used are tabs and page-mod, but there are others (e.g. context-menu and page-worker). There are also the Low-Level APIs of remote/parent and remote/child which deal with processes and frames.

However, you can use frame scripts if you desire to do so. Add-on SDK extensions are actually restartless/bootstrapped extensions which are wrapped by the add-on SDK. Thus, you can do most things which can be done in a bootstrapped extension within an Add-on SDK extension if you really want to do so. However, it is better to stay within the APIs provided by the Add-on SDK. If you go around those APIs then you loose some of the advantages which the Add-on SDK exists to provide to you (e.g. hiding the actual implementation behind APIs which are intended not to change).

Frame scripts and content scripts exist to perform the same function: access the content (e.g. HTML pages) which has been loaded into an area that is potentially under the control of a different process (e10s). Largely, the things that are referred to by the two different names are very similar. However, you will almost exclusively see the term "frame scripts" used only for XUL and bootstrap extensions while "content scripts" will almost always be referring to Add-on SDK scripts.

Again, you are probably better off using the Add-on SDK APIs to load the scripts you are using to access content that is potentially in another process.

Add-on SDK: Using the data directory:

For an Add-on SDK extension, instead of using a chrome:// URL it is more appropriate to use the [add-on base directory]/data/ directory and obtain the URL reference to your file using the sdk/self API. You would do this with:

var self = require("sdk/self");
let frameScriptUrl = self.data.url("content.js")

Then your loadFrameScript() line would be:

mm.loadFrameScript(frameScriptUrl, true);

Using chrome.manifest:

content lines:
The content line of the chrome.manifest file is:

content packagename uri/to/files/ [flags]

This is a minimum of 3 fields separated by whitespace with one or more optional additional fields for flags.

The first field is content which indicates that this is a line that defines how a chrome://packagename/content URL will be resolved.

The second field is a packagename. This is a name that you make up which must not conflict with other package names already in use by Firefox or those added by other extensions. Usually, this will be the name you are using for your add-on, or some permutation of the name, or id, if using multiple content lines. The name and ID of your Add-on SDK are usually the value of the name and id properties you included in your package.json file, but may be somewhat different. The packagename does not need to be your name or ID, it just needs to be unique to everything that was loaded into Firefox.

The third field is the URL to the directory which contains the files you are going to be referencing. This URL can either be absolute, or relative to the location of the chrome.manifest file. This URL must end with a /.

Firefox looks for the chrome.manifest file in the base directory of your add-on (the same one in which package.json is located). While it is possible to have additional chrome.manifest files using the manifest keyword, that would be unusual.

The prototypical add-on chrome.manifest would contain a line such as:

content packagename chrome/content

When using the chrome URLs made valid by that content line in your chrome.manifest you would use something like chrome://packagename/content/myScriptFile.js. This would reference a file called myScriptFile.js that is in the [add-on base directory]/chrome/content/ directory.

Another example:
chrome.manifest:

content myAddOnName my/special/directory/

In this case, chrome://myAddOnName/content/myScriptFile.js would reference the file [add-on base directory]/my/special/directory/myScriptFile.js.

Your specific issue:
While you stated you were following the tutorial, you did not actually do so for the contents of your chrome.manifest file. Nor when you changed what that file contained did you follow the description of what the content line should contain. However, even if you had followed the tutorial exactly, you would not have ended up with a functioning add-on because the tutorial was incorrect as to what should be in that file. The line in the tutorial was actually invalid. I have corrected that line in the MDN documentation.

What you need to use as the line in your chrome.manifest will depend on the directory structure you desire to use for your extension.

If you wanted your content.js to exist in a directory [add-on base directory]/chrome/content/ and be referenced by chrome://myAddOnName/content/content.js then the content line of your chrome.manifest would be:

content myAddOnName chrome/content/

Note: Even though you used myextension in your question (in your chrome:// URL only) for your packagename, I have not used it here to try to more clearly indicate that the packagename should be a name you choose which is unique to your add-on. It is not clear to me that you are using myextension in your question as a placeholder for what you are really using within your extension. If that is the actual text you are using rather than a placeholder for your question, then I would caution you that the packagename myextension is not very unique and has a reasonable chance to exist in some other random extension. If it does, it may, or may not, cause either or both of your extensions to malfunction.

Makyen
  • 31,849
  • 12
  • 86
  • 121
  • I appreciate such a detailed answer. You talk about content scripts and frame scripts. You suggest to use content scripts in Addons SDK because it is covered by SDK. Can you tell me if content script is possibly in my use case: I need to use `nsITextInputProcessor` Low level API in that tab. Here is a stackoverflow answer which suggested me to use frame scripts: http://stackoverflow.com/a/37526708/1132711 – alandarev Jun 20 '16 at 07:28
  • @alandarev, In the comments on that answer, I suspect that "frame scripts" were understood to mean any scripts, including content scripts, which run in the process controlling the web page content. I suggest that you start a new question. Make that question about your overall goal implemented in the Add-on SDK, not specific to how you are currently attempting to implement it. Do include the code you are currently trying to use, but as something like "I have attempted to accomplish this with A) code, reasons why it did not work for you; and B) code, reasons why it did not work for you; etc. – Makyen Jun 20 '16 at 15:08
2

The SDK provides an abstraction for frame scripts and process scripts (beyond the page-mod and tab attach mechanisms which also rely on frame scripts under the hood), the remote/parent and remote/child modules. You can use remote_require to load a process script and then use remote/child in the process script to enumerate the sdk wrappers for the frame script global objects.

the8472
  • 40,999
  • 5
  • 70
  • 122