模块

node的模块实现

node中模块分为两类:

require接收一个标识符作为参数,Node正是基于这个标识符进行模块查找的。模块标识符有以下三种形式:

  1. 核心模块名称,如http、fs、path等,试图加载一个与核心模块标识符相同的自定义模块是不会成功的,除非换用路径的方式
  2. 路径形式的文件模块,以 . 、 .. 或 / 开头的标识符,都被当做文件模块来处理
  3. 自定义模块,自定义模块指的是非核心模块,也不是路径形式的标识符(就是node_modules中的包)。它是一种特殊的文件模块,可能是一个文件或者包的形式。这类模块的查找是最费时的,也是所有方式中最慢的

Node是如何查找自定义模块的(模块路径生成规则)

编译过程中,Node对获取的JavaScript文件内容进行的头尾包装,在头尾分别添加了:

(function (exports, require, module, __filename, __dirname){\n
文件内容
\n})

使用vm原生模块的runInThisContext()方法执行(类似eval)包装后的文件代码,返回一个具体的function对象

将当前模块对象的exports属性、require方法、module(模块对象自身)以及在文件定位中得到的完整文件路径和文件目录作为参数传给这个function执行


AMD

define([id], [dependencies], factory);

definde(function() {
    var exports = {};
    实际模块代码
    return exports;
})

CMD

definde(['dep1', 'dep2'], function(dep1, dep2){
    return function(){}
}

UMD

(function (name, definition){
    //检测上下文环境是否为AMD或CMD
    var hasDefine = typeof define === 'function',
          //检测上下文环境是否为Node
          hasExports = typeof module !== 'undefined' && module.exports;
    if(hasDefine){
          //AMD或CMD环境
         define(definition)
    }else if(hasExports){
          //Node
          module.exports = definition()
    }else{
          //window
          this[name] = definition()
    }
})('my-module', function(){
    return function(){console.log('hello world')}
});

jungle