本文来自参考文章,仅做学习记录,方便查找。
npm 常用命令
npm start //初始化工程
npm run // run scripts
npm install // 安装依赖
npm update // 升级依赖
npm bin // 查看bin文件目录
npm link // 将工程软链接到全局
npm publish // 发布包
npm deprecate // 废弃包
npm help 可以查看所有命令
什么是 npm 脚本
npm 允许在package.json文件里面,使用scripts字段定义脚本命令。
{
// ...
"scripts": {
"build": "node build.js"
}
}
上面代码是package.json文件的一个片段,里面的scripts字段是一个对象。它的每一个属性,对应一段脚本。比如,build命令对应的脚本是node build.js。
命令行下使用npm run命令,就可以执行这段脚本。
npm run build 等同于执行node build.js
这些定义在package.json里面的脚本,就称为 npm 脚本。
查看当前项目的所有 npm 脚本命令,可以使用不带任何参数的npm run
命令
原理
每当执行npm run
,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。
比较特别的是,npm run
新建的这个 Shell,会将当前目录的node_modules/.bin
子目录加入PATH
变量,执行结束后,再将PATH
变量恢复原样。
这意味着,当前目录的node_modules/.bin
子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有 Mocha,只要直接写mocha test
就可以了
"test": "mocha test"
而不用写成
"test": "./node_modules/.bin/mocha test"
由于 npm 脚本的唯一要求就是可以在 Shell 执行,因此它不一定是 Node 脚本,任何可执行文件都可以写在里面。
npm 脚本的退出码,也遵守 Shell 脚本规则。如果退出码不是0
,npm 就认为这个脚本执行失败。
通配符
由于 npm 脚本就是 Shell 脚本,因为可以使用 Shell 通配符。
"lint": "jshint *.js"
"lint": "jshint **/*.js"
上面代码中,*
表示任意文件名,**
表示任意一层子目录。
如果要将通配符传入原始命令,防止被 Shell 转义,要将星号转义
"test": "tap test/\*.js"
传参
向 npm 脚本传入参数,要使用--
标明。
npm run lint -- --reporter checkstyle > checkstyle.xml
也可以在package.json
里面再封装一个命令。
"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"
执行顺序
如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。
如果是并行执行(即同时的平行执行),可以使用&
符号。
npm run script1.js & npm run script2.js
如果是继发执行(即只有前一个任务成功,才执行下一个任务),可以使用&&
符号。
npm run script1.js && npm run script2.js
这两个符号是 Bash 的功能。
钩子
npm 脚本有pre
和post
两个钩子。举例来说,build
脚本命令的钩子就是prebuild
和postbuild
。
"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
的时候,会自动按照下面的顺序执行。
npm run prebuild && npm run build && npm run postbuild
因此,可以在这两个钩子里面,完成一些准备工作和清理工作。下面是一个例子。
"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
自定义的脚本命令也可以加上pre
和post
钩子。比如,myscript
这个脚本命令,也有premyscript
和postmyscript
钩子。不过,双重的pre
和post
无效,比如prepretest
和postposttest
是无效的。
npm 提供一个npm_lifecycle_event
变量,返回当前正在运行的脚本名称,比如pretest
、test
、posttest
等等。所以,可以利用这个变量,在同一个脚本文件里面,为不同的npm scripts
命令编写代码。请看下面的例子。
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!`);
}
注意,prepublish
这个钩子不仅会在npm publish
命令之前运行,还会在npm install
(不带任何参数)命令之前运行。这种行为很容易让用户感到困惑,所以 npm 4 引入了一个新的钩子prepare
,行为等同于prepublish
,而从 npm 5 开始,prepublish
将只在npm publish
命令之前运行。
简写形式
npm start
是npm run start
npm stop
是npm run stop
的简写npm test
是npm run test
的简写npm restart
是npm run stop && npm run restart && npm run start
的简写
npm restart
是一个复合命令,实际上会执行三个脚本命令:stop
、restart
、start
。具体的执行顺序如下。
- prerestart
- prestop
- stop
- poststop
- restart
- prestart
- start
- poststart
- postrestart
使用 npm 的内部变量
通过npm_package_
前缀,npm 脚本可以拿到package.json
里面的字段。比如,下面是一个package.json
。
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}
那么,变量npm_package_name
返回foo
,变量npm_package_version
返回1.2.5
。
// 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
字段。
"repository": {
"type": "git",
"url": "xxx"
},
scripts: {
"view": "echo $npm_package_repository_type"
}
上面代码中,repository
字段的type
属性,可以通过npm_package_repository_type
取到。