前言
本文总结了工作中常用到的以及一些不常用容易忽略的npm知识,包括:
- npm 各种基本命令及作用
- package.json 的各字段详解
- 版本号详解
- npm3.x安装依赖包的规则
- 关于npm源的解释与设置
- pacak-lock.json的解释与作用
基本命令速览
描述 | 命令 |
---|---|
查看npm版本 | npm -v |
初始化项目(生成package.json) | npm init |
查看所有全局安装的包 | npm list -g |
查看包的版本号 | 查看包的所有版本(远程) npm view <Package Name> versions 查看包的最新版本 npm view <Package Name> version 查看包的版本及其他信息 npm info <Package Name> (在包文件夹下打开终端时可以直接输入npm info) |
查看当前登陆的npm账号 | npm whoami |
登陆npm | npm login 如果需要切换用户,只需要执行此命令重新登陆即可完成切换 |
注册npm | npm adduser |
安装pacakge.json中的依赖包 | npm install |
安装第三方npm包 | 全局安装install <Package Name> -g 本地安装 npm install <Package Name> 安装指定版本包 npm install <Package Name>@xx.xx.xx 安装最新版或tag版 npm install <Package Name>@latest npm install <Package Name>@beta beta为发布的tag版名称 安装并写入package.json的dependencies(生产环境依赖) npm install <Package Name> --save 安装并写入package.json的devDepencies中(开发环境依赖) npm install <Package Name> --save-dev 安装固定版本号 npm install <Package Name> --save-exact |
更新包 | 更新某个包npm update <Package Name> 更新包的同时更新package.json文件中对应包的版本信息 npm update <Package Name> --save |
删除包 | 删除全局包npm uninstall <Package Name> -g 删除包的同时删除留在package.json中dependencies下的包 npm uninstall <Package Name> --save 删除包的同时删除留在package.json中devDependencies下的包 npm uninstall <Package Name> --save-dev |
修改源 | npm config set registry https://registry.npm.taobao.org 查看源 npm config get registry |
管理包作者 | 添加包作者npm owner add <user> <Package Name> 删除包作者 npm owner rm <user> <Package Name> 查看包所有的作者 npm owner ls <Package Name> (owner或author均可) |
发包 | 在当前目录下打开终端 发布正式版 npm publish 发布tag版(tag名称随意) npm publish --tag beta |
链接其他包 当我们本地开发npm包时,一般该包的位置并不在项目目录中,为了方便开发,可以使用 npm link 将该包链接到项目中,方便开发调试。(注:尽量不要直接在项目的node_moudles中创建本地包进行开发,如果package.json中没有写依赖,很容易在更新其他包的时候造成本地包丢失,血泪的教训……😢) | npm link 1, 在本地包test包打开终端执行 npm link 将包链接到全局2,在项目根目录下执行 npm link test 将包链接到项目中 |
pacakge.json
npm init 会创建package.json文件 官方文档
- name
包的名字(必填字段),
· 名称必须少于或等于214个字符,
· 不能以'.'或者'_'开头,
· 名称中不能包含大写字母,
· 一定要简短并高度概括,
· 不能和npm其他包重名,否则发布不成功
· 名称可以带前缀,eg. @babel/cli 安装之后的目录如下:
- version
版本(必填字段)
版本号由三个数组用.隔开分别是[大版本,次要版本,修复版本]
大版本: 版本有重大升级,不向下兼容,升级需谨慎。eg. react@15.x和react@16.x、webpack@3.x和webpack@4.x
次要版本:版本有新功能,并向下兼容,可以随时更新。
修复版本:版本主要修复了bug,可以随时更新。
"latest"
: 最新版,npm i时会安装最新的大版本,绝对不要用这个,非常不安全"beta|test|alpha"
: 默认安装最新的tag版,关于发布tag的规范可以参考semver"1.0.0"
: 精准匹配版本号"^1.0.0"
: 匹配2,3级版本。eg. 可以匹配大于等于1.0.0
小于2.0.0的版本"~1.0.0"
: 匹配3级版本。eg. 可以匹配大于等于1.0.0
小于1.1.0
版本,但匹配不到1.1.0
版本"~1.2.3-beta.1"
: 匹配大于等于1.2.3-beta.1
小于1.3.0
的版本,但是需要注意的是如果是beta版,只能匹配大于等于1.2.3-beta.1
小于1.2.4-beta.1
的版本。也就是说beta版本前缀不能大于1.2.3
,正式版可以大于1.2.3
小于1.3.0
">1.0.0"
: 匹配大于该版本的。">=1.0.0"
: 匹配大于等于该版本的。"<1.0.0"
: 匹配小于该版本的。"<=1.0.0"
: 匹配小于等于该版本的。"=1.0.0"
: 匹配等于该版本的,和不加"="
的情况一样。">=1.0.0 <2.0.0"
: 匹配大于等于1.0.0
,小于2.0.0
的。"1.3.4 || >=1.0.0 <2.0.0"
: 匹配1.3.4
或大于等于1.0.0
,小于2.0.0的。"1.0.0-beta.1"
:tag版,如果不小心将tab版本执行了npm publish
发布成了正式版,这时只要执行npm dist-tag add 1.0.0-beta.1 latest
即可把该tag版转为正式版"1.2.3 - 2.3.4"
: 匹配1.2.3
到2.3.4
之间的版本, 如果只提供了一级或二级版本则匹配一级或二级最大版本。
eg.1.2.3 - 2
-->匹配大于等于1.2.3
小于3.0.0
的版本。"1.x"
: 匹配大于等于1.0.0
小于2.0.0
的版本,等同于"^"
"1.2.x"
: 匹配大于等于1.2.0
小于1.3.0
的版本,等同于"~"
"*"
: 匹配任何版本""
: 匹配任何版本,等同于*
"1"
: 匹配大于等于1.0.0
的版本,等同于1.x
"1.2"
: 匹配大于等于1.2.0
的版本,等于1.2.x
- description|keywords
包的描述/关键词,可以通过npm search
来搜索
- main
包的入口文件,默认为index.js,
browser 环境和 node 环境均可使用
- author
包的作者
- scripts
用来定义一些脚本命令命令如:start,dev,build等
- repository
代码存放的地方type可以是svn或git
url为访问路径
"repository": {
"type" : "git",
"url" : "https://github.com/npm/cli.git"
}
- maintainers
包的所有者列表,通过npm owner add
添加的都会出现在此列表
- homepage
项目主页地址
- bugs
项目问题的提交地址
- license
包的证书,指定了使用者使用的的权限
- files
一个文件类型的数组,用来表示在当前包作为依赖包时安装并显示的目录,语法类似于.npmignore 文件,表示含义刚好相反,.npmignore 里的代表安装时要忽略的;写入flies的代表安装时不忽略的
- browser
指定该包在客户端使用
- bin
指定script字段中的命令的执行文件
eg. { "bin" : { "myapp" : "./cli.js" } }
这样在script可以简写成: script:{"start": "myapp start"}
注:确保引用的文件(cli.js)头部引入#!/usr/bin/env node
- man
man是manual的缩写,man命令用来查看帮助文档的,如Linux中的命令帮助、配置文件帮助、编程帮助等信息,我们在package.json中配置之后,那包安装之后可以通过man <Pacakge Name>
来查找到包中的帮助文档。
附上官网例子:
{
"name" : "foo" ,
"version" : "1.2.3" ,
"description" : "A packaged foo fooer for fooing foos" ,
"main" : "foo.js" ,
"man" : "./man/doc.1"
}
以上代码执行man foo
可以查找到./man/doc.1
文件内容
如果文件名不是以包名开始的,则man 命令会自动创建前缀,如下:
{
"name" : "foo" ,
"version" : "1.2.3" ,
"description" : "A packaged foo fooer for fooing foos" ,
"main" : "foo.js" ,
"man" : \[ "./man/foo.1", "./man/bar.1" \]
}
以上代码会创建man foo
和 man foo-bar
命令来查询文件
文件需要以数字结尾,或者当文件压缩时以.gz
结尾,数字代表的是文件安装在man命令的哪部分。
- directories
目前这个配置没什么用
- config
可以用config在package.json中设置一些不会变化的配置参数,详情请查看npm-config, 附上官网的例子:
{ "name" : "foo" , "config" : { "port" : "8080" } }
而server.js是这样的:
http.createServer(...).listen(process.env.npm_package_config_port)
那么用户可以通过以下方式更改行为:
npm config set foo:port 80
- dependencies
当前包的依赖包,生产环境需要打包在项目中时使用(eg. react、vue、antd等需要打包后在生产环境使用的包)。可以是具体的包,也可以是git地址或压缩包。常用的一些例如:
"dependencies": {
"prop-types": "^15.7.2",
"react": "~16.8.6",
"react-dom": "latest",
"easy-danmaku": "/Users/jamie/work/fe/cnpm/danmaku",
"xxx": "git+https://github.com/xxx/xxxx.git"~~~~
},
在我们执行npm i
时可能会遇到这样的现象,
- A包中的依赖B包为什么安装后在node_modules里A包,B包都同级了,B包并没有安装在A包的node_modules里?
- 为什么A包中依赖B包,c包也依赖B包,为什么安装后有时候C包和A包、B包同级,有时候又分别安装到各自的node_modules里了?
在解释这个问题之前,可以先查看一下自己的npm 版本号,npm -v
如果npm版本号大于3.x, 这个版本的npm采用了包管理所以会出现上面说的现象。如果版本为npm2.x,属于嵌套模式,所有包的依赖包都会分别打包在自己的node_modules中,造成嵌套过深的问题。这里我们主要说npm3.x的包管理,如果A包,B包依赖的C包版本相同,则安装后会平铺在node_modules里,如果版本不同则会分别打包到各自的node_modules里。
注:在使用过程中发现,依赖包版本号为beta时,不会扁平化安装,如果需要扁平化安装需要写版本号或latest,这就造成了另一个版本冲突的问题,这时使用peerDependency更合适,下文会详细说明
- devDependencies
开发环境需要使用的工具类依赖包(eg. babel、webpack、eslint、typescript等需要在开发中用到的打包,编译,检测等工具包)。
- peerDependencies
提示安装时需要将peerDependencies中的依赖作为项目依赖安装。 在npm3.x后,如果包的依赖为peerDependencies,则会在安装过程中提示需要手动安装peerDependencies的依赖。作用是防止项目已经依赖了C包,安装的A包中也依赖了C包。两处的C包因版本不一致而导致的问题。
- optionalDependencies
可选依赖包,用来放一些不阻断项目正常运行的插件包,即使这些包安装失败也不会阻塞npm的继续执行。需要注意的是optionalDependencies里的包会覆盖dependencies里的
- bundledDependencies
捆绑组件包,打包后会将依赖包一并打包进去,安装时只需安装一个包即可,需要注意的是bundledDependencies中的依赖包需要先在dependencies或devDependencies中定义,在执行npm pack
的时候才会打包进去
- publishConfig
发包时设置该包发布的仓库地址,一般公司有内部私有仓库时,这里设置为该仓库地址。
"publishConfig": {
"registry": "http://xxx/xxxx/repository/cnpm/"
}
我们公司也有内部仓库但是发包是并不需要设置publishConfig,而是所有包都是在一个作用域下,例如:@babel/core
的形式
publishConfig
决定发包到哪,.npmrc
决定从哪安装。 关于.npmrc
的详细解释与用法请看下文。
- engines
指定包的运行引擎。
eg.
{ "engines" : { "node" : ">=0.10.3 <0.12" } }
// or
{ "engines" : { "npm" : "~1.0.20" } }
指定该包只能在node版本大于等于0.10.3小于0.12或npm版本大于等于1.0.20小于1.1.0的版本上运行)
- os
指定包运行的操作系统。
eg.
{"os" : [ "darwin", "linux" ]}
或者指定不能在某些操作系统运行
{"os" : [ "!win32" ]}
- cpu
指定包运行的cpu
eg.
{"cpu" : [ "x64", "ia32" ]}
或则指定不能在某些cpu运行,类似os
- private
如果设置为true,npm publish时会无法发布,这是为了防止将不能发布的包误发布,没什么用处
package.json中还可以添加一些非官方的工具类配置。
eg. 当我们查看antd的package.json时会发现有一些并不是官方文档里的,有一篇文章总结的很不错,点击这里看非官方配置
npm 其他知识点
npm源
说到npm源就需要介绍一下.npmrc文件,文件主要是用来设置npm源的,npm默认都是指向https://registry.npmjs.org/
但是为了提升安装速度,需要设置源为https://registry.npm.taobao.org/
但是当我们依赖包里又有npm包,又有公司私有仓库包时,需要将某些包的npm源指向公司私有仓库地址。拿我们公司举例,假设我们的npm包作用域为@test
我需要将@test
下的包的源指到公司仓库地址,这样我执行npm i时可以同时安装npm上和公司内部的包
npm config set @test:registry http://registry.xxxx.xxx.com
npm config set其实是在.npmrc
中设置了源,如果想直接打开文件设置,可以执行npm config ls -l
找到.npmrc
文件的位置进行
或者在终端直接执行npm config edit
进行编辑
推荐一个好用的随时切换npm源的工具nrm
package-lock.json
我们经常会发现在执行npm i
时会默认在根目录生成package-lock.json文件,打开查看会发现都是我们一些依赖包的相关信息
package-lock.json是用来锁定版本的,也就是说每次安装都会默认安装package-lock.json中的版本,如果多人开发,可以保证版本一致。
注:如果手动修改了package.json中的版本号,直接执行npm i
后发现安装的并不是package.json中的版本号,这时需要删除package-lock.json文件再安装,或直接安装某个特定包
Reference
npm官方文档:
https://docs.npmjs.com/cli-documentation/
https://docs.npmjs.com/files/package.json.html
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。