Even if we move to RequireJS modules, we still need to keep a version of Cu.import
to avoid breaking Thunderbird and add-ons. Maintaining this version of Cu.import
should also help with migrating some corner case modules, tests, etc.
The following steps are designed so that we can land them one at a time:
- Ensure our .jsm don't define a global
exports
orthis.exports
. I believe that the easiest way to do this is to patchmozJSComponentLoader
to detect such globals and MOZ_ASSERT(false). Rewrite code that violates this invariant. - Patch up
mozJSComponentLoader
to inject a globalexports
in loaded files. - Patch up
mozJSComponentLoader
to useexports
instead ofEXPORTED_SYMBOLS
if available. - Code a rewriting script to migrate as many jsm, tests as possible to use
exports
automatically. - Start to migrate manually code that hasn't migrated yet.
- (later) Eventually, at least in Firefox, start printing warnings for code that defines
EXPORTED_SYMBOLS
/this.EXPORTED_SYMBOLS
.
- Ensure our .jsm don't overwrite properties of globals (Object, String, ...). I'm not exactly sure how we can guarantee it, but I suspect that we can MOZ_ASSERT this in one of our many wrappers. Also, once we have static analysis running on JS, this can be moved to one of our linters.
- Patch up
mozJSComponentLoader
to always reuse the same compartment when there is no add-on id (optionally, we could also collapse to one compartment per add-on id, but I'm not sure it's worth the trouble). At this stage, in a module, code executed upon load by themozJSComponentLoader
is executed with the following semantics:
var initializer = new Function("exports", sourceCode);
var exports = {};
var self = { exports: exports };
initializer.bind(self)(exports);
Object.freeze(exports);
Note: at this stage, we still need a way to access BackstagePass
.
Note: This does not cover DevTools/Jetpack code, which relies upon an implementation of require
. We probably should not touch this code. I assume that it's easy to make the difference.
Note 2: I have found exactly 2 uses of Cu.unload
in our code, I hope that we can rewrite around them.
- Ensure our .jsm don't define a global
require
orthis.require
. I believe that the easiest way to do this is to patchmozJSComponentLoader
to detect such globals and MOZ_ASSERT(false). Rewrite code that violates this invariant. - Patch up
mozJSComponentLoader
so thatCu.import
auto-exports code published throughEXPORTED_SYMBOLS
but not exports. - Patch up
mozJSComponentLoader
to introduce a global functionrequire
with the following semantics:
function require(url) {
Cu.import(url).exports
}
- Code a rewriting script to migrate as many jsm, tests as possible to use
require
automatically. - Start to migrate manually code that hasn't migrated yet.
- (later) Eventually, at least in Firefox, start printing warnings for code that uses
Cu.import
.
- Patch up
mozJSComponentLoader
to introduce a functionlazyRequire
with the same semantics asdefineLazyModuleGetter
and the same signature asrequire
. - Rewrite our code to use
lazyRequire
instead ofdefineLazyModuleGetter
. - Either teach our static analysis tools that
lazyRequire
isrequire
or introduce a rewriting step before static analysis to replacelazyRequire
withrequire
.