Like @felix-kling already mentioned, that's due to module level isolation and it makes a lot of sense if you think about it. If it was otherwise not only Services
would be seen by other modules, but also abc
.
There is another important reason, though:
Since JS code modules are initiated once and cached after that, what would happen if you imported two.jsm
twice, once from a module already having imported Services.jsm
and once from another module not having done so? Now two.jsm
"seeing" Services
would depend on which of the other modules was imported first! Which would be extremely nasty.
In that context, your comment about "abc is imported into obj()" is wrong. Your code actually imports abc
into the top-level scope. Cu.import
will always import into the top-level scope, unless you explicitly specify another scope to import to.
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // true
"abc" in obj; // false!
If you wanted to import two.jsm
into obj
, you'd need to call Cu.import
with a second argument.
let obj = {
init: function() {
Components.utils.import('chrome://myaddon/modules/two.jsm', this);
}
};
"abc" in this; // false
"abc" in obj; // false
obj.init();
"abc" in this; // false
"abc" in obj; // true
But that does not affect the visibility of Services
, of course.
It would be helpful I guess, if Cu.import
just auto-imported some modules you'd import anyway, such as Services.jsm
and XPCOMUtils.jsm
. But this does not and likely will not ever happen due to legacy reasons and backward-compatibility constraints. (E.g. I had code break that imported const {Promise} = Cu.import(..., {});
because ES6 added a default Promise
global...; that kind of backward-compatibility issues/constraints).
Alternatives?
Well, the obvious one is not to use Cu.import
for your own stuff, but use something else. A bunch of add-ons, incl. all SDK add-ons of course, have their own CommonJS-style require()
implementation.
- You can actually re-use the SDK loader, without using the SDK, or with only using selected parts of the SDK if you like. See the
loader
documentation. I know that Erik creates a loader in the otherwse non-SDK Scriptish add-on.
- You can write your own custom loader based on the subscript loader and maybe
Sandbox
. E.g. I did so in my extSDK
boilerplate (all global symbols in loader.jsm == loader.jsm::exports
will be visible to each require
d module).
But doing so may require a quite bit of extra work, extra knowledge, and effort to port existing JS code modules to require()
based modules.