nodejs js模块加载

nodejs的非核心模块(core module)加载主要使用的就是module.js。

项目主模块(index.js/main.js等)加载使用的应该是module.js中的runMain(),其他js模块加载流程基本上是:

1,获取js文件信息;

2,new Module();

3,读取js文件内容,封装到一个function中,同时注入module本身,module.exports,包装过的require函数等变量;

4,在某个上下文环境中执行这个封装后的function;

5,返回module.exports;

主要代码如下

module.js:// Loads a module at the given file path. Returns that module‘s

// `exports` property.
Module.prototype.require = function(path) {
    assert(path, ‘missing path‘);
    assert(util.isString(path), ‘path must be a string‘);
    return Module._load(path, this);
};

// Check the cache for the requested file.
// 1. If a module already exists in the cache: return its exports object.
// 2. If the module is native: call `NativeModule.require()` with the
//    filename and return the result.
// 3. Otherwise, create a new module for the file and save it to the cache.
//    Then have it load  the file contents before returning its exports
//    object.
Module._load(filename, this){
    If(fileName in Module._cache)
        Return Module._cache[filename];
  var module = new Module(filename, parent);
  Module._cache[filename] = module;
  Module.load(filename);  // 先把模块放到缓存然后再去加载内容,可以解决循环依赖的问题。参见https://nodejs.org/api/modules.html的Cycles部分。
  return module.exports;
}

Module.prototype.load(filename){
    var extension = path.extname(filename) || ‘.js’;
    Module._extensions[extension](this, filename){
        var content = fs.readFileSync(filename, ‘utf-8’);
        module._compile(content, filename);
  }
}

// Run the file contents in the correct scope or sandbox. Expose
// the correct helper variables (require, module, exports) to
// the file.
// Returns exception, if any.
Module.prototype._compile = function(content, filename) {
    function require(path) {
        return self.require(path);
  }

  require.main = process.mainModule;

  // Enable support to add extra extension types
  require.extensions = Module._extensions;
  require.cache = Module._cache;

  // TODO: 每个模块加载到自己的context中会有什么不同?
  // Set the environ variable NODE_MODULE_CONTEXTS=1 to make node load all modules in their own context.
  // Module._contextLoad = (+process.env[‘NODE_MODULE_CONTEXTS‘] > 0);
  // if (Module._contextLoad) { .... }

  // create wrapper function
  var wrapper = NativeModule.wrap(content);
  // wrapper = ‘(function (exports, require, module, __filename, __dirname) { ‘ + content + ‘\n});‘

  // runInThisContext()可以认为是在某个上下文环境中执行的eval()。
  // compiledWrapper相当于eval(‘(function(){....})’)的结果,也就是真正的Function。
  var compiledWrapper = runInThisContext(wrapper, { filename: filename });

  // module.exports 和 exports 的区别:
  // 这里只传递了exports的引用;而上面Module._load()返回的是module.exports,因此给module.exports赋值后,
  // exports仍然指向之前的module.exports。
  var args = [self.exports, require, self, filename, dirname];

  // 真正执行compiledWrapper这个function,也就是执行了filename.js的内容。
  return compiledWrapper.apply(self.exports, args);
}

runInThisContext()就是vm.js里的runInThisContext(),vm.runInThisContext()调用了src/node_contextify.cc中的RunInThisContext()。

https://github.com/joyent/node/blob/master/lib/vm.js

https://github.com/joyent/node/blob/master/src/node_contextify.cc

时间: 2024-10-12 17:16:07

nodejs js模块加载的相关文章

js模块化/js模块加载器/js模块打包器

之前对这几个概念一直记得很模糊,也无法用自己的语言表达出来,今天看了大神的文章,尝试根据自己的理解总结一下,算是一篇读后感. 大神的文章:http://www.css88.com/archives/7628(大神的文章写的很详细,建议先看完大神的文章) 一.js模块化 什么是js模块化,我们从历史说起. 1.一开始我们怎么写脚本?就是在html文件中用<script></script>写代码 这种方式的缺点:代码复用靠复制,基本是全局变量. 2.后来我们用js文件写代码,用<

实现简单的 JS 模块加载器

实现简单的 JS 模块加载器 按需加载是前端性能优化的一个重要手段,按需加载的本质是从远程服务器加载一段JS代码(这里主要讨论JS,CSS或者其他资源大同小异),该JS代码就是一个模块的定义,如果您之前有去思考过按需加载的原理,那你可能已经知道按需加载需要依赖一个模块加载器.它可以加载所有的静态资源文件,比如: JS 脚本 CSS? 脚本 图片 资源 如果你了解 webpack,那您可以发现在 webpack 内部,它实现了一个模块加载器.模块加载器本身需要遵循一个规范,当然您可以自定义规范,大

Angular Material串串学客户端开发 2 - Node.js模块加载机制Require()

题外话解一下博客标题,因为第一篇文章评论中,有人质疑离题很远,说了半天和Angular Material没有半毛关系.其实我的的中心在后半句<串串学客户端开发>. require() 不要把这里的Require()和RequireJS混为一谈.不过有意思的是,Typescript的模块定义,甚至同时支持这两种模块机制. 导入和使用外部模块,只是简单的一句require(),看看angular/material/docs下的编译文件gulpfile.js的代码片段.对模块导入和使用有个直观的感觉

JS模块加载器加载原理是怎么样的?

路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的对应原则,加载器才能知道需要加载的 js 的路径.在这个例子里,就是 baseUrl + 'a.js' 和 baseUrl + 'b.js'. 但 id 和 path 的对应关系并不是永远那么简单,比如在 AMD 规范里就可以通过配置 Paths 来给特定的 id 指配 path. 原理二:crea

浅谈js模块加载方式(初级)

1.简介:  前端模块化开发日渐鼎盛,如何将零散的插件或者是普通的js脚本文件统一管理及引用,是众多开发者共同的目标.本人是从事.net开发的,最近对前端的一些东西特别的感兴趣,也会尝试的夹杂一点自己的想法,写一些小东西.东西不牛逼,但是感觉用起来还是方便那么一点的.下面就展示一下简短的小代码. 2.中心思想:通过外部调用事先封装好的模块加载方法,传入参数(包括主目录及模块js或者css的目录 ),在程序运行的同时,会动态的将相应的css或者是js代码追加引用到head标签内,这样,就可以使用被

关于前端JS模块加载器实现的一些细节

最近工作需要,实现一个特定环境的模块加载方案,实现过程中有一些技术细节不解,便参考 了一些项目的api设计约定与实现,记录下来备忘. 本文不探讨为什么实现模块化,以及模块化相关的规范,直接考虑一些技术实现原理. 1.简单实现模块化 一开始我想如果我的代码只有一个文件,那几行不就实现了吗 main.js var modules = {} var define = function(id,factory){ moudles[id] = factory } var require = function

require.js模块加载js

RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的RequireJS压缩后只有14K,堪称非常轻量.它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升. requirejs能带来什么好处 官方对requirejs的描述: RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it

node.js 模块加载原理

来自BYVoid的<Node.js+开发指南> 2015-9-14 11:23:30 有时候我们只是想把一个对象封装到模块中,例如: //singleobject.js function Hello() { var name; this.setName = function (thyName) { name = thyName; }; this.sayHello = function () { console.log('Hello ' + name); }; }; exports.Hello

require.js【模块化编程】- 模块加载简例

今天去学习了一下javascript的模块化编程,写了个简单的例子. ———————————————— 这是我的第一篇技术性的小博文,希望和大家相互交流  ———————————————— 这个列子我打算分两个部分罗列: 1.文件地图 2.源代码 demo.html: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtm