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
exportsorthis.exports. I believe that the easiest way to do this is to patchmozJSComponentLoaderto detect such globals and MOZ_ASSERT(false). Rewrite code that violates this invariant. - Patch up
mozJSComponentLoaderto inject a globalexportsin loaded files. - Patch up
mozJSComponentLoaderto useexportsinstead ofEXPORTED_SYMBOLSif available. - Code a rewriting script to migrate as many jsm, tests as possible to use
exportsautomatically. - 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
mozJSComponentLoaderto 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 themozJSComponentLoaderis 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
requireorthis.require. I believe that the easiest way to do this is to patchmozJSComponentLoaderto detect such globals and MOZ_ASSERT(false). Rewrite code that violates this invariant. - Patch up
mozJSComponentLoaderso thatCu.importauto-exports code published throughEXPORTED_SYMBOLSbut not exports. - Patch up
mozJSComponentLoaderto introduce a global functionrequirewith the following semantics:
function require(url) {
Cu.import(url).exports
}- Code a rewriting script to migrate as many jsm, tests as possible to use
requireautomatically. - 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
mozJSComponentLoaderto introduce a functionlazyRequirewith the same semantics asdefineLazyModuleGetterand the same signature asrequire. - Rewrite our code to use
lazyRequireinstead ofdefineLazyModuleGetter. - Either teach our static analysis tools that
lazyRequireisrequireor introduce a rewriting step before static analysis to replacelazyRequirewithrequire.