NPM工具
作者:高京京
邮箱:[email protected]
更改历史
* 2017-11-12 高京京 初始化文档
1 npm的历史、现状和发展
历史
2009年,npm(Node 包管理器)初次发布早期预览版;
2011年,npm 1.0:发布;
2015年,npm 支持私有模块
现状
npm公司发布了其软件包管理工具npm 5.0版,npm 5提升了性能,使其保持了对同类软件的竞争力。 npm的出现使我们分享代码或者复用代码变得更加简单。
发展
npm作为随同node.JS一起安装的包管理工具,在node包管理领域具有天然的优势,是目前javascript工作者使用最广的js包管理工具;
2016年10月,facebook公司推出一款新的包管理工具yarn,相对于npm具有更快,更可靠,更安全的优势,对npm使用率带来巨大的冲击,但是目前yarn还有一些不完善的地方,比如不能够独立升级某个依赖等,所以在一定时间内npm仍将是使用最广的JavaScript包管理器。
npm安装和使用
2.1 npm的安装
由于新版的node.js已经集成了npm,安装nodeJS就安装好npm。
可通过 "npm -v" 来测试是否成功安装。命令如下:
$ npm -v (可查看npm的安装版本)
如果安装成功显示:
安装npm成功之后: a.确认自己的node.js安装的目录:D:\app\node.js。 全局模块安装默认放在C:\Users\Administrator\AppData\Roaming\npm\node_modules里面。
b.然后,我自己配置了模块安装:
node -v
npm -v
npm config set prefix “D:\app\node.js\node_global”
npm config set cache “D:\app\node.js\node_cache”
c.去配置环境变量,
①在系统变量里新建 NODE_PATH ,值为D:\app\node.js\node_global, ②在用户变量上的path变量添加 D:\Program Files\nodejs\node_global。 ③重启下电脑,之后再全局安装了bower:npm i -g bower,之后再查看bower -v就可以显示版本号了,说明安装成功。
npm install bower -g bower init
2.2 npm的使用
npm 的包安装分为本地安装(local)、全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,如下:
npm install <package-name> #本地安装
npm install -g <package-name> #全局安装
下图是在全局环境下安装webpack实例:
在项目工程文件下安装依赖包并保存需要使用先创建package.json文件,下面的代码和图片表示在 ~/DeskTop/webDemo 文件中创建 package.json:
cd ~/DeskTop/webDemo
npm init
输入npm init 后,根据指示直接按下enter键,即可生成package.json,package.json文件内容如下:
{
"name": "npm",
"version": "1.0.0",
"description": "npm",
"main": "npm",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"npm"
],
"author": "shd",
"license": "MIT"
}
install命令可以使用不同参数,指定所安装的模块属于哪一种性质的依赖关系,即出现在packages.json文件的哪一项中。
- –-save:模块名将被添加到dependencies,可以简化为参数-S。
- –-save-dev: 模块名将被添加到devDependencies,可以简化为参数-D。
npm i lodash --save # --save用于将安装包名称添加到package.json的dependencies依赖中
npm i lodash --save-dev # --save用于将安装包名称添加到package.json的devDependencies依赖中
安装完毕后会在工作目录下产生一个node_modules目录,其目录下就是安装的各个node模块;
参数使用 --save 表示将在项目文件下将在package.json的项目依赖选项中添加了下载的node模块; 在其他地方使用该项目时,使用npm install即可自动下载在package.json选项中存在的依赖包,而不需要输入module name
更新本地/全局包
npm update <package-name>
npm update -g <package-name>
安装特定版本号的包:
npm install <package-name>@<version>
实例如下图:
nodejs集成了npm,因此无法全局升级npm,需要在nodejs的安装目录下局部升级npm。例:
cd "e:\nodejs" 进入node.js的安装目录
npm update npm 更新NPM
2.3 其他常用命令
$ npm uninstall express #卸载模块
$ npm update express #更新模块
$ npm search express #搜索模块
$ npm info express #查看模块信息
$ npm ls #查看已经安装的模块列表
$ npm outdated #检查模块是否已经过时
$ npm root #查看包的安装路径
$ npm start #启动模块
$ npm stop #停止模块
$ npm cache #管理模块的缓存
2.4 package.json详解
- 概述
一般前端项目的根目录下都有个一package.json文件;定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。
clone项目后,运行 npm install
指令会自动下载该文件里定义的依赖(包括运行和开发环境下的依赖)并安装到项目根目录下的 node\_modules
目录下;
package.json文件内部就是一个JSON对象,该对象的每一个成员就是当前项目的一项设置。比如name就是项目名称,version是版本(遵守“大版本.次要版本.小版本”的格式)。
主要字段描述
下图为一个完整的package.json文件的示例图: ;
创建package.json
创建package.json有两种方法:手动创建和使用命令行:
npm init
命令行要求回答一些选项;之后再当前目录下生成package.json文件; 在所有问题中只有
name
字段是必填的,其他的都是选填的script 字段
scripts指定了运行脚本命令的npm命令行缩写
图中的指令制定了使用npm run start, npm run build等将要执行的命令;
- dependencies、devDependencies字段
dependencies指明了项目运行的依赖,devDependencies指明了项目开发所依赖的模块;
他们的值为一个对象,对象的键为项目依赖的模块名,值为模块对应的版本号;表明项目依赖的模块和相应的版本号范围;
指定版本:比如1.2.2,遵循“大版本.次要版本.小版本”的格式规定,安装时只安装指定版本。 波浪号(tilde)+指定版本:比如~1.2.2,表示安装1.2.x的最新版本(不低于1.2.2),但是不安装1.3.x,也就是说安装时不改变大版本号和次要版本号。 插入号(caret)+指定版本:比如ˆ1.2.2,表示安装1.x.x的最新版本(不低于1.2.2),但是不安装2.x.x,也就是说安装时不改变大版本号。需要注意的是,如果大版本号为0,则插入号的行为与波浪号相同,这是因为此时处于开发阶段,即使是次要版本号变动,也可能带来程序的不兼容。 latest:安装最新版本。
项目中存在package.json文件使用:
npm install
即可下载安装package.json中定义的模块,并且保存在node_modules目录下
如果在项目中添加模块,可以使用在命令行使用相应的参数
--save|-S
和--save-dev|-D
来将下载的模块信息保存到package.json中npm install --save lodash #将下载的模块信息保存到dependencies对象中; npm install --save-dev gulp #将下载的模块信息保存到devDependencies对象中;
其他字段
name:项目名,npm install依赖此名称! 注意: (1)name中不能包含汉子、空格、不能以点号或下划线开头; (2)不要在name中包含js, node字样; (3)这个名字可能在require()方法中被调用,所以应该尽可能短;
- version:项目版本 注意:npm采用”语义版本“管理软件包。所谓语义版本,就是指版本号为a.b.c的形式,其中a是大版本号,b是小版本号,c是补丁号。
- description:可选字段,必须是字符串。npm search的时候会用到
- keywords:关键字,npm search会用到
- homepage:项目官网的url
- bugs:项目的提交问题的url和(或)邮件地址
- License:如果是使用一个普遍的license
- Author, contributors:author是一个人,contributors是一组人
- engines:指定工作的node的版本
- Main: 可选字段。这个字段的值是你程序主入口模块的ID。如果其他用户需要你的包,当用户调用require()方法时,返回的就是这个模块的导出(exports)
- Bin: 可选字段。很多的包都会有执行文件需要安装到PATH中去。这个字段对应的是一个Map,每个元素对应一个{ 命令名:文件名 }。
{ "bin" : { "npm" : "./cli.js" } }
2.5 npm的缓存机制
npm install <package>
和 npm update <package>
可以下载和更新本地的模块;
其中安装之前,npm install会先检查node_modules目录之中是否已经存在指定模块;如果存在,就不再重新安装了,即使远程仓库已经有了一个新版本,也是如此。 如果你希望,一个模块不管是否安装过,npm都要强制重新安装,可以使用-f或–force参数。
它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。
npm update命令怎么知道每个模块的最新版本呢?
其实,npm 模块仓库提供了一个查询服务,叫做 registry 。以 npmjs.org 为例,它的查询服务网址是 https://registry.npmjs.org/ 。 这个网址后面跟上模块名,就会得到一个 JSON 对象,里面是该模块所有版本的信息。比如,访问 https://registry.npmjs.org/react,就会看到 react 模块所有版本的信息。 它跟下面命令的效果是一样的。
$ npm view react
$ npm info react
$ npm show react
$ npm v react
npm install或npm update命令,从 registry 下载压缩包之后,都存放在本地的缓存目录。 这个缓存目录,在 Linux 或 Mac 默认是用户主目录下的.npm目录,在 Windows 默认是%AppData%/npm-cache。通过配置命令,可以查看这个目录的具体位置。
$ npm config get cache
$HOME/.npm
浏览该文件:
$ ls ~/.npm
$ npm cache ls
你会看到里面存放着大量的模块,储存结构是{cache}/{name}/{version};
每个模块的每个版本,都有一个自己的子目录,里面是代码的压缩包package.tgz文件,以及一个描述文件package/package.json。 除此之外,还会生成一个{cache}/{hostname}/{path}/.cache.json文件。比如,从 npm 官方仓库下载 react 模块的时候,就会生成registry.npmjs.org/react/.cache.json文件。 这个文件保存的是,所有版本的信息,以及该模块最近修改的时间和最新一次请求时服务器返回的 ETag 。
对于一些不是很关键的操作(比如npm search或npm view),npm会先查看.cache.json里面的模块最近更新时间,跟当前时间的差距,是不是在可接受的范围之内。如果是的,就不再向远程仓库发出请求,而是直接返回.cache.json的数据。 .npm目录保存着大量文件,清空它的命令如下。
$ rm -rf ~/.npm/*
# 或者
$ npm cache clean
2.6 模块的安装过程
- 发出npm install命令
- npm 向 registry 查询模块压缩包的网址
- 下载压缩包,存放在~/.npm目录
- 解压压缩包到当前项目的node_modules目录
注意,一个模块安装以后,本地其实保存了两份。一份是~/.npm目录下的压缩包,另一份是node_modules目录下解压后的代码。
2.7 使用NPM淘宝镜像
- 说明
在国内直接使用 npm 的官方镜像是非常慢的,推荐使用淘宝 npm 镜像。
淘宝 npm 镜像是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。
你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:
- 安装
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
- 注意
安装完后最好查看其版本号cnpm -v或关闭命令提示符重新打开,安装完直接使用有可能会出现错误
- tips
cnpm跟npm用法完全一致,只是在执行命令时将npm改为cnpm。
2.4 最佳实践
1. 用npm init来创建你的项目
创建项目的时候,npm init的优点在于能给交互式地替你创建package.json文件,它会弹出问题让你填写项目的名称和描述等等。但其实还有更简化的方式:
$ npm init --yes
如果你使用npm init --yes的话,它不会问你要如何创建,就直接按默认配置创建一个package.json。这个默认配置当然也是可实现设置的:npm config set init.author.name YOUR_NAME npm config set init.author.email YOUR_EMAIL
2. 查找npm的package
考虑到npm中有上万个模块供你选择,要找到合适的package是很困难的。我们团队的经验是这样,最近在Node.js的问卷调查中,很多开发者也告诉我们要找到合适的package是很郁闷的一件事情。所以现在我们试着找一个能发送HTTP请求的模块吧~ npms.io这个网站能很好地帮助到我们。它将各个package的质量、受欢迎度、可维护性等指标做了量化并展现。具体的说,这些指标包括:是否使用了过时的依赖包、是否有代码检查配置、是否经过测试以及最近的版本是何时发布的,等等。
3. 了解你选择的package
当你选定了你要用的模块之后(本例中我们选用了request模块),我们应该首先查看它的文档,看看有什么现存的issue,以便充分了解我们要用在应用中的模块。希望你牢记一点,当使用的npm package越多,你可能遇到的不可靠或危险的package也就越多。想了解更多npm相关的安全风险的话,请阅读我们写的一篇指导文档。 如果想去到package的主页,可执行下面的命令:
$ npm home request
要查看现存的issue,或者公开的roadmap,执行以下命令:$ npm bugs request
另外,如要查看package的仓库,执行以下命令:$ npm repo request
4. 保存依赖
当你找到想用在工程里的package之后,下一步就是安装和保存它。最常用的方式是采用npm install request(译注:其中的request是package名字)。 如果你还想把这个package自动加到package.json里,你可以这样:
$ npm install request --save
npm会把你的依赖保存起来,并加上^前缀。这个前缀的意思是,下次再使用npm install是时候还会自动安装这个package的在此大版本下的最新版本。如果你想修改这个功能的话,可以:$ npm config set save-prefix='~'
如果你就想保存目前的这个版本,可以:$ npm config set save-exact true
5. 锁定依赖
你可以像前面一节讲的那样,在
package.json
里面指定了保存依赖的版本号。但大部分npm模块的作者不会这样做,因为他们想自动地获取补丁和新功能。 但在生产环境下,如果不指定保存依赖的版本号会存在问题。因为如果恰好你开发的过程中作者发布了新版本,那么有可能本地和生产环境使用的依赖的版本就是不一样的。这个时候,如果新版本有bug的话,就会影响到生产环境。 要解决这个问题,你可以使用npm shrinkwrap
。它会生成一个npm-shrinkwrap.json
文件,不仅记录了当前环境中使用的模块精确的版本号,还记录了这些模块的其他依赖的版本,以此类推。一旦工程中有了此文件,npm install
就会使用它来复制一个完全一样的依赖树。6. 查找过时的依赖
npm提供了一个内置的工具方法来查看过时的依赖:npm outdated。
$ npm outdated conventional-changelog 0.5.3 0.5.3 1.1.0 @risingstack/docker-node eslint-config-standard 4.4.0 4.4.0 6.0.1 @risingstack/docker-node eslint-plugin-standard 1.3.1 1.3.1 2.0.0 @risingstack/docker-node rimraf 2.5.1 2.5.1 2.5.4 @risingstack/docker-node
当你维护的项目很多的时候,要保持每个项目中的依赖都是最新的是一件很痛苦的事情。要实现这个任务的自动化,可以选用Greenkeeper,当有依赖更新的时候,它会自动为你的仓库发pull请求。7. 保存生产环境中没有devDepenendencies
称devDepenendencies为开发环境依赖是有原因的,你在生产环境是用不着他们的。生产环境不用这些devDepenendencies可以让你线上的代码包更小更安全,因为多一个依赖就多一个安全风险。 如果需要只安装生产环境依赖,运行:
$ npm install --production
或者,你可以设置NODE_ENV变量为生产环境:$ NODE_ENV=production npm install
8. 确保你的项目和token的安全
如果你开发的时候登陆了Linux系统的用户,那你的
npm token
就会存在.npmrc
文件中。有的时候这个文件会不小心被上传到github。目前,在github上搜索.npmrc
文件的话,能找到好几千个,里面很多都包含了token。如果你自己的仓库里也有.xxx的文件的话,赶快检查下自己的证书有没有被上传! 另一个潜在的安全隐患在于,有的文件会被不小心上发布到npm上。一般来说npm是参考.gitignore
文件来决定哪些文件会被上传。但你也可以加一个.npmignore
文件,它会override.gitignore
。9. 开发package
在本地开发package的时候,大家一般都会在发布之前在自己的项目上先实践一下。这个时候
npm link
就能派上用场。npm link
的作用在于,它会在全局目录创建一个symlink
(符号链接),指向npm link
所运行的那个package。 你也可以在其他地方运行npm link package-name
,这样会在全局安装的package-name
和目前项目的/node_modules
之间创建一个symlink。 可以像下面这样实践一下!/# create a symlink to the global folder /projects/request $ npm link /# link request to the current node_modules /projects/my-server $ npm link request /# after running this project, the require('request') /# will include the module from projects/request
3 同类工具对比
bower: Bower是一个客户端技术的软件包管理器,它可用于搜索、安装和卸载如JavaScript、HTML、CSS之类的网络资源
bower与npm的区别
在实际项目中,NPM和Bower都会被运用。并且Bower的安装和升级全都依赖于NPM,使用如许下命令就可以全局安装Bower:npm install -g bower,之后你就可以使用bower install[#]. 其中。与NPM最大区别在于,NPM主要运用于Node.js项目的内部依赖包管理,安装的模块位于项目根目录下的node_module文件夹内。而Bower大部分情况下用于前端开发,bower 能依据配置文件自动下载相关依赖,非常方便,这也是推荐使用 bower 的原因之一,对于CSS/Js模块等内容进行依赖。依赖的下载目录结构可以自定义。
yarn: facebook公司推出的一款快速、可靠、安全的依赖管理工具
yarn和npm的区别
1.yarn.lock 文件
为了防止拉取到不同的版本,Yarn 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)yarn.lock 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。
npm 其实也有办法实现处处使用相同版本的 packages,但需要开发者执行 npm shrinkwrap 命令。这个命令将会生成一个锁定文件,在执行 npm install 的时候,该锁定文件会先被读取,和 Yarn 读取 yarn.lock 文件一个道理。npm 和 Yarn 两者的不同之处在于,Yarn 默认会生成这样的锁定文件,而 npm 要通过 shrinkwrap 命令生成 npm-shrinkwrap.json 文件,只有当这个文件存在的时候,packages 版本信息才会被记录和更新。
2.并行安装
无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 成功安装之后,才能继续后面的安装。而 Yarn 是同步执行所有任务,提高了性能。
3.输出更简洁
npm 的输出信息比较冗长。在执行 npm install <package> 的时候,命令行里会不断地打印出所有被安装上的依赖。相比之下,Yarn 简洁太多:默认情况下,结合了 emoji (Windows 上 emoji 不可见)直观且直接地打印出必要的信息,也提供了一些命令供开发者查询额外的安装信息。
参考文档:
NPM使用介绍-菜鸟教程: http://www.runoob.com/nodejs/nodejs-npm.html
Node.js&NPM的安装与配置:http://www.infoq.com/cn/articles/nodejs-npm-install-config
node.js的配置以及向git提交代码:http://www.tuicool.com/articles/aiaQR3b
知乎上关于node.js 的话题:https://www.zhihu.com/topic/19569535/top-answers
知乎中关于npm的话题:https://www.zhihu.com/question/24414899
npm,bower,jamjs等包管理工具各自的特性及区别:https://www.zhihu.com/question/24414899
package.json中文文档:http://www.mujiang.info/translation/npmjs/files/package.json.html