前言
不得不说前端的生态还是非常旺盛的,翻看各种开源前端项目的时候总是能找到些惊喜,安装大型项目时附带的一堆不明所以的库当中往往也会有宝藏级别的存在。凡事先不要想着自己造轮子,多翻翻 npm 绝对好处多多。
最近发现了 mysticatea/npm-run-all 这个神器,这个工具是为了解决官方的 npm run
命令无法同时运行多个脚本的问题,它可以把诸如 npm run clean && npm run build:css && npm run build:js && npm run build:html
的一长串的命令通过 glob 语法简化成 npm-run-all clean build:*
这样精致小巧的模样。再者大家也知道 shell 的 &
语法实际上是不支持 cmd 的,为了跨平台也最好使用这样的第三方库来提供支持。preact 中就是用来对数量繁多的子模块进行并行构建和顺序测试。下面的内容大部分来官方的文档,这里就用自己的说法简单翻译了一下。
安装
$ npm install npm-run-all --save-dev
# 或者
$ yarn add npm-run-all --dev
使用方法
这个包提供三个命令,分别是 npm-run-all
run-s
run-p
,其中后两个都是 npm-run-all
带参数的简写,分别对应串行和并行。
顺序执行
$ npm-run-all clean lint build
依次执行三个任务,注意如果某个脚本退出时返回值为空值,那么后续脚本默认是不会执行的,你可以使用参数 --continue-on-error
来规避这种行为。
并行执行
$ npm-run-all --parallel lint build
同时执行这两个任务,需要注意如果脚本退出时返回空值,所有其它子进程都会被 SIGTERM
信号中断,同样可以用 --continue-on-error
参数禁用行为。
混合执行
$ npm-run-all clean lint --parallel watch:html watch:js
这段命令首先按顺序执行 clean
lint
两个脚本,然后同时执行 watch:html
和 watch:js
的任务。
$ npm-run-all a b --parallel c d --sequential e f --parallel g h i
# or
$ npm-run-all a b --parallel c d --serial e f --parallel g h i
这段命令通过以下顺序执行:
- 顺序运行
a
和b
; - 然后同时运行
c
和d
; - 再依次运行
e
和f
; - 最后同时执行
g
,h
,i
。
Glob-like 名称匹配
你可以使用 Glob 通配符来匹配任务名称,方便指定多个名称相似的任务,和标准语法不同的是分隔符由 /
改为 :
以适应需要。
$ npm-run-all --parallel watch:*
👆 不匹配分隔符,同时运行 watch:html
watch:js
但不运行 watch:js:index
。
$ npm-run-all --parallel watch:**
👆 匹配分隔符,所有以 watch:
开头的脚本都会被运行。
附带运行参数
在脚本名称后使用双引号包裹来提供参数,甚至还支持用占位符,延迟到运行命令时再提供参数。
$ npm-run-all build "start-server -- --port {1}" -- 8080
上例是占位符的工作方式,实际使用时可以这样编写 package.json
:
{
"scripts": {
"start": "npm-run-all build \"start-server -- --port {1}\" --"
}
}
运行命令时只需:
$ npm run start 8080
> example@0.0.0 start /path/to/package.json
> npm-run-all build "start-server -- --port {1}" -- "8080"
可用的占位符包括:
{1}
,{2}
, ...- 指定序号的单个参数
{@}
- All arguments
{*}
- All arguments as combined
这里的语法类似 shell,后两种不太懂区别,有了解的老哥可以留言指点下。
Node API
这个库还提供了面向 Node 的模块接口,示例如下,具体请参考官方文档。
const runAll = require("npm-run-all");
runAll(["clean", "lint", "build:*"], {parallel: false})
.then(() => {
console.log("done!");
})
.catch(err => {
console.log("failed!");
});
runAll(["build:* -- --watch"], {parallel: true})
.then(() => {
console.log("done!");
})
.catch(err => {
console.log("failed!");
});