一. CommonJS规范
1.1 CommonJS的出发点
CommonJS规范的提出,主要是为了弥补当前JavaScript没有标准的缺陷(如模块、二进制、Buffer等等),以达到具备开发大型应用的基础能力。

1.2 CommonJS的模块规范
CommonJS对模块的定义主要分为:模块定义、模块引用、模块标识。
在Node中,一个文件就是一个模块。
1.2.1 模块定义
模块上下文提供了module对象和exports对象。module对象代表模块自身,exports是module的属性;exports对象作为模块导出的唯一出口。
exports.say = function () {
console.log('Hello Node.js!')
}
1.2.2 模块引用
模块上下文提供了require()方法来引入模块,它接受一个模块标识。
const fs = require('fs')
1.2.3 模块标识
模块标识就是传递给require()方法的参数,有以下3种类型:
1. 小驼峰模块名称
2. 相对路径
3. 绝对路径
二. Node的模块实现
Node引入模块的3个步骤:
1. 路径分析
2. 文件定位
3. 编译执行
Node的模块类型:
1. 核心模块(系统模块):省略了文件定位、编译执行的步骤,并且在路径分析中优先判断,加载速度快。
2. 文件模块(自定义模块、第三方模块):运行时动态加载,需要完整的引入模块步骤,加载速度慢。
2.1 优先从缓存加载
Node会缓存加载过的模块,核心模块的缓存检查优先与文件模块。
2.2 路径分析和文件定位
2.2.1 模块标识符分析
在Node的实现中,模块标识符分为以下几类:
1. 核心模块,如fs、path
2. 相对路径的文件模块
3. 绝对路径的文件模块
4. 非路径形式的文件模块(如axios),基于模块路径module.paths遍历查找
2.2.2 文件定位
文件扩展名分析
在分析模块标识符的过程中,会出现标识符不包含文件扩展名的情况,Node会按.js、.json、.node的次序补充扩展名,依次尝试。
目录分析和包
1. 如果文件扩展名分析失败,却得到一个目录。Node会在目录下查找package.json文件并通过JSON.parse()解析,对包描述对象的main属性值进行文件定位。
2. 如果没有package.json文件或main属性值错误,Node会将index当做默认文件名,按照文件扩展名分析的次序依次查找。
3. 如果目录分析失败,则进入下一个模块路径查找,以此循环直到模块路径遍历完,则会抛出查找失败的异常。
2.3 模块编译
Node对于不同的文件扩展名,载入方法也有所不同,具体如下:
1. .js文件:通过fs模块同步读取后编译执行。
2. .node文件:这是C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成的文件。
3. .json文件:通过fs模块同步读取后,用JSON.parse()解析返回结果。
4. 其余扩展名:被当做.js文件载入
每一个编译成功的模块,会将其文件路径作为索引缓存在Module._cache对象上,以提高二次引入的性能。
三. NPM
NPM是Node的包管理器,用于管理、组织、使用第三方模块。
3.1 包结构
CommonJS规范的包目录结构如下:
- package.json:包描述文件
- bin:可执行二进制文件目录
- lib:js代码目录
- doc:文档目录
- test:单元测试用例目录
3.2 发布包
1. 编写模块
2. 初始化package.json(npm init)
3. 注册账号(npm adduser或通过npm官网注册)
4. 登录账号(npm login,使用淘宝镜像的同学记得把镜像还原,否则无法登录)
5. 上传包(npm publish folderName)
6. 查看包是否发布成功(npm info packageName)
3.3 NPM私域搭建
TODO