AMD modules define on to the default property of the module object in the module registry:
define(function() {
return 'hello world';
});
defines the module object in the ES6 loader registry as Module({ default: 'hello world' })
AMD modules need to have their AMD dependencies returned as AMD modules directly:
define(['a', 'b'], function(a, b) {
});
When a is AMD and b is ES6, we need to return the default property accordingly for a, while having b remain an ES6 module.
We can track AMD modules with meta when creating them Module({ default: 'hello world', __defaultOnly: true })
In this way, a above would return 'hello world'
into the define function. This allows us to load AMD from AMD.
ES6 modules need to have AMD modules treated as ES6 modules, so they have to still get the Module object with a default property.
An ES6 module would load an AMD module using default syntax only:
import $ from 'jquery';
If doing a named export from AMD, we'd always get empty (since the module is Module({ default: ..., __defaultOnly: true })
).
If loadng the module object of an AMD module directly (module x from 'x'
), we'd get the module object above as well.
We transpile ES6 into AMD to the following output:
define(['a', 'b'], function(a, b) {
// undo the default lowering above
if (!a || !a.__esModule) a = { default: a }
if (!b || !b.__esModule) b = { default: b }
return {
some: 'export',
__esModule: true
};
});
Any dependencies of the ES6 module that are AMD will be lowered to become their default properties.
But in ES6, we don't want this (as described in the previous section).
So the undo code above has to check if any imports are not module objects, and turn them back into module objects.
When a is AMD and b is ES6, we end up with the correct two ES6 module access forms we need.
Note that in order for this to work in an ES6 loader, the AMD compatibility layer must clone the module object into a new object that has the __esModule
property.
The transpiled module returns a flag on its own output to ensure that it, itself, doesn't get marked as an AMD module, and instead can be a full module object (Module({ some: 'export' })
).
This way the interop works comprehensively in both existing AMD environments and can be shimmed for compatibility in ES6 loaders as well.
I think that covers everything...