Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
236 lines (156 sloc) 8.3 KB

This specification establishes a convention for creating a style of reusable JavaScript modules and systems that will load and link those modules.

  • Modules are singletons.
  • Modules have an implicitly isolated lexical scope.
  • Loading may be eager in asynchronous loaders.
  • Execution must be lazy.
  • With some care, modules may have cyclic dependencies.
  • Systems of modules may be isolated but still share the same context.
  • Modules may be used both in browsers and servers.

Guarantees Made by Module Writers

No requirement in this section implies that a module system must enforce that requirement. These are merely requirements that a module must satisfy in order to function in any module system.

  1. A module must be encoded in UTF-8.

  2. A module must only assume that its scope contains require, exports, and module in addition to the globals provided by JavaScript.

    1. Depending on any other values limits portability to engines that do not provide those values and will cause reference errors on those systems.
  3. A module must consider that every object in its scope may be immutable.

    1. Depending on the mutability of an object precludes the use of the module in a system that shares its global scope among mutually suspcious programs, like between mashups in a secured JavaScript context.

    2. It may be acceptable to upgrade an object in scope (shim) if it does not provide the needed, specified behavior, but this will limit portability to secure contexts with legacy implementations.

  4. A module must only depend on the specified behavior of values in scope.

    1. Depending on any extension to the specified behavior limits portability.
  5. All calls to require must be given a single string literal as the argument, or the value of require.main if it is defined.

    1. If the argument to require is not a string, the dependency cannot be discovered and asynchronously loaded before executing the module. This would limit portability to systems that read the text of a module to discover dependencies and load them asynchronously before execution, which is necessary for portability to browsers and other systems that only support asynchronous loading.

    2. require.main is guaranteed to already have been loaded, so it is a reasonable exception to the rule that all dependencies must be discoverable without executing the module.

  6. All calls to require must be by the name require.

    1. If require takes on a different name, the dependency will not be discoverable without executing the module.
  7. All calls to require must be given a module identifier as the argument.

    1. Some module loaders may accept values that are not module identifiers. Depending on this behavior inside a module limits the portability of the module, particularly to systems that use packages to isolate the module identifier name space for a set of modules.

Guarantees Made by Module Interpreters

  1. The top scope of a module must not be shared with any other module.

    1. All var declarations in a module will only be accessible within that module and will not collide with declarations in other modules
  2. A require function must exist in a function's lexical scope.

    1. The require function must accept a module identifier as its first and only argument.

    2. require must return the same value as module.exports in the identified module, or must throw an exception while trying.

    3. require may have a main property.

      1. The require.main property may be read-only and non-configurable.

      2. The require.main property must be the same value as module in the lexical scope of the first module that began executing in the current system of modules.

      3. The require.main property must be the same value in every module.

    4. require must have a resolve function.

      1. resolve accepts a module identifier as its first and only argument

      2. resolve must return the resolved module identifier corresponding to the given module identifier relative to this module's resolved module identifier.

    5. require must have an async function.

      1. async must accept an identifier or an array of identifiers as its first argument.

        1. A single identifier is equivalent to an array with a single identifier.
      2. async accepts an optional callback function as its second argument.

      3. async accepts an optional errback function as its third argument.

      4. async must call require for each module identifier in order

      5. async may wait for each module's transitively required modules to asynchronously load before calling require.

      6. If any require call throws an exception, or if any module cannot be loaded before it is required, errback must be called with the Error as its argument.

      7. If every require call returns, async must call callback with the respective exports for each module identifier as its arguments.

  3. An exports object must exist in a function's lexical scope.

    1. the exports object must initially be the same value as module.exports.
  4. A module object must exist in a function's lexical scope.

    1. The module object must have an id property.

      1. The module.id property must be a module identifier such that require(module.id) must return the module.exports value when called in this or any module in the same system of modules.

      2. The module.id property may be read-only and non-configurable.

    2. The module object must have an exports property.

      1. The module.exports property must initially be an empty object.

      2. The module.exports property must be writable and configurable.

    3. The module object may have a location absolute URL.

    4. The module object may have a directory absolute URL.

      1. The directory must be the directory containing the location.

Module Identifiers

  1. A module identifier is a string of "terms" delimited by forward slashes.

  2. A term is either:

    1. any combination of lower-case letters, numbers, and hyphens,

    2. a single dot, ".", or

    3. a double dot, "..".

  3. Module identifiers should not have file-name extensions like .js.

  4. Module identifiers may be "relative" or "resolved". A module identifier is "relative" if the first term is . or ...

  5. Top-level identifiers are resolved relative to "".

  6. The require function in each module resolves relative identifiers from the corresponding module.id.

  7. To resolve any path of module identifiers,

    1. An array of terms must be initialized to an empty array.

    2. For each module identifier in the path of identifiers,

      1. Pop off the last term in the array, provided one exists.

      2. For each term in a module identifier in order,

        1. Take no action if the term is ".".

        2. Pop a term off the end of the array if the term is "..".

        3. Push the term on the end of the array otherwise.

    3. The array of terms must be joined with forward slashes, "/" to construct the resulting "resolved" identifier.

Unspecified

This specification leaves the following important points of interoperability unspecified:

  1. Whether modules are stored with a database, file system, or factory functions, or are interchangeable with link libraries.

  2. Whether require accepts values that are not module identifiers as specified here.