npm 支持众多 CLI 命令,除了 install 最常用的就是 npm run command
,npm run 是 npm run-script 的简写,其执行的命令定义来自于 npm scripts
什么是 npm scripts
npm package 通过 package.json 的 main
字段描述 package 入口,在 package 开发过程中经常有需要和 CLI 交互的工作,比如执行 eslint、运行单元测试、生成测试报告、开启 debug 模式等
npm 允许通过 package.json 的 scripts
字段描述这些 CLI 命令,然后通过 npm run command
运行。egg.js 使用脚手架初始化代码会内置如下 scripts
"scripts": {
"start": "egg-scripts start --daemon --title=egg-server-demo",
"stop": "egg-scripts stop --title=egg-server-demo",
"dev": "egg-bin dev",
"debug": "egg-bin debug",
"test": "npm run lint -- --fix && npm run test-local",
"test-local": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
"ci": "npm run lint && npm run cov",
"autod": "autod"
},
如果想开启 egg.js 本地联调,在命令行执行 npm run dev
即可,执行单元测试可以通过 npm run test
实现,这样方便 package 使用者处理各种不同任务
工作原理
在运行 npm run command
时 npm 会在当前路径的 package.json>scripts 下搜索 command,匹配到后新建一个 shell,在 shell 内执行 command 配置的命令内容,windows 操作系统会使用 cmd.exe
这样 npm scripts 可以不拘泥于 node 或 js脚本,任何 shell 可执行的内容都可以自定义在 npm scripts 中,如果机器中安装了 python也可以被 scripts 内容定义为 python PATH.py
如果希望运行的脚本接收参数,格式和 shell 要求一致,使用 --key=value
格式
"start": "egg-scripts start --daemon --title=egg-server-demo"
环境变量
npm scripts 执行前会设置一些可能用到的环境变量,通过 npm run env
命令可以查看这些环境变量,比较常用的有
package.json 信息
package.json 中的所有字段都会用 npm_package_字段名
格式设置到环境变量,可以通过 npm_package_version
访问到 package 的 version 信息,如果 scripts 使用 node 脚本
package.json
"scripts": {
"test": "node test.js"
},
test.js
const assert = require('assert');
const version = process.env.npm_package_version;
assert(version, '1.0.0');
npm config 信息
类似的 npm 相关的所有配置也会被设置到 npm_config_
开头的环境变量里
PATH 添加 node_modules/.bin
npm scripts 执行前会把当前目录的 node_modules/.bin
目录加入到环境变量 PATH 中,执行完成后恢复,这样该目录下的所有脚本都可以不写路径直接使用
为什么要刻意添加 node_modules/.bin
目录?
很多工具型 package 写出来就是为了服务于其它 package 的开发,这些 package 会通过 .bin
目录暴露出其可执行文件,比如自动化测试工具 jest,如果没有把 .bin 目录加入到环境变量,其它 package 在 npm scripts 中使用 jest 需要
"scripts": {
"test": "jest"
}
.bin 目录加入到 PATH 中后可以写成
"scripts": {
"test": "jest"
}
package 生成 .bin 目录方式 https://docs.npmjs.com/files/package.json#bin jest package.json > https://github.com/facebook/jest/blob/master/packages/jest/package.json
{
"name": "jest",
"version": "26.2.2",
"main": "build/jest.js",
"dependencies": {
"@jest/core": "^26.2.2",
"import-local": "^3.0.2",
"jest-cli": "^26.2.2"
},
"bin": "./bin/jest.js"
}
pre、post 钩子
当使用命令
npm run xxx
时,npm 会尝试执行 package.jsonscripts
中配置的 xxx 脚本命令,但 npm 同样会尝试在 package.jsonscripts
中查找是否配置了 prexxx,postxxx 脚本命令。如果都配置了,npm 会按照以下顺序执行脚本
- npm run prexxx
- npm run xxx
- npm run postxxx
npm 提供一个 npm_lifecycle_event
变量,返回当前正在运行的脚本名称,可以利用这个变量,使用同一个脚本为不同的启动方式做差异化的处理
简写
npm run 是 npm run-script 简写,有几个命令因为过于常用,npm 提供了进一步简写
- 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 scripts 后就可以写自己的命令行工具了