node加载模块分为3个步骤
1.路径查找
2.文件定位
3.模块编译
1.路径查找
通过module.paths可以看出,文件查找是先查找当前目录的node_modules,然后查找父目录的node_modules,然后逐级向上查找
2.文件定位
如果require传参没有文件扩展名,那么node会按.js .json .node 的顺序查找文件
如果没有查找到对应文件,node会把对应目录作为包处理,查找目录下pageage.json文件,用JSON.parse()处理,然后查找到main属性,根据main属性进行文件定位,如果main属性没有文件拓展名,依然按照.js .json .node 顺序查询。如果main属性文件指定的文件名错误,或者压根没有pageage.json,node会将index作为默认文件名,按照.js .json .node 依次进行查找,如果还没有定位到,将进入下一个模块路径查找,全部递归后,如果还没有找到,将会抛出查询失败异常。
3.模块编译
编译分为三种情况,js模块、c/c++模块、json模块
Js模块
每个模块都有默认变量,exports、module、require、__filename、__dirname。这些变量的来源是在编译过程,对文件进行收尾处理
function(exports、module、require、__filename、__dirname){
/*文件内容*/
}
exports和module.exports的区别
exports是module.exports的引用,如果直接对exports进行复制,只是改变了exports的指向,但是对于module.exports是没有任何改变的。所以我们不能直接对exports进行赋值,应该对exports的属性赋值。
c/c++模块
因为是c/c++编写,所以该模块并不需要编译,而是直接进行加载和执行。
通过调用process.dlopen()方法执行。
json模块
node直接通过fs模块同步读取json文件,然后通过JSON.parse()进行转换,后赋值给module.exports。
模块缓存
核心模块编译成功后缓存在NativeModule._cache下
文件模块编译成功后缓存在Module._cache下