npm使用不完全乱指

配置

1
2
3
4
5
6
7
8
9
10
11
12
// 配置列表
npm config list
// 获取指定配置
npm config get key
// eg
npm config get registry
// 指定配置
npm config set key=value
// eg
npm config set registry=https://registry.npm.taobao.org
// 删除指定配置
npm config delete key

NPM依赖包版本号~和^和*的区别

~ 会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0
^ 会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0
* 这意味着安装最新版本的依赖包

推荐使用~,只会修复版本的bug,比较稳定
使用^或者* ,更新后会有可能导致项目不稳定,

锁定依赖

可以将需要安装的模块版本前缀默认设置成波浪号(~):

1
npm config set save-prefix="~"

对于那些偏执的认为任何更新(模块的行为)会破坏系统的人,可以配置npm仅安装精确版本号的模块:

1
npm config set save-exact true

定义默认的npm init

使用 npm init 初始化一个新的项目,这个过程会提示输入很多项目的配置,并创建一个 package.json 文件。

如果不想每次开始一个新的项目都需要重新输入同样的信息,可以使用 -y 标记表示你能接受 package.json 文件的一堆默认值:

1
npm init -y

也可以通过config设置一些的默认值:

1
2
npm config set init.author.name <name>
npm config set init.author.email <email>

安装及升级包

1
2
3
4
5
6
7
8
// 只安装package.json配置中的dependencies包: 
npm install --product
// 查看可升级的包
npm outdated
// 查看全局可升级的包
npm -g outdated
// 升级包
npm update [package]

也可以使用npm-check来检查npm依赖包是否有更新,错误以及不在使用的,也可以使用npm-check进行包的更新。

查看指定包的信息

1
2
3
4
5
npm [show|view|info|v] <package name>
// 所有版本信息
npm info <package name> versions
// 最新稳定版信息
npm info <package name> versions

查看安装包版本

1
2
3
4
5
6
// 本地包
npm [list|ls|la|ll] <packageName>
// 全局安装包
npm [list|ls|la|ll] <packageName> -g
// 通过depth限制输出的模块层级:
npm [list|ls|la|ll] -g --depth=0

运行命令

npm run 可以运行 package.jsonscript里面的脚本。

由于 npm 脚本就是 Shell 脚本,因此可以使用 Shell 通配符。*表示任意文件名,**表示任意一层子目录

1
2
"lint": "jshint *.js"
"lint": "jshint **/*.js"

如果要将通配符传入原始命令,防止被 Shell 转义,要将星号转义。

1
"test": "tap test/\*.js"

命令传参

npm 脚本传入参数,要使用--标明。

1
2
3
"lint": "jshint **.js"
// 向上面的npm run lint命令传入参数,必须写成下面这样
npm run lint -- --reporter checkstyle > checkstyle.xml

也可以在package.json里面再封装一个命令。

1
2
"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"

命令的执行顺序

如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。
如果是并行执行(即同时的平行执行),可以使用&符号。

1
npm run script1.js & npm run script2.js

如果是继发执行(即只有前一个任务成功,才执行下一个任务),可以使用&&符号。

1
npm run script1.js && npm run script2.js

这两个符号是 Bash 的功能。此外,还可以使用 node 的任务管理模块:script-runnernpm-run-allredrun

钩子

npm 脚本有prepost两个钩子。举例来说,build脚本命令的钩子就是prebuildpostbuild

1
2
3
"prebuild": "echo I run before the build script",
"build": "cross-env NODE_ENV=production webpack",
"postbuild": "echo I run after the build script"

用户执行npm run build的时候,会自动按照下面的顺序执行。

1
npm run prebuild && npm run build && npm run postbuild

可以在这两个钩子里面,完成一些准备工作和清理工作。下面是一个例子。

1
2
3
"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"

npm 默认提供下面这些钩子。

  • prepublish,postpublish
  • preinstall,postinstall
  • preuninstall,postuninstall
  • preversion,postversion
  • pretest,posttest
  • prestop,poststop
  • prestart,poststart
  • prerestart,postrestart

自定义的脚本命令也可以加上prepost钩子。比如myscript这个脚本命令,也有premyscriptpostmyscript钩子。不过,双重的prepost无效,比如prepretestpostposttest是无效的。

注意,prepublish这个钩子不仅会在npm publish命令之前运行,还会在npm install(不带任何参数)命令之前运行。这种行为很容易让用户感到困惑,所以 npm 4引入了一个新的钩子prepare,行为等同于prepublish,而从 npm 5开始,prepublish将只在npm publish命令之前运行。

npm 提供一个npm_lifecycle_event变量,返回当前正在运行的脚本名称,比如pretesttestposttest等等。所以,可以利用这个变量,在同一个脚本文件里面,为不同的npm scripts命令编写代码。请看下面的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
const TARGET = process.env.npm_lifecycle_event;

if (TARGET === 'test') {
console.log(`Running the test task!`);
}

if (TARGET === 'pretest') {
console.log(`Running the pretest task!`);
}

if (TARGET === 'posttest') {
console.log(`Running the posttest task!`);
}

简写命令

四个常用的 npm 脚本有简写形式。

  • npm startnpm run start
  • npm stopnpm run stop的简写
  • npm testnpm run test的简写
  • npm restartnpm run stop && npm run restart && npm run start的简写

npm startnpm stop都比较好理解,而npm restart是一个复合命令,实际上会执行stoprestartstart三个命令,具体的执行顺序如下。

  • prerestart
  • prestop
  • stop
  • poststop
  • restart
  • prestart
  • start
  • poststart
  • postrestart

获取package.json配置

npm 脚本有一个非常强大的功能,就是可以使用 npm 的内部变量。首先,通过npm_package_前缀,npm 脚本可以拿到package.json里面的字段。比如,下面是一个package.json

1
2
3
4
5
6
7
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}

那么,变量npm_package_name返回foo,变量npm_package_version返回1.2.5

1
2
3
// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5

上面代码中,我们通过环境变量process.env对象,拿到package.json的字段值。如果是 Bash 脚本,可以用$npm_package_name$npm_package_version取到这两个值。

npm_package_前缀也支持嵌套的package.json字段。

1
2
3
4
5
6
7
"repository": {
"type": "git",
"url": "xxx"
},
scripts: {
"view": "echo $npm_package_repository_type"
}

上面代码中,可以通过npm_package_repository_type取到repository字段的type属性。
下面是另外一个例子。

1
2
3
"scripts": {
"install": "foo.js"
}

上面代码中npm_package_scripts_install变量的值等于foo.js

获取全局配置

npm 脚本还可以通过npm_config_前缀,拿到 npm 的配置变量,即npm config get xxx命令返回的值。比如,当前模块的发行标签,可以通过npm_config_tag取到。

1
"view": "echo $npm_config_tag"

注意package.json里面的config对象,可以被环境变量覆盖。

1
2
3
4
5
{ 
"name" : "foo",
"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }
}

上面代码中,npm_package_config_port变量返回的是8080。这个值可以用下面的方法覆盖。

1
$ npm config set foo:port 80

最后,npm run env命令可以列出所有环境变量。

参考

npm scripts 使用指南

[译]10个 NPM 使用技巧