Node.jsnpm详解
⼀、npm简介
安装npm请阅读我之前的⽂章中npm安装那⼀部分,不过只介绍了linux平台,如果是其它平台,有写了更加详细的介绍。
npm的全称:Node Package Manager.
####(1)通俗的理解
其实从字⾯意思就可以理解这个产品有什么作⽤翻译为“Node包管理器”。对,就是Node的包的⼀个管理⼯具,⽬前我尝试的有
1. 下载并安装包(npm install [pkg])
2. 升级安装包(npm update [pkg])
3. 卸载安装包(npm uninstall/rm [pkg]),可以指定卸载包的版本号 ...
其实这些命令很简单,常⽤的必须记住,不常⽤的查询即可,这才是⽐较好的学习知识⽅式。
在终端输⼊:
//查看npm拥有的全部命令
$ npm --help
$ npm help
//查看某⼀个npm命令的详细⽤法
$ npm <command> --help
$ npm help <command>
####(2)专业的解释
npm(Node Package Manager)是Node.js下的主流套件管理程式。它在Node.js v0.6.x版本之后,内建于Node系统。通过npm可以协助开发者安装、卸载、删除、更新Node.js套件,并且可以通过npm发布⾃⼰的插件。
⼆、类似的产品
mysql下载下来没安装包其实学习⼀个产品,可以联系其它产品,能够更好的理解现在⼿头的产品。第⼀次学习npm我的第⼀反应就是,很像linux/mac平台的很多软件,依赖管理的⽅式可以参考当然相似性可以随便联想。
接下来,举⼏个例⼦吧,当然详细了解可以查baidu && google。
1. gem
2. PyPL
3. pear
4. macPort
5. Homebrew
6. rem
7. apt-get
8. yum ...
是不是很多都很熟悉?这样对于npm的认识就不⽤局限于概念啦。
三、npm基础功能
(1)npmrc⽂件介绍
⾸先介绍⼀下npmrc⽂件,这个⽂件是npm包管理器的配置⽂件。
与npmrc相关的三个⽂件:
1. ⽤户配置⽂件:~/.npmrc
2. 全局配置⽂件:$PREFIX/npmrc
3. npm内部配置⽂件:安装npm的⽬录下
下⾯仔细看⼀下npm config的配置。
(2)npm获取配置的6种⽅式(优先级从⾼到低):
1.命令⾏参数
$ --proxy <server>:<port>
2.环境变量
以"npm config"为前缀的环境变量将会被认为是npm的配置属性。像Maven镜像的概念,⽅便通信吧。
$ npm_config_proxy=<server>:<port>
3.⽤户配置⽂件
//查看⽂件路径
$ npm config get userconfig
//mac系统默认路径
$HOME/.npmrc
4.全局配置⽂件
//查看⽂件路径
$ npm config get globalconfig
//mac系统默认路径
/usr/local/etc/npmrc
3,4中输⼊终端的效果如图:
5.内置配置⽂件
安装npm的⽬录下的npmrc⽂件。
6.默认配置
如果前5条均未设置,npm会使⽤默认配置参数。
(4)npm install
“安装指定包”:这个命令不难,但是也有需要注意的地⽅,就是安装的模式有两种,在后⾯会单独讲解。
如果不知道包的具体名称,可以在上进⾏搜索。
(5)npm uninstall
“卸载指定包”:在help的时候,会给你推荐npm rm 这个命令,uninstall会卸载掉包的依赖,rm。
####(6)npm ls
查看安装的包清单,其实和linux的ls命令很像,可以跟很多参数,详情可以使⽤
$ npm help ls
####(7)npm search
搜索包的详细信息,⽐如我们搜索express试试。第⼀次搜索,会提⽰建⽴索引,需要耐⼼等待⽚刻,⼤家测试的时候不要就关掉啦终端。npm WARN Building the local index for the first time, please be patient
其实看上去复杂,只是东西有点⼤,不过主要包含以下6个部分:
1. 名称
2. 描述
3. 作者
4. 发布时间
5. 发布版本号
6. 关键字
####(8)npm update
更新安装的包
更多API可以查看官⽹:
四、版本号的知识。
在node.js中的package.json配置⽂件中,我们需要配置版本号,⽐如0.1.2
第⼀位数字:主版本号
第⼆位数字:⼦版本号
第三位数字:补丁版本号
到⼀个不错的介绍软件项⽬版本号的⽂章
为什么要解释这个呢?肯定是有⽤,因为npm安装的时候是可以选择版本号的,有点理解会⽐较好吧,⾄少我是这么认为的。
⼀、前⾔
很久之前就想系统的学习nodejs技术了,但是由于很多事情,忙不太过来,今天晚上下定决⼼要⼊门这门技术,所以⼀⼝⽓看完了《Node.js开发指南》和《Node.js中⽂⽂档》,总算是真正⼊门了,接下来就总结⼀部分,剩下的只有明天再总结了。
⼆、Node.js简介
⼀句话简单说明⼀下node.js是什么东西。
Node.js 是⼀个让 JavaScript 运⾏在服务端的开发平台。
三、Node.js的安装
学习了Node.js,觉得如果在window下学习这门技术的话还太成熟,第三⽅的⽀持不太好,所以只介绍linux或者mac上⾯的安装。node.js在window上⾯的安装直接下载安装包,⼀直下⼀步就可以装好,环境变量也会⾃动配置好,npm(node package manage)在新版本也会相应的装上。
对于mac环境安装也⽐较简单,介绍两种安装⽅式。
1.homebrew(注意⼀直使⽤admin权限吧,⼤多都是权限⽂件夹,可以在终端开始使⽤sudo -s命令来⼀直使⽤admin权限)
$ sudo brew install node
这样下载完了就算安装上了,我们可以来检测⼀下你的安装(软件配置必须要的步骤)。
# 查看node版本号
$ node -v
# 查看npm版本号和清单
$ npm -v && npm list
如果npm没有安装上,那么可以使⽤以下命令安装。
$ sudo curl /install.sh | sh
2.使⽤源码编译的⽅式(其实有⽅便的尽量就避免⿇烦的,嘿嘿)
下载地址:
执⾏典型的安装命令即可(注意到/bin⽬录,或者有configure⽂件的⽬录)。
$ ./configure && make && sudo make install
四、Node.js的多版本管理器n
下载地址:
如上执⾏源码安装命令即可。
当然,如果你安装了npm,就有更⽅便的⽅式,这也是很迷⼈的地⽅。
$ sudo npm install -g n
接下来检查⼀下安装情况。
$ n --version
这样就可以使⽤⾃由切换使⽤node的版本了。⽤如下命令安装指定版本的node。
$ n version
下载后,会默认下载到:/usr/local/n/versions/⽬录
如果你安装后,再使⽤"$ n version"命令就是指定使⽤的默认版本号,也可以使⽤“$ n use version xxx.js”来暂时使⽤某个node版本执⾏xxx.js⽂件。
五、万事具备,只⽋Hello Node.js
每个语⾔⼊门都可以写⼀个hello xxx,⽰好。
在node中,这个很简单,只需要进⼊REPL模式,暂时不要管这个模式是什么,我们先使⽤。这个⽤截图来直观说明⼀下。
进⼊REPL模式的命令:
$ node
接下来直接输⼊:
console.log("hello node.js!");
就可以在终端打印出:
>hello node.js!
>undefined
写过js的应该对最后会输出undefined并不吃惊,先可以不管。
下⾯解释⼀下REPL模式:
其实这个模式不⽤解释,经过上⾯的例⼦应该就有直观的认识啦,类似mysql、python等的shell交互的⽅式,可以让你输⼊马上就得到反馈,输出结果到屏幕上⾯。在node中可以连续按两次ctrl+c退出(但是python要使⽤exit()函数,很不舒服)。
上⾯是⼀种最简单的⽅式,还是介绍⼀种正规的⽅式吧,既然是js的运⾏平台,我们就写⼀个js⽂件:hello.js,内容很简单,如下:
console.log("hello node.js!");
console.log("%d\n", 60);
在终端执⾏(注意要进⼊hello.js所在⽬录哦):
$ node hello.js
就可以在终端直接输出结果了。
为什么我加⼊了“console.log('%d\n', 60);”这⼀句呢?那是因为这可以测试出其实可以⽤c语⾔printf的⽅式来写console.log()。
六、Node.js终于来到了浏览器
前⾯的例⼦都是在控制台⾥⾯的,没什么意思,我们接下来写⼀个我们典型的B/S访问的⽅式。当然这就离不开HTTP了,查看了⼀下node 的源码,新版本默认是http 1.1,⽀持http和https这两种协议。
我们先建⼀个http.js⽂件,⾥⾯的内容对于后台的开发⼈员就很熟悉了。
var http = require("http");
res.writeHead(200, {"Content-Type": "text/html"});
res.write("<h1>Node.js</h1>");
}).listen(8888);
console.log("HTTP server is listening at port 8888.");
以上代码监听的port:8888,这其实就是建⽴了⼀个request,我们在浏览器地址栏中输⼊:即可以访问我们打印的内容。
我们先在终端运⾏后台服务:
$ node http.js
我们来分析⼀下这个简单的程序,其实从require的加载⽅式我们并不陌⽣,这是现在模块加载在前端普遍使⽤的函数名,那么为什么我们的js代码就能够这样来请求和访问呢?我们来简单的看看源码的解析。
1. ⾸先我们先看看源码的http.js⽂件。
var Server = exports.Server = server.Server;
function createServer() { return new Server(requestListener) };
在这个⽂件中,我们知道createServer()⽅法其实返回的就是Server类,这个类是由server这个实例来的。
2. 接下来我们再追踪⼀下_http_server.js⽂件。
这个要问怎么到这些⽂件的,其实是凭直觉和猜测,再加上模块化的调试⽅法,可以到http.js⽂件的加载模块,就可以到相应的⽂件
了。
function requestListener() {};
function connectionListener(socket) {}
Server.prototype.setTimeout = function(msecs, callback) {};
再这个⽂件中,我们可以看出和Socket原理差不多,使⽤定时器来实现端⼝的监听,但是在源码中可以到主定时器,这个概念来源于游戏开发,在全局设置定时器,这样⼤⼤提升了性能,不得不佩服作者的才能。
3. 那么我们node底层是c/c++来实现的,我们可以追踪⼀下node的启动。
我们先到c语⾔的main⽂件,后来发现好多node_开头的,⼤楷就是系统和⾏⼀点的⽂件了,在⽂件中发现了:node::Start(argc, argv);函数,但是不到具体实现,那么就肯定是在依赖⽂件中,通过头⽂件的声明,到了,其实实现位于⽂件。
4. ⽂件来看node启动流程。
函数⼤致的执⾏顺序为:
int Start(int argc, char** argv)
V8::Initialize();
CreateEnvironment() //创建当前环境
SetupProcessObject() //启动当前环境的进程
Load() //加载当前环境
context() //引⽤上下⽂
uv_run //开始异步事件运⾏
RunAtExit //删除异步事件链表
上⾯可以看出其实就是通过⼀系列初始化,最后达到平台的建⽴。
5. module的加载实质
其实我们经过上⾯的分析,我们⼤致知道的node的构成,那么我们能够在node.js(猜想:这个js⽂件是c和js沟通的桥梁)中,发现传⼊了process对象。源码结构如下:
(function(process) {});
//本地模块的加载接⼝
我们来看⼀看根据process来绑定c语⾔的模块。
var HTTPParser = process.binding("http_parser").HTTPParser;
是不是就很清晰啦,接下来我们看看模块是怎么注册的。
//现在产⽣的插件会放置在node_module⽂件夹下应该很清晰了
//定义了⼀个指针结构
node_module_struct* mod
//注册⾃⼰的模块
mod->register_func(Handle<Object> target)
//为注册的模块设置⼀个上下⽂
mod->register_context_func
//最后加载到模块缓存,这⾥也是实现延迟加载的本质
cache->Set(module, exports)
在模块注册后,还需要做⼀些准备⼯作才能够真正的加载到我们的js⽂件。
//⽂件中执⾏绑定
static void Binding(const FunctionCallbackInfo<Value>& args);
//⽂件中会定义你的js
void DefineJavaScript(Handle<Object> target);
6. 在module.js⽂件中,得到真正的js⽂件的加载,平台调⽤。
在这⾥作者的module数据结构设置得⽐较简单,抛去其它得留下结构如下:
module: {
id: "",
parent: [],
export: {},
filename,
children: []
}
这样我们这个http程序就能够很好得解释啦。其实知道了原理后⾯得知识就是看看api和写法了。太晚啦,睡觉觉啦 =_=...后续...

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。