This document shows a possible migration path from Cu.import()
to ES6 modules for the code of Firefox.
Add-ons and Thunderbird should not be affected by the migration.
- Make sure that calling ES6
import foo
in chrome code always returns the same object regardless of the global from which it is called, as is the case currently withCu.import()
. - Make sure that evaluating
import foo
in chrome code blocks the embedding as is the case currently withCu.import()
. - Inform developers that they should now use ES6 modules instead of jsm for their new code.
- Reject patches that introduce new jsm modules. Optionally, patch mozReview to do this automatically.
@jonco, how hard are 1. and 2.?
- Patch
mozJSComponentLoader
to acceptexport { a, b, c }
instead ofEXPORTED_SYMBOLS
when available. For compatibility with add-ons and Thunderbird,EXPORTED_SYMBOLS
will remain usable as long asCu.import()
exists. - Start migrating the code from
EXPORTED_SYMBOLS
toexport
. An automatic rewrite should cover most cases.
@jonco, how ard is 1.?
- Patch
mozJSComponentLoader
so thatCu.import(foo)
andimport foo
from chrome code access the same singleton. Essentially,Cu.import()
becomes a variant ofimport foo
that returns a backstage pass instead of only the symbols actually exported. Keeping this compatibility will be necessary to ensure that we can migrate piecewise without breaking the unicity of module instances, as well as for compatibility with add-ons, Thunderbird. - Inform developers that they should now use
import foo
in their new code, rather thanCu.import()
. - Reject patches that introduce new instances of
Cu.import()
. Optionally, patch mozReview to do this automatically. - Start migrating the code from
Cu.import()
toimport foo
. An automatic rewrite should cover most cases.
@jonco How hard is 1?
At this stage, we will still have the following cases to contend with:
- uses of
XPCOM.defineLazyModuleGetter
; - conditional imports;
- scoped imports and imports from within a function.
As far as I can tell, none of these cases has a simple counterpart in ES6 modules. I believe, however, that once we have reached this stage, we will have improved considerably the state of our codebase and gained experience that we may then use to handle the missing cases.
Eventually, we may also want to get rid of backstage passes.
In response to @jorendorff:
It is my understanding that this is the intended semantics of modules (although, yes, the implementation will need to differ): one instance of one application (== one page in one tab) only has one instance of each module, right?
I believe that the oddity here is the fact that we have XUL windows and XPCOM components and all sorts of containers (and globals) for a single application. I would say that they are the one that have non-web semantics but that they shouldn't bring down the whole ship with them.
True. I don't think that this is a problem in practice, though, because jsm code typically imports modules before starting. I'm planning to use
Cu.import()
as a crutch for lazy loading until we have a better solution.See above, I'm actually hoping that we can use
Cu.import
as a crutch and make it accept both ES modules and JSMs. Pending @Jonco's feedback.