Can I load custom jsm modules in bootstrap.js of a restartless add-on?

1k Views Asked by At

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 [email protected]: [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.

2

There are 2 best solutions below

5
On

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");

}
6
On

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: