CommonJS规范概述
说明
CommonJS对ES规范不曾涉及到的文件(FS),流(Stream),Buffer,Socket等做出了规范,希望JS除了能在浏览器还能再各个系统中运行,Node为其最佳实践由最初命名为ServerJS也可以看出
The project was started by Mozilla engineer Kevin Dangoor in January 2009 and initially named ServerJS.
CommonJS所处位置
模块化
CommonJS对模块的定义十分简单,主要分为模块引用、模块定义和模块标识3个部分。
引用:
var App = require('express')
定义:
exports.add = function(){}
//OR
module.exports = function(){}
模块定位:
根据.js=>.json=>.node的优先级来查找如果没找到文件而找到一个目录.则会在文件目录下找package.json中的main定义的js为引用模块,如果还是没找到则在当前目录下找index.js如果还是没找到就报错
编译:
模块定义:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
- js文件通过fs读取后执行
- node这是c++写的文件,通过dlopen()加载最后编译生成的文件
- json通过fs读取并用JSON.parse()转换
编译完成后的模块存在一些内置对象如require module exports __filename __dirname是如何做到的喃,其实在编译后形成的js代码如下:
(function (exports, require, module, __filename, __dirname) {
var math = require('math');
exports.area = function (radius) {
return Math.PI * radius * radius;
};
})
模块读取
根据不同的文件类型有不同的读取方式,以json为例
// Native extension for .json
Module._extensions['.json'] = function(module, filename) {
var content = NativeModule.require('fs').readFileSync(filename, 'utf8');
try {
module.exports = JSON.parse(stripBOM(content));
} catch (err) {
err.message = filename + ': ' + err.message;
throw err;
}
};
https://blog.csdn.net/dwc_fly/article/details/9902579
模块加载流程
下面以一段简单的代码来模拟下exports是如何导出的,核心方法是调用了runInThisContext
let Script = require('vm')
var exports = {}
var filename = "test.js"
function requirenew(){
return exports
}
var source =
`
console.log(exports)
exports.add = function(){console.log('test')}
`
var runInThisContext = Script.runInThisContext;
var wrap = function (script) {
return wrapper[0] + script + wrapper[1];
};
var wrapper = [
'(function (exports, module, __filename, __dirname) { ',
'\n});'
];
source = wrap(source);
var fn = runInThisContext(source, filename, true);
fn(exports, this, filename, filename);
console.log(requirenew())