CommonJS 规范及实现

包规范的实现 - NPM

NPM 是 CommonJS 包规范的一种实现。

CommonJS 包规范的目录

  • package.json:包描述文件
  • bin:用于存放可执行二进制文件的目录
  • lib:用于存放 JavaScript 代码的目录
  • doc:用于存放文档的目录
  • test:用于存放单元测试用例的代码

安装依赖包

全局安装

npm install express -g命令是对express进行全局安装,-g是将一个包安装为全局可用的可执行命令。它根据包描述文件中bin字段配置,将实际脚本链接到与 Node 可执行文件相同的路径下:

{
  "bin": {
    "express": "./bin/express"
  }
}
1
2
3
4
5

模块规范的实现

Node 作为 CommonJS 规范的实现,并没有完全按照规范实现,而是对模块规范进行了一定的取舍,同时也添加了少许自身需要的特性。

Node 中引入模块,需要经历如下3个步骤:

  1. 路径分析
  2. 文件定位
  3. 编译执行

自定义模块的路径分析及文件定位

现在针对自定义模块,简单说明其路径分析和文件定位是如何进行的。

第一步:路径分析

/home/wind-stone/project/目录下,创建app.js文件,其内容为console.log(module.paths),在当前目录下执行node app.js,Linux 下,得到的输出为一数组,数组内的每一项称为模块路径,该数组的结构为:

[
    '/home/wind-stone/project/node_modulse',  // 当前文件目录下的 node_modules 目录
    '/home/wind-stone/node_modulse',          // 父目录下的 node_modules 目录
    '/home/node_modulse',                     // 父目录的父目录下的 node_modules 目录
    '/node_modulse',                          // 沿路径向上逐级递归,直到根目录下的 node_modules 目录
]
1
2
3
4
5
6

以上即为查找自定义模块时的各级模块路径,Node 会先在当面目录的node_modules查找模块即定位文件,若是没找到,会沿路径向上逐级递归,直到根目录下的node_modules目录定位文件。

第二步:文件定位

上述每查找到一node_modules目录时,就要进行文件定位。其过程为:

  1. 文件扩展名分析:若require()所引用的模块标识符不包含扩展名,则 Node 会按.js.json.node的次序补足扩展名,依次尝试。
  2. 目录分析和包:若是上一步没找到文件,但是得到同名的目录,此时 Node 会将目录当成一个包来处理
    • 首先,Node 会在当前目录下查找package.json文件,通过JSON.parse()解析出包描述对象里的main属性指定的文件名进行定位,若是文件名缺少扩展名,将会进入扩展名分析的步骤
    • 若是package.json文件不存在,或者main属性制定的文件名错误,Node 会将index当做默认文件名,然后做扩展名分析,即依次查找index.jsindex.jsonindex.node

若是在文件定位的过程中没有成功定位到任何文件,则自定义模块进入下一模块路径进行查找。

若是模块路径数组都被遍历完毕,依然没有查找到目标文件,则会抛出查找失败的异常。

Reference: [深入浅出 NodeJS]

require.resolve

获取模块的绝对路径

require.resolve('a.js')
// 结果
// /home/ruanyf/tmp/a.js
1
2
3

Reference: require() 源码解读open in new window