2.2 软件包管理系统Node Package Manager(npm)
依赖关系是软件包管理的一个重要方面。每个软件包都有可能依赖其他的软件包,例如软件包A需要软件包B,而软件包B需要软件包C。通常这些软件包并不具备自动安装所依赖的软件包的功能,当用户安装软件包A时,他需要预先手工安装软件包B和C。如果依赖关系复杂的话,则用户将不得不花大量精力去处理这些软件包之间的依赖关系。
软件包管理系统一般能够从软件源处自动下载所依赖的软件包并安装,解决软件包之间的依赖关系,所以软件包管理系统在各种系统软件和应用软件的安装管理中均有广泛应用。例如,微软.Net开发平台上的软件包管理系统是NuGet。
Node Package Manager(npm)顾名思义是Node.js的软件包管理系统,完全以JavaScript编写,支持跨平台,由Isaac Z. Schlueter在2010年创建,主要功能包括:
• 一个在线仓库(https://registry.npmjs.org),允许开发人员将自己编写的JavaScript软件包注册并上传到这个在线仓库供下载使用。
• 命令行工具用于解决JavaScript软件包的依赖关系,例如从在线仓库中搜索、下载、安装、卸载、更新所需要的JavaScript软件包,并将它们整合到自己的项目中。在本书中npm主要指这个命令行工具。
2.2.1 安装和更新npm
npm不需要单独安装,安装Node.js时会一并安装npm,它是Node.js的默认软件包管理工具。由于npm更新频繁,Node.js附带的npm可能不是最新版本,用户可以在命令控制台执行以下命令将其更新到最新版本。
npm install npm@latest -g
运行npm命令可查看各种信息。
(1)查看npm的版本,命令如下:
npm -v
(2)查看npm命令列表,命令如下:
npm help
(3)查看npm的配置,命令如下:
npm config list -l
2.2.2 package.json
Node.js项目的根目录下一般会有一个package.json文件。这个文件定义了当前项目的属性,包括项目运行时所依赖的软件包。
package.json常用属性如表2-2所示。
表2-2 package.json常用属性
以下是一个基本的package.json文件。在package.json文件中,只有name和version字段是必要的,其他字段都是可选的。
{ "name": "myproj", "version": "1.0.0", "description": "", "main": "index.js", "dependencies": { "jquery": "^3.1.1", }, "devDependencies": { "karma": "^1.3.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
以上package.json示例定义了项目的入口文件为index.js。当其他Node.js应用通过require引用这个软件包时,index.js文件将被调用。
package.json文件可以手工编写,也可以通过执行npm init命令自动生成。该命令采用互动方式,要求用户回答一些问题,然后在当前目录下生成一个基本的package.json文件。所有问题之中,只有项目名称(name)和项目版本(version)是必填的。
本书的示例是Web前端程序,不是Node.js项目,那为什么要介绍package.json文件呢?
2.2.3 安装软件包
本书介绍package. json文件,是因为它可以定义项目运行时所依赖的软件包(dependencies)和开发环境所依赖的软件包(devDependencies)。有了package.json文件,开发人员可以在项目根目录下直接执行npm install命令,该命令会根据package.json文件从在线仓库中下载dependencies和devDependencies中列出的软件包,安装到当前目录的node_modules子目录中,这样就解决了Web前端程序的依赖问题。
package.json文件里的dependencies和devDependencies字段列出的软件包采用语义化版本,npm install会根据这个信息下载相应版本的软件包,例如:
"devDependencies": { "karma": "^1.3.0" },
其中,^前缀表示与指定版本兼容,最左边的主要版本不变,但是次要版本和补丁版本可以是更高的版本。例如“^1.3.0”表示这个项目支持>=1.3.0但是<2.0.0版本的Karma。npm install会下载符合条件的最新版本的软件包。如果想要了解更多有关npm的语义化版本信息,可以参考https://docs.npmjs.com/misc/semver。
如果只安装dependencies字段里列出的软件包,可以执行以下命令:
npm install --production
不要将node_modules目录提交到源代码管理系统中。基于package.json,只需要执行命令npm install就可以恢复项目的开发和运行环境。
如果项目依赖的软件包没有被定义在package.json文件里,那么这些软件包需要单独安装。安装软件包的形式分两种:本地安装与全局安装。
1.本地安装
本地安装软件包的命令是:
npm install <package name>
本地安装的软件包会被下载到当前所在目录(通常是当前项目的根目录)的node_modules子目录中,适用于安装一些JavaScript库和框架。这些库和框架会被当前项目所引用。
如果使用--save参数,npm命令会将软件包信息写入package.json文件的dependencies字段中,这通常用于安装项目运行所需要的软件包。
npm install <package name> --save
如果使用--save-dev参数,npm命令会将软件包信息写入package.json文件的devDependencies字段中。这样的软件包通常仅被用于开发环境。
npm install <package name> --save-dev
建议在每个项目的根目录中都创建一个package.json文件。
在使用npm安装软件包时,建议使用--save或--save-dev参数。
例如当前项目需要karma软件包,c:\myproj是当前项目的根目录,打开命令控制台,将当前目录切换到c:\myproj,执行以下命令:
C:\>cd c:\myproj
然后执行以下命令(因为karma用于测试JavaScript代码,属于开发环境需要的软件包,所以使用--save-dev参数):
C:\myproj>npm install karma --save-dev
安装完毕后会输出以下信息:
C:\myproj>npm install karma --save-dev myproj@1.0.0 C:\myproj `-- karma@1.3.0 +-- bluebird@3.4.6 +-- body-parser@1.15.2 | +-- bytes@2.4.0 | +-- content-type@1.0.2 | +-- debug@2.2.0 | | `-- ms@0.7.1 | +-- depd@1.1.0 …
以上输出信息的简单说明如下:
• karma@1.3.0,当前安装的软件包,版本为1.3.0。
• bluebird@3.4.6, karma依赖的软件包,版本为3.4.6。
• body-parser@1.15.2, karma依赖的软件包,版本为1.15.2。body-parser依赖的软件包在这个树状结构的下一层。
karma软件包被安装在node_modules目录下的karma子目录中。除karma目录外,还有其他依赖软件包的目录,这些都是NPM根据软件包的依赖关系自动下载的,如图2-5所示。
图2-5 node_modules目录
2.全局安装
全局安装指的是将软件包安装到一个全局安装目录中,这样各个项目都可以使用这些软件包。一般来说,全局安装适用于各种Node.js工具。例如npm本身就是一个全局安装的软件包,所以可以在命令控制台里直接执行npm。
全局安装软件包的命令是:
npm install -g <package name>
例如,本书示例需要使用gulp工具,就可以采用全局安装的方式,使各个项目都可以使用gulp工具。具体命令如下:
npm install -g gulp
运行以上命令后,gulp工具被安装到目录{prefix}\node_modules\中。在作者的计算机上,{prefix}是C:\Users\demouser\AppData\Roaming\npm目录。以下命令会显示当前{prefix}的值:
npm config get prefix
全局安装目录也可以通过以下命令进行修改:
npm config set prefix=c:\global_packages
修改全局安装目录后,软件包会被安装到c:\global_packages\node_modules。
修改完全局安装目录后,请将新的目录添加到Windows的环境变量PATH中,并将旧目录从PATH环境变量中删除。以后就可以在命令控制台中直接执行全局安装的工具了。
2.2.4 列出已安装的软件包
npm list命令以树型结构列出当前项目安装的所有软件包,以及它们依赖的软件包。具体命令如下:
npm list
如果加上一个参数-g或--global就可以列出全局安装的软件包和它们依赖的软件包。具体命令如下:
npm list -g
如果不想输出所依赖软件包的信息,可以添加--depth参数。具体命令如下:
npm list -g --depth=0
运行以上命令将得到如下结果:
C:\>npm list -g --depth=0 c:\global_packages +-- gulp@3.9.1 `-- npm@3.10.8