影响力的本质是一种精神的输出。
前情回顾
上篇文章主要分享了的一个nodejs的模块儿查找机制,查找过程大致会经历路径分析,文件定位,编译执行这三个过程。今天续聊一聊Node模块儿的解析和npm的知识点
模块儿编译
在Node中引每个模块儿都是一个对象,大致如下:
代码语言:javascript复制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 = [];
}
定位到具体的文件后,Node会新建一个模块儿对象,然后根据路径载入并编译。当然,文件类型不同,载入方法也有所不同。
.js文件通过fs模块读取后进行编译.node文件是用C 写的扩展文件,通过dlopen()方法加载最后编译生成的文件.json文件通过fs读取后,用JSON.parse解析并返回结果
不同的文件类型,Node的读取方式也会不同,如json文件:
// Native extion for .json
module._extentions['.json'] = function (module,filename) {
var content = NativeModule.require('fs').readFileSync(filename,'utf-8')
try{
module.exports = JSON.parse(content)
}catch(err){
err.message = filename ':' err.message
throw err;
}
}
JS模块儿如何编译?
每个js文件中都存在require,exports,module这三个变量,但是我们并没有去定义它们。在Node的文档中,我们也可以找到__dirname,__filename这两个变量,它们是从哪里来的呢?
实际上,Node对获取到的JS文件进行了包装。在头部添加了(function(exports,require,module,__filename,__dirname){,在尾部添加了})。如:
(function(exports,require,module,__filename,__dirname){
var math = require('math')
exports.add = function(a,b){
return a b
}
})
这样每个模块文件之间进行了隔离。同时包装后的代码通过原生模块的runInThisContext()方法执行,返回一个具体的对象。最后,当前模块对象的exports,module,require属性作为参数传给这个function()执行。这样一来,虽然这些变量没有定义,但是在模块文件中确是存在的。
npm和包
也许我们平时用npm很多,也知道它是包管理器,但是大部分人对其中的细节并没有过多的思考过。
包是什么?包实际上是一个存档文件,即一个目录直接打包为.zip或.tar.gz的格式。安装后解压为目录。符合规范的包目录应该包含以下文件package.json包描述文件bin存放可执行二进制文件lib存放js代码doc存放文档test存放单元测试用例代码
包描述文件
pageage.json用来描述与具体代码不相干的一些信息。
name包名称description包简介version版本号keywords关键词maintainers维护者列表contributors贡献者列表license许可证列表respositories托管源代码的地址dependencies依赖包homepage网站地址os操作系统支持列表cpucpu架构支持列表engine支持额js引擎列表builtin是否内建在底层系统的标准组件directories包目录说明implements实现的规范列表scripts脚本说明对象npm的常用功能
npm在日常开发中用太常见了,所以就不做太多的描述了。简单介绍下如何发布一个包。发布一个包大致会用到以下几个命令:
npm init初始化包npm adduser添加用户npm publish上传包
如果想看到当前路径下能够找的的所有的包,可以执行npm ls
总结
JS模块儿如何编译npm和包
javascript基础知识总结


