CommonJS包规范是理论,NPM是其中的一种实践。NPM之于Node,相当于gem之于Ruby,pear之于PHP。对于Node而言,NPM帮助完成了第三方模块的发布、安装和依赖等。借助NPM,Node与第三方模块之间形成了很好的一个生态系统。
借助NPM,可以帮助用户快速安装和管理依赖包。除此之外,NPM还有一些巧妙的用法,下面我们详细介绍一下:
## 1.查看帮助
在安装Node之后,执行 npm -v 命令可以查看当前NPM版本:
~~~
$ npm -v
1.2.32
~~~
在不熟悉NPM的命令之前,可以直接执行NPM查看帮助引导说明:
~~~
$ npm
Usage: npm <command>
where <command> is one of:
add-user, adduser, apihelp, bin, bugs, c, cache,
complection, config, ddp, dedupe, deprecate, docs, edit,
explore, faq, find, find-dupes, get, help, help-search,
home, i, info, init, install, isntall, issues, la, link,
list, ll, ln, login, ls, outdated, owner, pack, prefix,
prune, publish, r, rb, rebuild, remove, restart, rm, root,
run-script, s, se, search, set, show, shrinkwrap, star,
stars, start, stop, submodule, tag, test, tst, un,
uninstall, unlink, unpublish, unstar, up, update, version,
view, whoami
npm <cmd> -h quick help on <cmd>
npm -l display full usage info
npm faq commonly asked questions
npm help <item> search for help on <item>
Specify configs in the ini-formatted file:
/Users/jacksontian/.nmprc
or on the command line via: npm <command> --key value
Config info can be viewed via: npm help config
npm@1.2.32 /usr/local/lib/node_modules/npm
~~~
可以看到,帮助中列出了所有的命令,其中npm help <command> 可以查看具体的命令说明。
## 2.安装依赖包
安装依赖包是NPM最常见的用法,它的执行语句是 npm install express。执行该命令后,NPM会在当前目录下创建node_modules目录,然后在node_modules下创建express目录,接着将包解压到这个目录下。
安装好依赖包后,直接在代码中调用require('express');即可引入该包。require()方法在做路径分析的时候会通过模块路径查找到express所在的位置。模块引入和包的安装这两个步骤是相辅相成的。
**全局模式安装**
如果包中含有命令行工具,那么需要执行 npm install express -g 命令进行全局模式安装。需要注意的是,全局模式并不是将一个模块包安装为一个全局包的意思,它并不意味着可以从任何地方通过require()来引用到它。
全局模式这个称谓其实并不准确,存在诸多误导。实际上,-g 是将一个包安装为全局可用的可执行命令。它根据包描述文件中的bin字段配置,将实际脚本链接到与Node可执行文件相同的路径下:
~~~
"bin":{
"express":"./bin/express"
},
~~~
事实上,通过全局模式安装的所有模块包都被安装进了一个统一的目录下,这个目录可以通过如下方式推算出来:
~~~
path.resolve(process.execPath,"..",'..','lib', 'node_modules');
~~~
如果Node可执行文件的位置是 /usr/local/bin/node ,那么模块目录就是 /usr/local/lib/node_modules。最后,通过软链接的方式将bin字段配置的可执行文件链接到Node的可执行目录下。
**从本地安装**
对于一些没有发布到NPM上的包,或是因为网络原因导致无法直接安装的包,可以通过将包下载到本地,然后以本地安装。本地安装只需为NPM指明package.json文件所在的位置即可:它可以是一个包含package.json的存档文件,也可以是一个URL地址,也可以是一个目录下有package.json文件的目录位置。具体参数如下:
~~~
npm install <tarball file>
npm insatll <tarball url>
npm install <folder>
~~~
**从非官方源安装**
如果不能通过官方源安装,可以通过镜像源安装。在执行命令时,添加 `--registry=http://registry.url`即可,示例如下:
~~~
npm install underscore --registry=http://registry.url
~~~
如果使用过程中几乎都采用镜像源安装,可以执行一下命令行指定默认源:
~~~
npm config set registry http://registry.url
~~~
## 3.NPM钩子命令
另一个需要说明的是C/C++模块实际上是编译后才能使用的。package.json中scripts字段的提出就是让包安装或者等过程中提供钩子机制,示例如下:
~~~
"scripts":{
"preinsatll":"preinstall.js",
"install":"install.js",
"uninstall":"uninstall.js",
"test":"test.js"
}
~~~
在以上字段中执行 npm install <package> 时,preinstall 指向的脚本会被加载执行,然后install指向的脚本会被执行。在执行 npm uninstall <package> 时,uninstall指向的脚本也许会做一些清理工作等。
当在一个具体的包目录下执行 npm test 时,将会运行 test 指向的脚本。一个优秀的包应当包含测试用例,并在package.json 文件中配置好运行测试的命令,方便用户运行测试用例,以便检验包是否稳定可靠。
## 4.发布包
为了将整个NPM的流程串联起来,这里将演示如何编写一个包,将其发布到NPM仓库中,并通过NPM安装回本地。
**编写模块**
模块的内容我们尽量保持简单,这里还是以sayHello作为例子,相关代码如下:
~~~
exports.sayHello = function(){
return 'Hello World!';
};
~~~
将这段代码保存为hello.js即可。
**初始化包描述文件**
package.json文件的内容尽管相对较多,但是实际发布一个包时并不需要一行一行编写。NPM提供的 npm init 命令会帮助你生成 package.json 文件,具体如下所示:
~~~
$npm init
This unility will walk you through creating a package.json file.
It only covers the most common items,and tries to guess sane defaults.
See 'npm help json' for definitive documentation on these fields
and exactly what they do.
Use 'npm install <pkg> --save' afterwards to install a package and save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (module) hello_test_jackson
version: (0.0.0) 0.0.1
description: A hello world package
entry point: (hello.js) ./hello.js
test command:
git repository:
keywords: Hello world
author: Jackson Tian
license: (BSD) MIT
About to write to /Users/jacksontian/git/divelntonode/examples/03/module/package.json
{
"name":"hello_test_jackson",
"version":"0.0.1",
"description":"A hello world package",
"main":"./hello.js",
"scripts":{
"test":"echo \"Error: no test specified\" && exit 1"
},
"repository":"",
"keywords":[
"Hello",
"world"
],
"author":"Jackson Tian",
"license":"MIT"
}
Is this ok? (yes) yes
npm WARN package.json hello_test_jackson@0.0.1 No README.md file found!
~~~
NPM通过提问式的交互逐个填入选项,最后生成预览的包描述文件。如果你满意,输入 yes ,此时会在目录下得到 package.json 文件。
**注册包仓库账号**
为了维护包,NPM必须要使用仓库账号才允许将包发布到仓库中。注册帐号的命令是 npm adduser 。这也是一个提问式的交互过程,按顺序进行即可:
~~~
$ npm add user
Username: (jacksontian)
Email: (shyvo1987@gmail.com)
~~~
**上传包**
上传包的命令是 npm publish <folder> 。在刚刚创建的 package.json 文件所在的目录下,执行 npm publish . 开始上传包,相关代码如下:
![](https://box.kancloud.cn/2016-08-28_57c1cec120b7c.png)
在这个过程当中,NPM会将目录打包为一个存档文件,然后上传到官方源仓库中。
**安装包**
为了体验和测试自己上传的包,可以还一个目录执行 npm install hello_test_jackson 安装它:
~~~
$ npm install hello_test_jackson --registry=http://registry.npmjs.org
~~~
**管理包权限**
通常,一个包只有一个人拥有权限进行发布。如果需要多人进行发布,可以使用 npm owner 命令帮助你管理包的所有者。
![](https://box.kancloud.cn/2016-08-28_57c1cec13d1df.png)
使用这个命令,也可以添加包的拥有者,删除一个包的拥有者:
![](https://box.kancloud.cn/2016-08-28_57c1cec154048.png)
## 5.分析包
在使用NPM的过程中,或许你不能确定当前目录下能否通过 require() 顺利引入想要的包,这时可以执行 npm ls 分析包。
这个命令可以为你分析出当前路径下能够通过模块路径找到的所有包,并生成依赖树,如下:
![](https://box.kancloud.cn/2016-08-28_57c1cec165130.png)
- 目录
- 第1章 Node 简介
- 1.1 Node 的诞生历程
- 1.2 Node 的命名与起源
- 1.2.1 为什么是 JavaScript
- 1.2.2 为什么叫 Node
- 1.3 Node给JavaScript带来的意义
- 1.4 Node 的特点
- 1.4.1 异步 I/O
- 1.4.2 事件与回调函数
- 1.4.3 单线程
- 1.4.4 跨平台
- 1.5 Node 的应用场景
- 1.5.1 I/O 密集型
- 1.5.2 是否不擅长CPU密集型业务
- 1.5.3 与遗留系统和平共处
- 1.5.4 分布式应用
- 1.6 Node 的使用者
- 1.7 参考资源
- 第2章 模块机制
- 2.1 CommonJS 规范
- 2.1.1 CommonJS 的出发点
- 2.1.2 CommonJS 的模块规范
- 2.2 Node 的模块实现
- 2.2.1 优先从缓存加载
- 2.2.2 路径分析和文件定位
- 2.2.3 模块编译
- 2.3 核心模块
- 2.3.1 JavaScript核心模块的编译过程
- 2.3.2 C/C++核心模块的编译过程
- 2.3.3 核心模块的引入流程
- 2.3.4 编写核心模块
- 2.4 C/C++扩展模块
- 2.4.1 前提条件
- 2.4.2 C/C++扩展模块的编写
- 2.4.3 C/C++扩展模块的编译
- 2.4.2 C/C++扩展模块的加载
- 2.5 模块调用栈
- 2.6 包与NPM
- 2.6.1 包结构
- 2.6.2 包描述文件与NPM
- 2.6.3 NPM常用功能
- 2.6.4 局域NPM
- 2.6.5 NPM潜在问题
- 2.7 前后端共用模块
- 2.7.1 模块的侧重点
- 2.7.2 AMD规范
- 2.7.3 CMD规范
- 2.7.4 兼容多种模块规范
- 2.8 总结
- 2.9 参考资源
- 第3章 异步I/O
- 3.1 为什么要异步I/O
- 3.1.1 用户体验
- 3.1.2 资源分配
- 3.2 异步I/O实现现状
- 3.2.1 异步I/O与非阻塞I/O
- 3.2.2 理想的非阻塞异步I/O
- 3.2.3 现实的异步I/O
- 3.3 Node的异步I/O
- 3.3.1 事件循环
- 3.3.2 观察者
- 3.3.3 请求对象
- 3.3.4 执行回调
- 3.3.5 小结
- 3.4 非I/O的异步API
- 3.4.1 定时器
- 3.5 事件驱动与高性能服务器