yspreen
yspreen

Reputation: 1971

Use function from the main.js in imported module

I'm trying to include IOUtil.js and ChannelReplacement.js in my add-on, using the Cu.import(...) function. These two both use xpcom_generateQI, which I'm trying to obtain from the XPCOM jsm, but the two scripts cant access it.

const {Cc, Ci, Cu, Cr} = require("chrome");

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const xpcom_generateQI = XPCOMUtils.generateQI;
Cu.import(self.data.url("IOUtil.js"));
Cu.import(self.data.url("ChannelReplacement.js"));

gives me xpcom_generateQI is not defined.
How do I access a function which is defined in main.js?

Upvotes: 1

Views: 871

Answers (1)

nmaier
nmaier

Reputation: 33162

Issues

  1. Don't use Cu.import for local SDK modules. Don't write JS code modules for SDK add-ons, the SDK uses CommonJS-style modules together with the require() facility which also comes with proper cleanup for free, which cannot be said for JS code modules and Cu.import (you'd need to properly Cu.unload everything and likely kill some references yourself).
  2. That https-everywhere stuff are neither JS code modules nor SDK modules, but uses the subscript loader. Either convert it to SDK code modules, or use the subscript loader yourself.
  3. It is OK to import built-in JS Code modules in different scopes/modules. There is not actually a need to make available xpcom_generateQI from main (although it can be done; well, get to that).
  4. To be future proof, you should bind your xpcom_generateQI shortcut properly, as in XPCOMUtils.generateQI.bind(XPCOMUtils). Otherwise, if the implementation changes and requires a proper this, your stuff will break.
  5. To export something from any CommonJS module, you need to put it into the exports module. See the first link.
  6. To import something, use require() (first link again).
  7. Be aware of circular references, where Module A imports Module B imports Module A. Right now this kinda works (but only kinda, because some stuff might not be available from Module A when Module B imports it like this, as Module A is not fully loaded). Better avoid it.

Example 1 (circular)

So here is a example with circular require (main imports modules imports main)

main.js

function someFunction() {
  console.log("some function called");
}

exports.someFunction = someFunction;

var mod = require("./module");
mod.anotherFunction();

module.js

const { someFunction } = require("./main");

exports.anotherFunction = function() {
  someFunction();
}

Now, because of circular references this is a fragile construct. If works right now, but when modules get more complex or the SDK changes, it might break... Better put someFunction into a third module.

Example 2 (avoiding circular imports)

main.js

var mod = require("./module");
mod.anotherFunction();

// Or call someFunction directly
var { someFunction } = require("./utils");
someFunction();

module.js

const { someFunction } = require("./utils");

exports.anotherFunction = function() {
  someFunction();
}

utils.js

function someFunction() {
  console.log("some function called");
}

exports.someFunction = someFunction;

There are no circles anymore. If you wanted to reuse xpcom_generateQI, you'd put it as a property of exports in utils.js (in this example) and later require it with require("./utils").

https-everywhere

The https-everywhere stuff needs to be either converted or loaded using the subscript loader. I would recommend against the subscript loader, because in all likelihood the verbatim https-everywhere code does not clean up after itself. I'd actually also recommend against just converting it by throwing some stuff in (exports.xzy = ...). This code is not meant to be run in the SDK. Better create your own implementation and just borrow ideas from https-everywhere where needed.

Upvotes: 3

Related Questions