NPM与包

Node组织了自身的核心模块,也使得第三方文件模块可以有序地编写和使用。但是在第三方模块中,模块与模块之间仍然是散列在各地的,相互之间不能直接引用。在模块之外,包和NPM是将模块联系起来的一种机制。 - 朴灵

NPM遵循CommonJS的包规范。CommonJS包规范定义包结构和包描述文件两个部分,前者用于组织包中的各种文件,后者则用于描述包的相关信息,以供外部文件读取分析。

下面分别介绍一下包结构和包描述文件。

包结构

符合CommonJS规范的包目录应该包含一下文件:

1. package.json:包描述文件
2. bin:用于存放可执行二进制文件的目录
3. lib:用于javascript代码的目录
4. doc:用于存放文档的目录
5. test:用于存放单元测试用例的代码

可以看到,CommonJS包规范从文档、测试等方面都做过考虑。

包描述文件与NPM

包描述文件是一个JSON格式的文件(package.json),位于包的根目录下,是包的重要组成部分。NPM的所有行为都有包描述文件的字段息息相关。

CommonJS对于包描述文件定义了以下必须的字段。

1. name:包名

包名由小写的字母和数字组成,可以包含.、_和-,不允许出现空格。包名必须是唯一的。

2. description:包简介

3. version:版本号

版本号十分重要,常常用于一些版本控制的场合。

4. keywords:关键词数组

用于分类搜索。一个好的关键词数组有利于快速找到编写的包。

5. maintainers:包维护者列表

每个维护者由name、email和web三个属性组成,NPM通过此属性进行权限验证。

6. contributors:贡献者列表

贡献者列表第一个贡献者是包作者本人。其他贡献者是对此包有过贡献的人。

7. bugs:一个反馈bug的网页地址或邮件地址

8. licenses:许可证列表

当前包使用的许可证列表,表明这个包可以在哪些许可证下使用。

9. repositories:托管源代码的位置列表

表明可以通过哪些方式和地址访问包的源代码。

10. dependencies:当前包所需要依赖的包列表

这个属性十分重要,NPM会通过这个属性帮助自动加载依赖的包。

以上都是必须字段,除了必选字段,规范还定义了一些可选字段。

1. homepage:当前包的网站地址

2. os:操作系统支持列表

这些操作系统的取值包括aix、freebsd、linux、macos、solaris、vxworks、windows。

3. cpu:CPU架构的支持列表

有效的架构名称为arm、mips、ppc、sparc、x86和x86_64。

4. engine:支持的JavaScript引擎列表

有效的引擎取值包括ejs、flusspfered、gpsee、jsc、node和v8等。

5. builtin:标志当前包是否是内建在底层系统中的标准组件

6. directories:包目录说明

7. implements:实现规范的列表

标志当前包实现了CommonJS的哪些规范。

8. scripts:脚本说明对象

主要被包管理用来安装、编译、测试和卸载包。

包规范的定义可以帮助Node解决依赖包安装的问题,NPM正式基于该规范进行了实现。

包描述文件的规范中,NPM实际需要的字段有name、version、description、keywords、repositories、author、bin、main、scripts、engines、dependencies、devDependenices。

相对于包规范来说,多了author、bin、main、devDependencies4个字段。

1. author:包作者

2. bin

配置好bin字段后,可以直接通过npm install pageage_name -g命令添加脚本到执行路径,可以在命令行直接执行。

3. main

使用require引入包时,会检查这个字段,并将其作为包中其余模块的入口。
如果不存在这个字段,会查找包目录下的index.js、index.node、index.json文件作为默认入口。

4. devDependencies:开发环境下需要配置的依赖

NPM常用功能

CommonJS包规范是理论,NPM是其中的一种实践。对于Node而言,NPM帮助其完成第三方模块的发布、安装和依赖等。借助NPM,Node与第三方模块形成了一个很好的生态系统。

下面介绍一下NPM常用的一些功能。

1. 查看帮助

安装好NPM之后,可以使用 npm -v 查看当前NPM的版本。

npm1.png

可以看到,我的电脑目前安装的NPM版本是6.4.1。

在不熟悉NPM命令时,可以直接执行 npm 查看帮助引导说明。

npm2.png

可以看到,帮助中列出了所有的命令。

2. 安装依赖包

安装依赖包是NPM最常见的用法。安装好依赖包之后,就可以使用require关键字引入。

全局模式安装

如果包中存在命令行工具,可以使用 npm install package_name -g 命令进行全局模式安装。全局模式并不是将一个模块安装为一个全局包的意思,并不意味着可以在任何地方通过require来引用它。

实际上,-g是将一个包安装为全局可用的可执行命令。它根据包描述文件的bin字段配置,将实际脚本链接到与Node可执行文件相同的路径下。

本地安装

对于一些没有发布到NPM上的包,或是因为网络原因导致无法直接安装的包,可以通过将包下载到本地,然后以本地安装。本地安装只需为NPM指明pageage.json文件所在的位置即可。

具体参数如下:

npm install <tarball file>
npm install <tarball url>
npm install <folder>
非官方源安装

安装包可以不通过官方源安装,可以通过镜像源安装。
执行命令时,添加 –registry=http://registry.url即可。示例如下:

npm install underscore --registry=http://registy.url

3. NPM钩子说明

package.json中scripts字段的提出让包在安装或者卸载过程中提供钩子机制。

"scripts": {
  "preinstall": "preinstall.js",
  "install": "install.js",
  "uninstall": "uninstall.js",
  "test": "test.js"
}

在运行 npm install * 时,会首先执行preinstall指向的脚本,然后install指向的脚本会被执行。在执行 npm uninstall * 时,会执行uninstall执行的脚本。

当执行npm test时,会运行test执行的脚本。一个优秀的包应该包含测试用例,方便用户进行测试,以便检测包是否文档可靠。

4. 发布包

预想写一下发布包的流程,奈何账号验证的时候,NPM内部服务器错误,就略过吧,有时间再补一篇如何发布自己的自定义组件。(哈哈,没办法,就是这么任性。)

局部NPM

企业内部使用NPM有个人使用有一定的差别。企业的限制在于,享受模块开发带来的低耦合和项目组织上的好处时,也要考虑模块保密性的问题。现有的解决方案就是企业搭建自己的NPM仓库。关于如何搭建自己的个人仓库,有时间再分享。

NPM存在问题

NPM目前潜在的问题在于,在NPM平台上,每个人都可以分享包到平台上,鉴于开发人员水平不一,上面的包也良莠不齐。另外一个问题则是,Node代码可以运行在服务器端,需要考虑安全问题。

为了解决上述问题,可以使用CPAN社区中的 Kwalitee 风格来让模块自然排序。
符合 Kwalitee 的模块要满足的条件大致如下。

1. 具备良好的测试
2. 具备良好的文档(README、API)
3. 具备良好的测试覆盖率
4. 具备良好的编码规范

CPAN社区制定了相当多的规范来考察模块。未来,NPM社区也会有更多的规范来考察模块。

总结

文章主要介绍一下包与NPM之间的关系,文章内容大多来源于《深入浅出Node.js》,感兴趣的同学可以买一本精读,文章质量是很好的,既有深度又有广度。