2

I'm trying to load a custom module in a restartless add-on, using the following:

chrome/content/modules/Test.jsm:

var EXPORTED_SYMBOLS = [ 'Test' ];

let Test = {};

chrome.manifest:

content   test  chrome/content/

bootstrap.js:

const Cu = Components.utils;

// Tried this first, but figured perhaps chrome directives aren't loaded here yet
// let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;

function install() {
  let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function uninstall() {
  let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function startup() {
  let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function shutdown() {
  let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}

However, I get the following types of WARN messages (this one was for shutdown(), but basically identical for all functions and in the earlier attempt in the global scope):

1409229174591 addons.xpi WARN Exception running bootstrap method shutdown on test@extensions.codifier.nl: [Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXPCComponents_Utils.import]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: resource://gre/modules/addons/XPIProvider.jsm -> file:///test/bootstrap.js :: shutdown :: line 21" data: no] Stack trace: shutdown()@resource://gre/modules/addons/XPIProvider.jsm -> file:///test/bootstrap.js:21 < XPI_callBootstrapMethod()@resource://gre/modules/addons/XPIProvider.jsm:4232 < XPI_updateAddonDisabledState()@resource://gre/modules/addons/XPIProvider.jsm:4347 < AddonWrapper_userDisabledSetter()@resource://gre/modules/addons/XPIProvider.jsm:6647 < uninstall()@extensions.xml:1541 < oncommand()@about:addons:1 <

Are chrome.manifest directives not yet available in bootstrap.js? Or is what I am attempting some kind of security violation, perhaps? Or am I simply doing something trivially wrong?


What I was hoping to achieve, is that I could do something like the following:

chrome/content/modules/Test.jsm:

var EXPORTED_SYMBOLS = [ 'Test' ];

let Test = {
    install: function( data, reason ) {
    },

    /* etc */

    bootstrap: function( context ) {
        context.install = this.install;
        context.uninstall = this.uninstall;
        context.startup = this.startup;
        context.shutdown = this.shutdown;
    }
}

bootstrap.js:

const Cu = Components.utils;
Cu.import( 'chrome://test/modules/Test.jsm' );
Test.bootstrap( this );

Perhaps it's a bit over the top to begin with, but I just kind of like the idea of hiding implementations in modules and/or objects and keeping bootstrap.js super clean.

If you happen to have suggestions on how to achieve this by other means: I'm all ears.

Codifier
  • 354
  • 1
  • 14

2 Answers2

2

Yes you can your path is wrong though.

Just do this:

let test = Cu.import( 'chrome://test/content/modules/Test.jsm', {} ).Test;

notice the /content/

You don't have to do the .Test unless you want the lower case test to hold it. You can just do:

Cu.import( 'chrome://test/content/modules/Test.jsm');

and use as Test.blah where blah is whatever is in the JSM module.

This code can go anywhere, it does not have to be in the install function.

Make sure to unload the custom JSM modules or else it can lead to zombie compartments which is bad for memory. Read here:

Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • Thank you for your answer Noitidart! I will try this out later, but I trust that it works. But please help me understand, if you will: why is //**content**/modules needed here, while that was not needed when I was using a `resource://` namespace in a non-restartless version, for instance. (Unfortunately, resources are not allowed in bootstrapped add-ons, as you probably know already). I mean, isn't the directory `content` already defined in the directive `content test chrome/content/`? Why do I still need to add it in the url? And where can I find out more about this mechanism? – Codifier Aug 28 '14 at 15:44
  • PS.: I was aware of the possible memory leaks already. But thank you anyway, for the heads-up! – Codifier Aug 28 '14 at 15:45
  • It's just how chrome.manifest stuff works they made it that way :) – Noitidart Aug 28 '14 at 17:22
  • Resource paths dont were not made to be like chrome paths which are registered via manifest. I think this was api developer decision. – Noitidart Aug 28 '14 at 17:23
  • 2
    I've tested your suggestion now. However, the module is only available in `startup()` and `shutdown()`, unfortunately; not in the global scope, or the other functions. In those it warns: `No chrome package registered for chrome://test/content/modules/Test.jsm`. I was hoping I could completely delegate bootstrapping to my jsm module, by doing something like `Test.bootstrap( this );`, but that is a no-go now, it seems. I'll update my question with an example of what I was hoping to achieve. Perhaps you, or anybody else, still has some ideas of how to achieve something similar. – Codifier Aug 28 '14 at 18:02
  • 2
    Thats interesting I didnt know that. I thought once chrome.manifest registerd you can use it wheever in your boostrap.js, ok thats a new one for me. thxnk you';re right i had done some experimenting and startup is the earliest you can call it: https://gist.github.com/Noitidart/9045387 – Noitidart Aug 28 '14 at 18:31
1

Beyond @Noitidart's answer, you don't have to use chrome.manifest' and register a content package if your only concern is how to import your module.

function install(data, reason) {
  Components.utils.import(data.resourceURI.spec + "relative/path/to/your/module.jsm");

}
paa
  • 5,048
  • 1
  • 18
  • 22
  • To do this way, make sure its in the `install` or `startup` functions, they both have this first argument of `data` (well so do shutdown and uninstall but thats more important for `unloading` the module). Or if you want to do it outside the install function, set global var or somethign to `data` arg of install. See here for whats contained in the data object: https://gist.github.com/Noitidart/9025999#comment-1120821 – Noitidart Aug 28 '14 at 15:16
  • Ah, this is good to know as well. Thank you. I prefer the solution that I can use outside of the functions as well, at the moment though. – Codifier Aug 28 '14 at 15:48
  • You wouldn't happen to know of a way to make this work in global scope, would you? (Probably not, since it makes sense to only have `resourceURI.spec` available in the functions), but please see my questions edits, for what I was hoping to achieve. Perhaps you have some more ideas. Thank you. – Codifier Aug 28 '14 at 18:11
  • 2
    If your aim is to keep `bootstrap.js` minimal you might be satisfied with an [`include()` function](https://gist.github.com/erikvold/1024242) utilizing `loadSubScript` – paa Aug 28 '14 at 21:45
  • Thanks! In the meantime I found out about `__SCRIPT_URI_SPEC__` (which he utilizes) as well, and *that* was the kind of thing I was hoping to find. If put a reference to it in your answer, I'll mark is as best. – Codifier Aug 29 '14 at 06:40