前端嘛 Logo
前端嘛

CommonJS

CommonJS是一个旨在规范JavaScript在网络浏览器之外(如网络服务器或本地桌面应用程序)的模块生态系统的项目。

CommonJS(CMJ)是一个社区模块化规范,CommonJS 关于模块工作方式的规范目前广泛用于 Node.js 服务器端 JavaScript。它也用于浏览器端 JavaScript,但由于浏览器不支持 CommonJS,因此必须使用转译器对代码进行打包。

规范内容(v1.1.1)

Require

require is a Function

  1. The "require" function accepts a module identifier.

  2. "require" returns the exported API of the foreign module.

  3. If there is a dependency cycle, the foreign module may not have finished executing at the time it is required by one of its transitive dependencies; in this case, the object returned by "require" must contain at least the exports that the foreign module has prepared before the call to require that led to the current module's execution.

  4. If the requested module cannot be returned, "require" must throw an error.

  5. The "require" function may have a "main" property.

    • This attribute, when feasible, should be read-only, don't delete.

    • The "main" property must either be undefined or be identical to the "module" object in the context of one loaded module.

  6. The "require" function may have a "paths" attribute, that is a prioritized Array of path Strings, from high to low, of paths to top-level module directories.

    • The "paths" property must not exist in "sandbox" (a secured module system).

    • The "paths" attribute must be referentially identical in all modules.

    • Replacing the "paths" object with an alternate object may have no effect.

    • If the "paths" attribute exists, in-place modification of the contents of "paths" must be reflected by corresponding module search behavior.

    • If the "paths" attribute exists, it may not be an exhaustive list of search paths, as the loader may internally look in other locations before or after the mentioned paths.

    • If the "paths" attribute exists, it is the loader's prorogative to resolve, normalize, or canonicalize the paths provided.

Module Context

  1. In a module, there is a free variable "require", which conforms to the above definiton.

  2. In a module, there is a free variable called "exports", that is an object that the module may add its API to as it executes.

    • modules must use the "exports" object as the only means of exporting.

  3. In a module, there must be a free variable "module", that is an Object.

    • The "module" object must have a "id" property that is the top-level "id" of the module. The "id" property must be such that require(module.id) will return the exports object from which the module.id originated. (That is to say module.id can be passed to another module, and requiring that must return the original module). When feasible this property should be read-only, don't delete.

    • The "module" object may have a "uri" String that is the fully-qualified URI to the resource from which the module was created. The "uri" property must not exist in a sandbox.

Module Identifiers

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

  2. A term must be a camelCase identifier, ".", or "..".

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

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

  5. Top-level identifiers are resolved off the conceptual module name space root.

  6. Relative identifiers are resolved relative to the identifier of the module in which "require" is written and called.

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 a PATH is supported by the module loader for resolving module identifiers.

CommonJS 规范内容综述

Node天生支持 CMJ 标准,它规定:

  1. 一个 js 文件就是一个 CMJ 模块,通过 node 命令运行的模块称为入口模块

  2. 模块中所有全局定义的变量、函数,不会互相污染

  3. 使用 exports 来导出模块中的内容,供其它模块使用

  4. 使用 requre 来导入其它模块导出的内容

  5. CMJ 模块是同步加载的,模块在导入时会阻塞执行,直到模块完全加载并可用

  6. 模块可以多次加载,首次加载的时候会运行模块并对输出结果进行缓存,再次加载时会直接使用缓存中的结果

模块导出

可以使用 module.exports 导出模块中的函数

// util.js
const getSum = (a, b) => a + b;
module.exports = { getSum };

也可以使用 exports 导出

// util.js
const getSum = (a, b) => a + b;
exports.getSum = getSum;

模块导入

使用 require 导入模块

// index.js
const util = require('./util.js');
const sum = util.getSum(1, 2);