天天都在使用 npm,但本身明白不少地方仍是不清楚,为此决定仔细阅读 npm 的官方文档,这篇文章讲解了 npm 的基本使用方法,后续会讲 npm 的一些高级用法。node
虽然前不久出现的 yarn 确实比 npm 快,可是我想 npm 至少还会使用好久,所以有必要详细了解它。react
package.json
中的常见字段package.json
至关因而一个项目的总体描述,其中记录了该项目的 git 地址,项目简介,依赖模块,bug 汇报地址等等信息,现在不少工具都利用 package.json
来存放配置文件,好比 eslint 能够读取 package.json
中的 eslintConfig
字段来获取配置,babel 能够读取 babel
字段来获取配置。webpack
关于 package.json
中每一个字段的定义,请参照官方文档 package.json,这里只提到一些很是经常使用的字段。git
包名,这个名字决定了包在 node_modules
中的文件夹名,能够加上 scope,好比 @att/wxx
,scope 为 att
,用户安装的时候会被安装在 node_modules/@att/
这个文件夹下。web
该模块的入口文件,好比 "main": "build/index.js"
,别人在 require 这个包的时候,实际是 require 了项目中的 build/index.js
这个文件。typescript
用来指定可执行文件的名称和路径,好比 { "bin" : { "wxx-cli" : "src/cli.js" } }
,这样用户在安装该模块的时候,npm 会建立一个文件叫作 wxx-cli
放置在 node_modules/.bin
文件下,并将其连接至 src/cli.js
这个文件上。关于此,后面还会详细讲解。express
用来指定一些脚本,也就是人们一般所说的 npm script,这个字段是一个对象,在这里能够自定义多个命令,这些命令可使用 npm run 来执行,好比:npm
{ "scripts":{ "build": "webpack", "start": "webpack-dev-server" } }
有了上面这样的配置,在项目中执行 npm run build
就会执行命令 webpack
,npm script 涉及的东西较多,后面有专门的一章来说它。json
package.json
中的 dependencies
和 devDependencies
分别记录了该项目在生产环境下依赖的模块,和在开发环境下依赖的模块。gulp
好比一个项目使用了 typescript 来开发,在发布的时候一般要将代码编译为 JavaScript,所以在开发的时候使用的 typescript 就应该放在 devDependencies
,因此在安装的时候,可使用 npm i typescript --save-dev
来安装。
另外项目代码中依赖了一个模块 qs
来解析 url,为了让你的代码跑起来,这个模块必须存在,所以,必须将该模块记录在 dependencies
中,使用 npm i qs --save
来进行安装。这样用户在运行你的代码的时候,你代码中的 require('qs')
才不至于找不到模块报错。
peerDependencies 经常出如今一些插件的 package.json
中,好比一个 react 的第三方组件,它只能用在 react 版本高于 15.0.0 的时候,此时它就应该这样写:
{ "peerDependencies": { "react": "15.x" } }
这表示,要想使用我,你必须使用 react 15.0.0 之后的版本,请确保你安装了 react 15.0.0 之后的版本。
为何要存在 peerDependencies
呢?
使用 peerDependencies
代表的是,我与另一个模块协调工做。这有别于依赖于某个模块,仔细体会,他们之间的差别很微妙。一个插件,可能不会去引用摸个模块,好比一个 jQuery
插件,它只是在 jQuery.propotype
上添加了一些方法,所以在安装插件的时候,插件应该是默认你已经安装了它的宿主模块。npm3 之后,在执行 npm install
的时候不会安装 peerDependencies
中的模块,这是符合 peerDependencies
的设计理念的。
如何使用 peerDependencies
?
若是你的模块与另一些模块协同工做,该模块要想工做,须要用户已经安装另一个模块,好比一个 webpack 的 loader,一个 gulp 的插件,一个 express 的中间件等等。这个时候你须要考虑使用 peerDependencies
。
另外,设置 peerDependencies
的时候 版本范围要大,试想一下,你的项目中使用了 10 个 react 的第三方组件,这些第三方组件的 peerDependencies
分别是这样写的 "react": "15.0.0"
,"react": "15.1.0"
,"react": "15.2.0"
...,这时候会出现什么状况?状况是你没办法同时使用这些第三方组件,由于它们限定了要使用某个特定版本的 react,你没有办法兼顾全部组件的要求。
当相反,若是版本的限制要求的比较宽泛,好比 "react": ">15.0.0"
表示大于 15.0.0 版本就行了,这样以来全部的组件均可以融洽相处了。
Ok,上面这些 package.json
中的字段算是最为常见的了,其余有些看到单词就知道是什么意思了,还有一些不常见,如需了解,请参见官方文档。
package.json
使用 npm init
来建立一个 package.json
,在建立的过程当中要求输入一些基本信息,若是但愿使用默认内容,可使用 npm init --yes
这样就不须要一步步按回车了。
能够经过 npm set
来设置默认项,好比 npm set init.author.email "i@example.com"
设置默认邮件。
在安装模块的时候一般使用 npm install <package name>
好比 npm install q
,也可使用缩写 npm i q
,但更多时候当咱们安装了一个模块后,一般但愿将它记录下来,将其写入到 package.json
中,在安装模块的时候,能够经过 --save
和 --save-dev
选项来将一个模块添加至 dependencies
或 devDependencies
中。
一个模块的版本号应该形如 1.0.0
,在版本升级的时候,每一位表明着不一样的变化:
修改 bug,打补丁,应该修改最后一位,好比 1.0.1
新的特性,且不会影响现存的特性,比较小的修改,增长中间一位,好比 1.1.0
大的修改,对现有功能有影响,增长第一位,好比 2.0.0
安装第三方模块的时候须要指定其版本号,若是你打开一个既有项目的 package.json
,会看到 ^
, ~
这样的符号,由于依赖的模块是在不断升级的,这些符号表示接受怎样的升级:
用户在安装某个模块的时候,也会一并安装该模块依赖的模块(存在于 dependencies
中的模块),这个时候 npm 会安装最新的知足你版本要求的模块。看下面详细说明:
接受微小的升级,bug 修复:1.0 或者 1.0.x 或者 ~1.0.4,这表示在安装的时候接受最后一位的变化。好比在初次安装的时候,模块 A 是 1.0.0 版本,用户下次安装的时候 A 模块已经升级到了 1.0.9,这个时候就会安装 1.0.9 版本,若是 A 项目的维护者,下次发布了 1.1.0 那么,再次安装的时候依然会安装 1.0.9。
接受较小的升级,新增特性:1 或者 1.x 或者 ^1.0.4,这表示接受中间位置的变化
接受重大升级:*
或者 x
懂得这个很重要,不少时候这个符号写的不对,致使依赖模块升级后,整个项目就跑不起来了。固然了有时候会看到更加复杂的写法,请参照这里 semver 了解更高级的用法。
依赖的模块才你开发的过程当中也可能在升级,为了得到符合你的版本描述的最新版本,能够在 package.json
所在目录下执行 npm update
来升级模块。也能够经过执行 npm outdated
来获取当前项目中可升级的模块的信息。
由于项目变更,不须要使用某个模块了,这个时候不该该让他继续存在于 package.json
中的,没有使用到,但仍是要被安装,这显然是浪费资源,污染环境的作法。使用 npm uninstall loadsh
来卸载一个模块,不会从 package.json
中删除该模块,须要添加 --save
和 --save-dev
来卸载他们。
有两种模式来安装模块 global 和 local,安装在全局的模块一般是一些命令行工具,好比 eslint
,能够将其安装在全局,在任何目录下都能使用。可是全局的模块只能存在一个版本,这也是为何不少时候一些模块建议安装在本地,这样不一样的项目可使用不一样的版本,避免不一样项目之间的冲突。将一个模块安装在全局,只须要加上 -g
选项,好比 npm i eslint -g
。
安装全局模块,经常出现一些权限问题,一般是由于当前用户没有 npm 全局安装目录的写权限,为此可使用 chown 来修权限,也能够直接使用 sudo 来执行 npm install 操做,或者将 npm 默认安装目录修改成一个本身具备权限的目录。这些操做请参考 Fixing npm permissions
升级一个全局模块,只须要执行 npm update -g <package>
便可,好比 npm update -g gulp
。
很简单 npm uninstall -g <package>
好比 npm uninstall -g eslint
建立了一个项目,填写了 package.json,为了让本身的代码让更多人使用,须要将其发布到 npm 上面,须要仔细填写 package.json 中的 description
和 keywords
这些字段的信息将有助于其余人在 npm 上搜索到该模块。
为了将模块发布到 npm 上,首先须要建立一个 npm 的帐号,这能够在 https://npmjs.com/ 上建立帐号,也可使用 npm adduser 在命令行中建立帐号。若是是在网站上注册的帐号,须要使用 npm login
来登陆。在登陆的时候须要输入用户名和密码,以及你的 E-mail。
登陆完成后执行 npm publish
就能够发布模块了,在发布模块以前要确保你的模块名在当前的 npm 仓库中是不存在的。另外本地的一些测试文件,一般不须要发布在 npm 上,这样用户在安装的时候只会下载那些必要的文件,npm 在发布的时候会忽略掉全部 .gitignore
和 .npmignore
中忽略的文件,一般你应该在 .npmignore
中忽略掉测试文件、文档等内容,另外要提供一个 README.md
。
对本身的模块进行了升级之后,须要将更新发布到 npm 上去,这个时候要一样是使用 npm publish
,可是在此以前要注意更新版本号,你能够手动更改,也可使用 npm version <update_type>
来更改,这儿的 update_type
能够是 patch
, minor
, major
使用这三个值,npm 会对应地将版本号的第 3 位、第 2 位、第 1 位加 1,分别表示这次升级有微小改动、有较小改动以及有大幅改动。
有些时候须要建立一个公司内部使用的模块,或者某个模块已经有了同名的模块存在,这个时候能够用到带有命名空间的模块,其名称形如 @scope/project
,在 npm 上面带有命名空间的模块默认是私有的,并且每一个用户有有一个属于本身的命名空间也就是 @username
,在 npm 上私有的模块是要付费的,所以为了免费地发布一个带有命名空间的模块,须要将该模块设置为公开的,只须要在执行 publish
的时候加上 --access=public
选项便可。
在安装这些带有命名空间的模块的时候须要这样安装 npm install @scope/project --save
,在项目中引用的时候也要带上 scope,require('@scope/project')
。
npm 也容许开发着给某个版本打 tag,好比当版本进行到 1.0.9 的时候能够给他打个 tag 叫作 beta,这个时候用户可使用 npm i project-name@beta
来安装这个版本,这等价于 npm i project@1.0.9
使用 npm dist-tag add <package>@<version> tag
来给某个版本打 tag,默认状况下载 npm publish
的时候 npm 会给当前版本打一个 tag 叫作 latest
,表示这是最新的,可使用 npm publish --tag <tag-name>
来改变默认的 tag。