# 二.npm-run-all
前言
用来运行多个命令
- 串行(严格按照执行顺序执行)
- 并行(不相互阻塞的命令)
# 1. 背景
通常来说,前端项目会包含 js、css、less、scss、json、markdown 等格式的文件,为保障代码质量,给不同的代码添加检查是很有必要的,代码检查不仅保障代码没有低级的语法错误,还可确保代码都遵守社区的最佳实践和一致的编码风格,在团队协作中尤其有用。
- eslint (opens new window),可定制的 js 代码检查;
- stylelint (opens new window),可定制的样式文件检查,支持 css、less、scss;
- jsonlint (opens new window),json 文件语法检查,踩过坑的同学会清楚,json 文件语法错误会知道导致各种失败;
- markdownlint-cli (opens new window),Markdown 文件最佳实践检查;
需要注意的是,html 代码也应该检查,但是工具支持薄弱,就略过不表。此外,为代码添加必要的单元测试也是质量保障的重要手段,常用的单测技术栈是:
- mocha (opens new window),测试用例组织,测试用例运行和结果收集的框架;
- chai (opens new window),测试断言库,必要的时候可以结合 sinon (opens new window) 使用
提示
测试工具如 tap (opens new window)、ava (opens new window) 也都提供了命令行接口,能很好的集成到 npm script 中,原理是相通的。
包含了基本的代码检查、单元测试命令的 package.json 如下:
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"lint:js": "eslint *.js",
"lint:css": "stylelint *.less",
"lint:json": "jsonlint --quiet *.json",
"lint:markdown": "markdownlint --config .markdownlint.json *.md",
"test": "mocha tests/"
},
"devDependencies": {
"chai": "^4.1.2",
"eslint": "^4.11.0",
"jsonlint": "^1.6.2",
"markdownlint-cli": "^0.5.0",
"mocha": "^4.0.1",
"stylelint": "^8.2.0",
"stylelint-config-standard": "^17.0.0"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 2. 串行
用 &&
可以把多条 npm script 按先后顺序串起来使用
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"test": "npm run lint:js && npm run lint:css && npm run lint:json && npm run lint:markdown && mocha tests"
}
}
2
3
4
5
6
7
8
9
然后直接执行 npm test
或 npm t
,从输出可以看到子命令的执行顺序是严格按照我们在 scripts 中声明的先后顺序来的:
eslint ==> stylelint ==> jsonlint ==> markdownlint ==> mocha
需要注意的是,串行执行的时候如果前序命令失败(通常进程退出码非 0),后续全部命令都会终止
# 3. 并行
把连接多条命令的 &&
符号替换成 &
即可
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"test": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests"
}
}
2
3
4
5
6
7
8
9
重新运行 npm t,我们得到如下结果:
细心的同学可能已经发现上图中哪里不对,npm run lint:js 的结果在进程退出之后才输出,如果你自己运行,不一定能稳定复现这个问题,但 npm 内置支持的多条命令并行跟 js 里面同时发起多个异步请求非常类似,它只负责触发多条命令,而不管结果的收集,如果并行的命令执行时间差异非常大,上面的问题就会稳定复现。怎么解决这个问题呢?
答案也很简单,在命令的增加 & wait
即可,这样我们的 test 命令长这样:
npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/ & wait
加上 wait 的额外好处是,如果我们在任何子命令中启动了长时间运行的进程,比如启用了 mocha 的 --watch
配置,可以使用 ctrl + c
来结束进程,如果没加的话,你就没办法直接结束启动到后台的进程。
# 4. npm-run-all
使用 npm-run-all
实现更轻量和简洁的多命令运行。
用如下命令将 npm-run-all
添加到项目依赖中:
npm i npm-run-all -D
--parallel: 并行运行多个命令,例如:npm-run-all --parallel lint build
--serial: 多个命令按排列顺序执行,例如:npm-run-all --serial clean lint build:**
--continue-on-error: 是否忽略错误,添加此参数 npm-run-all 会自动退出出错的命令,继续运行正常的
--race: 添加此参数之后,只要有一个命令运行出错,那么 npm-run-all 就会结束掉全部的命令
这个包提供三个命令,分别是 npm-run-all run-s run-p,其中后两个都是 npm-run-all 带参数的简写,分别对应串行和并行
然后修改 package.json 实现多命令的串行执行:
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
// "test": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/ & wait",
"mocha": "mocha tests/",
"test": "npm-run-all lint:js lint:css lint:json lint:markdown mocha"
}
}
2
3
4
5
6
7
8
9
10
11
npm-run-all 还支持通配符匹配分组的 npm script,上面的脚本可以进一步简化成:
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
// "test": "npm-run-all lint:js lint:css lint:json lint:markdown mocha",
"test": "npm-run-all lint:* mocha"
}
}
2
3
4
5
6
7
8
9
10
如何让多个 npm script 并行执行?也很简单:
// package.json
{
"name": "demo",
"version": "0.1.0",
"main": "index.js",
"scripts": {
// "test": "npm-run-all lint:js lint:css lint:json lint:markdown mocha",
"test": "npm-run-all --parallel lint:* mocha"
}
}
2
3
4
5
6
7
8
9
10
并行执行的时候,我们并不需要在后面增加 & wait
,因为 npm-run-all 已经帮我们做了。