The goal of this specification is to define a subset of AMD-, Node- and Globals-style modules that can interoperate with each other, and to define a static semantics for reliably extracting the imports from modules written using this subset.
In general, this means limiting conditional or dynamic dependencies, so that all imports can be determined by parsing. The vast majority of existing modules are written using this subset.
A companion spec, AMD Wrapping for Interoperability, describes how to wrap these modules so that they can interoperate using the AMD definition and AMD-compatible loaders.
- relative dependency: a dependency that begins with
./
or../
. - top-level variable: the lexical binding to a free variable at the top-level of a module file. If the same name is re-bound in a child scope, references to the newly bound variable are not references to the top-level variable.
AMD example:
// this is a top-level call to `define`
define(["definitions", "b"], function(definitions, b) {
definitions.forEach(function(define) {
// `define` is re-bound by the parameter, so
// this `define` is not a top-level call to `define`.
define(1);
});
}));
if (typeof define !== 'undefined') {
// this is a top-level call to `define`
define(["a", function(a) { /* factory body */ })
}
Node example:
// this is a top-level call to `require`
var requirements = require("requirements");
// this is an assignment to the top-level `module`
module.exports = requirements.map(function(require) {
// `require` is re-bound by the parameter, so
// this `require` is not a top-level call to `require`
var module = require("test-suite");
// `module` has been rebound, so this is not a top-level
// assignment to `module.exports`
module.exports = ["a", "b", "c"];
});
An AMD module contains a single call to the module's top-level define
function.
If there is more than one call to the top-level define
function, it is a SyntaxError
.
If there are more than two arguments to the define
function, it is a SyntaxError
.
If the first argument to the define
function (dependencies) is not an Array Literal, or any element of the Array Literal is not a String Literal, it is a SyntaxError
.
If the second argument to the define
function (factory) is not a Function Expression, it is a SyntaxError
.
If a module specifies relative dependencies, each of those dependencies MUST resolve to a file in the same package that meets these requirements.
The imports of an AMD module is the Array of Strings passed to the define
function.
- Let exports be an empty list.
- If factory has at least one Return Statement, add
default
to exports. - If dependencies does not have an
exports
element, return exports - Let exportsIndex be the index of the
exports
dependency in dependencies. - Let exportsBinding be the variable binding created by the argument at exportsIndex in the arguments list.
- Search factory for Assignment Expressions whose Reference is exportsBinding. For each such expression:
- Add the expression's Property Name to exports
- Return exports.
Any modules provided by the package MUST be valid Node modules. The name of the module will be derived from the location in the package.
If a node module contains a call to the top-level require function, and it has more than one parameter, or the parameter is not a String Literal, it is a SyntaxError
.
- Let imports be an empty list
- Let requires be a list of all Call Expressions that are top-level calls to the
require
function. - For each require in requires:
- Add the first parameter to the Call Expression to imports
- Return imports
- Let exports be an empty list
- Let script be the script representing the node module
- If script has a top-level assignment to
module.exports
, add default to exports - Let exportsBinding be the top-level binding with the name
exports
. - Search script for Assignment Expressions whose Reference is exportsBinding. For each such expression:
- Add the expression's Property Name to exports
- Return exports.
ES6 modules MUST be valid ModuleBodys.
The static semantics for imports and exports are the same as the static semantics in ES6.
What about support for CJS sugar syntax in AMD, i.e.:
and
That's the only way we author all our modules in my company.