CommonJS规范的起因:

1.JavaScript没有模块系统。没有原生的支持密闭作用域或依赖管理。
2.JavaScript没有标准库。除了一些核心库外,没有文件系统的API,没有IO流API等。
3.JavaScript没有标准接口。没有如Web Server或者数据库的统一接口。
4.JavaScript没有包管理系统。不能自动加载和安装依赖。

在node中引入模块需要经历3个步骤:

1.路径分析

2.文件定位

3.编译执行

CommonJS对模块的定义十分简单,主要分为模块引用、模块定义和模块标识3个部分。

1.模块引用
require('xxx')
2.模块定义
exports.xxx
module.exports = {}
3.模块标识
模块标识其实就是传递给require()方法的参数,

它必须是符合小驼峰命名的字符串
或者以.、..开头的相对路径

或者绝对路径。它可以没有文件名后缀.js。

 

Nodejs模块分类Node.js的模块分为两类,一类是node提供的模块,称为核心模块;另一类是用户自己编写的模块,称为文件模块。核心模块在Node.js源代码编译的时候编译进了二进制执行文件,在nodejs启动过程中,部分核心模块直接加载进了内存中,所以这部分模块引入时可以省略文件定位和编译执行两个步骤,所以加载的速度最快。另一类文件模块是动态加载的,加载速度比核心模块慢。但是Node.js对核心模块和文件模块都进行了缓存,于是在第二次require时,是不会有重复开销的。其中原生模块都被定义在lib这个目录下面,文件模块则不定性。
ps:核心模块又分为两部分,C/C++编写的和Javascript编写的,前者在源码的src目录下,后者则在lib目录下。(lib/*.js)(其中lib/internal部分不提供给文件模块)

注:通过process.moduleLoadList可以查看已经加载的核心模块。 核心模块 = 原生模块

 

 

加载过程如下图:

 

 

 CommonJS模块规范允许在标识符中不包含文件扩展名,这种情况下,Node会按.js、.node、.json的次序补足扩展名,依次尝试

小诀窍是:如果是.mode和.json文件,在传递给require() 的标识符中带上扩展名,会加快一点速度。另一个诀窍是:同步配合缓存,可以大幅度缓解Node 单线程中阻塞式调用的缺陷。

 

编译和执行是引入文件模块的最后一个阶段。定位到具体的文件后,Node会新建一个模块对象,然后根据路径载入并编译。对于不同的文件扩展名,其载人方法也有所不同,具体如下所示。

.js文件。通过fs模块同步读取文件后编译执行。

.node文件。这是用C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成的文件。

.json文件。通过fs模块同步读取文件后,用JSON.parse()解析返回结果。

其余扩展名文件。它们都被当做.js文件载人。

每一个编译成功的模块都会将其文件路径作为索引缓存在Module._cache对象上,以提高二次引入的性能。

内置模块

原生模型的引入:

 

*  GYP项目生成工具

*  V8引擎C++库

*  Iibuv库

*  Node内部库

*  其他库

 

包组织模块示意图:

 

 发布包的流程:

1.编写包程序(编写代码)

2.初始化包描数文件(package.json)--npm install

3.注册包仓库账号 

npm adduser

Username:(XXXXX)

Email:(***@XX.com)

4.上传包

npm publish <folder>

在刚刚创建的package.json文件所在的目录下,执行 npm pulish .  开始上传包

这个过程中,NPM会将目录打包成为一个文档文件,然后上传到官方源仓库中。

5.安装包

npm install 包名

6.管理包权限

npm owner ls eventproxy

添加包的拥有者,删除一个包的拥有者:

npm owner ls <package name>

npm owner add  <user>  <package name> 

npm owner rm <user>  <package name>