影响力的本质是一种精神的输出。
前情回顾
上篇文章主要分享了的一个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
操作系统支持列表cpu
cpu架构支持列表engine
支持额js引擎列表builtin
是否内建在底层系统的标准组件directories
包目录说明implements
实现的规范列表scripts
脚本说明对象npm的常用功能
npm在日常开发中用太常见了,所以就不做太多的描述了。简单介绍下如何发布一个包。发布一个包大致会用到以下几个命令:
npm init
初始化包npm adduser
添加用户npm publish
上传包
如果想看到当前路径下能够找的的所有的包,可以执行npm ls
总结
JS模块儿如何编译
npm和包
javascript基础知识总结