4

前言

本文总结了工作中常用到的以及一些不常用容易忽略的npm知识,包括:

  1. npm 各种基本命令及作用
  2. package.json 的各字段详解
  3. 版本号详解
  4. npm3.x安装依赖包的规则
  5. 关于npm源的解释与设置
  6. 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
登陆npmnpm login
如果需要切换用户,只需要执行此命令重新登陆即可完成切换
注册npmnpm 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 安装之后的目录如下:image.png

  • version

版本(必填字段)
版本号由三个数组用.隔开分别是[大版本,次要版本,修复版本]
大版本: 版本有重大升级,不向下兼容,升级需谨慎。eg. react@15.x和react@16.x、webpack@3.x和webpack@4.x
次要版本:版本有新功能,并向下兼容,可以随时更新。
修复版本:版本主要修复了bug,可以随时更新。

  1. "latest": 最新版,npm i时会安装最新的大版本,绝对不要用这个,非常不安全
  2. "beta|test|alpha": 默认安装最新的tag版,关于发布tag的规范可以参考semver
  3. "1.0.0": 精准匹配版本号
  4. "^1.0.0": 匹配2,3级版本。eg. 可以匹配大于等于1.0.0小于2.0.0的版本
  5. "~1.0.0": 匹配3级版本。eg. 可以匹配大于等于1.0.0小于1.1.0版本,但匹配不到1.1.0版本
  6. "~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
  7. ">1.0.0": 匹配大于该版本的。
  8. ">=1.0.0": 匹配大于等于该版本的。
  9. "<1.0.0": 匹配小于该版本的。
  10. "<=1.0.0": 匹配小于等于该版本的。
  11. "=1.0.0": 匹配等于该版本的,和不加"="的情况一样。
  12. ">=1.0.0 <2.0.0": 匹配大于等于1.0.0,小于2.0.0的。
  13. "1.3.4 || >=1.0.0 <2.0.0": 匹配1.3.4或大于等于1.0.0,小于2.0.0的。
  14. "1.0.0-beta.1":tag版,如果不小心将tab版本执行了npm publish 发布成了正式版,这时只要执行 npm dist-tag add 1.0.0-beta.1 latest即可把该tag版转为正式版
  15. "1.2.3 - 2.3.4": 匹配1.2.32.3.4之间的版本, 如果只提供了一级或二级版本则匹配一级或二级最大版本。
    eg. 1.2.3 - 2 -->匹配大于等于1.2.3小于3.0.0的版本。
  16. "1.x": 匹配大于等于1.0.0小于2.0.0的版本,等同于"^"
  17. "1.2.x": 匹配大于等于1.2.0小于1.3.0的版本,等同于"~"
  18. "*": 匹配任何版本
  19. "": 匹配任何版本,等同于*
  20. "1": 匹配大于等于1.0.0的版本,等同于1.x
  21. "1.2": 匹配大于等于1.2.0的版本,等于1.2.x


  • description|keywords

包的描述/关键词,可以通过npm search来搜索

  • main

包的入口文件,默认为index.js,
browser 环境和 node 环境均可使用

  • author

包的作者

  • scripts

用来定义一些脚本命令命令如:start,dev,build等image.png

  • 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 fooman 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时可能会遇到这样的现象,

  1. A包中的依赖B包为什么安装后在node_modules里A包,B包都同级了,B包并没有安装在A包的node_modules里?
  2. 为什么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时会发现有一些并不是官方文档里的,有一篇文章总结的很不错,点击这里看非官方配置
image.png

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文件的位置进行
image.png
或者在终端直接执行npm config edit进行编辑
推荐一个好用的随时切换npm源的工具nrm

package-lock.json

我们经常会发现在执行npm i时会默认在根目录生成package-lock.json文件,打开查看会发现都是我们一些依赖包的相关信息
image.png
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


Jamie
13 声望1 粉丝

逆水行舟,不进则退