如何并行运行多个npm脚本?
在我的package.json
我有以下两个脚本:
"scripts": {
"start-watch": "nodemon run-babel index.js",
"wp-server": "webpack-dev-server",
}
每当我开始在Node.js中开发时,我必须并行运行这两个脚本。 我想到的第一件事是添加第三个脚本,如下所示:
"dev": "npm run start-watch && npm run wp-server"
...但是在运行wp-server
之前,这将等待start-watch
完成。
如何并行运行它们? 请记住,我需要查看这些命令的output
。 另外,如果您的解决方案涉及构建工具,我宁愿使用gulp
而不是grunt
因为我已经在另一个项目中使用了它。
#1楼
使用一个并发的包。
npm i concurrently --save-dev
然后按如下所示设置您的npm run dev
任务:
"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""
#2楼
使用Concurrently包是可行的,但是您不需要它来完成此任务。 您可以仅在基于UNIX的计算机上使用管道运行并发任务。 我建议使用这种方法,因为它使您不必添加其他依赖项。
"dev": "npm run start-watch > /dev/null | npm run wp-server"
注意:第一个命令的输出将被忽略
#3楼
更好的解决方案是使用&
"dev": "npm run start-watch & npm run wp-server"
#4楼
快速解决方案
在这种情况下,最好的选择是:
如果此脚本用于仅在基于* nix的计算机上运行的私有模块 ,则可以使用控制运算符进行分叉,如下所示: &
在部分package.json文件中执行此操作的示例:
{
"name": "npm-scripts-forking-example",
"scripts": {
"bundle": "watchify -vd -p browserify-hmr index.js -o bundle.js",
"serve": "http-server -c 1 -a localhost",
"serve-bundle": "npm run bundle & npm run serve &"
}
然后,您可以通过npm run serve-bundle
并行执行它们。 您可以增强脚本,以将分叉进程的pid输出到文件,如下所示:
"serve-bundle": "npm run bundle & echo \"$!\" > build/bundle.pid && npm run serve & echo \"$!\" > build/serve.pid && npm run open-browser",
Google像bash控制运算符之类的东西, 用于分叉以了解其工作原理的更多信息。 我还在下面的Node项目中提供了有关利用Unix技术的更多信息:
进一步的内容RE:Unix工具和Node.js
如果您不在Windows上,则Unix工具/技术通常可以很好地使用Node脚本来实现某些目标,因为:
- 许多Node.js都在模仿Unix原则
- 您正在使用* nix(包括OS X),并且NPM仍在使用Shell
Nodeland中用于系统任务的模块通常也是从fs
到streams
的Unix工具的抽象或近似。
#5楼
如果您使用的是类似UNIX的环境,则只需使用&
作为分隔符:
"dev": "npm run start-watch & npm run wp-server"
否则,如果您对跨平台解决方案感兴趣,则可以使用npm-run-all模块:
"dev": "npm-run-all --parallel start-watch wp-server"
#6楼
我遇到了&
和|
问题|
,分别退出状态和错误抛出。
其他解决方案希望使用给定名称运行任何任务,例如npm-run-all,这不是我的用例。
因此,我创建了npm-run-parallel ,它异步运行npm脚本并在完成后报告。
因此,对于您的脚本,将是:
npm-run-parallel wp-server start-watch
#7楼
在Windows cmd中,您可以使用start
:
"dev": "start npm run start-watch && start npm run wp-server"
以这种方式启动的每个命令都在其自己的窗口中启动。
#8楼
您应该使用npm-run-all (或concurrently
, parallelshell
),因为它对启动和终止命令有更多控制。 运算符&
, |
是个坏主意,因为您需要在所有测试完成后手动将其停止。
这是通过npm进行量角器测试的示例:
scripts: {
"webdriver-start": "./node_modules/protractor/bin/webdriver-manager update && ./node_modules/protractor/bin/webdriver-manager start",
"protractor": "./node_modules/protractor/bin/protractor ./tests/protractor.conf.js",
"http-server": "./node_modules/http-server/bin/http-server -a localhost -p 8000",
"test": "npm-run-all -p -r webdriver-start http-server protractor"
}
-p
=并行运行命令。
-r
=当其中一个命令的退出代码为零时,终止所有命令。
运行npm run test
将启动Selenium驱动程序,启动http服务器(为您提供文件)并运行量角器测试。 一旦完成所有测试,它将关闭http服务器和selenium驱动程序。
#9楼
如果将双“与”号替换为单个“与”号,则脚本将同时运行。
#10楼
我已经从上面检查了几乎所有解决方案,并且只有使用npm-run-all我才能解决所有问题。 与所有其他解决方案相比,主要优点是可以运行带有参数的脚本 。
{
"test:static-server": "cross-env NODE_ENV=test node server/testsServer.js",
"test:jest": "cross-env NODE_ENV=test jest",
"test": "run-p test:static-server \"test:jest -- {*}\" --",
"test:coverage": "npm run test -- --coverage",
"test:watch": "npm run test -- --watchAll",
}
注意
run-p
是npm-run-all --paraller
快捷方式
这使我可以使用npm run test:watch -- Something
类的参数运行命令。
编辑:
npm-run-all
还有一个更有用的选项 :
-r, --race - - - - - - - Set the flag to kill all tasks when a task
finished with zero. This option is valid only
with 'parallel' option.
将-r
添加到您的npm-run-all
脚本中,以在代码0
结束时npm-run-all
所有进程。 当您运行HTTP服务器和其他使用该服务器的脚本时,此功能特别有用。
"test": "run-p -r test:static-server \"test:jest -- {*}\" --",
#11楼
我有一个没有任何其他模块的跨平台解决方案 。 我一直在寻找可以在cmd.exe和bash中同时使用的try catch块之类的东西。
解决方法是command1 || command2
command1 || command2
似乎在两个环境中都相同。 因此,OP的解决方案是:
"scripts": {
"start-watch": "nodemon run-babel index.js",
"wp-server": "webpack-dev-server",
// first command is for the cmd.exe, second one is for the bash
"dev": "(start npm run start-watch && start npm run wp-server) || (npm run start-watch & npm run wp-server)",
"start": "npm run dev"
}
然后,简单的npm start
(和npm run dev
)将在所有平台上工作!
#12楼
npm-run-all --parallel task1 task2
编辑:
您需要预先安装npm-run-all 。 另请检查此页面以了解其他使用方案。
#13楼
那分叉怎么样
运行多个Node脚本的另一种选择是使用单个Node脚本,它可以派生许多其他脚本。 Node本身支持分叉,因此它不添加任何依赖关系并且是跨平台的。
最小的例子
这只会按原样运行脚本,并假定它们位于父脚本的目录中。
// fork-minimal.js - run with: node fork-minimal.js
const childProcess = require('child_process');
let scripts = ['some-script.js', 'some-other-script.js'];
scripts.forEach(script => childProcess.fork(script));
详细的例子
这将运行带有参数的脚本,并由许多可用选项进行配置。
// fork-verbose.js - run with: node fork-verbose.js
const childProcess = require('child_process');
let scripts = [
{
path: 'some-script.js',
args: ['-some_arg', '/some_other_arg'],
options: {cwd: './', env: {NODE_ENV: 'development'}}
},
{
path: 'some-other-script.js',
args: ['-another_arg', '/yet_other_arg'],
options: {cwd: '/some/where/else', env: {NODE_ENV: 'development'}}
}
];
let processes = [];
scripts.forEach(script => {
let runningScript = childProcess.fork(script.path, script.args, script.options);
// Optionally attach event listeners to the script
runningScript.on('close', () => console.log('Time to die...'))
runningScripts.push(runningScript); // Keep a reference to the script for later use
});
与分叉脚本进行通信
分叉还具有额外的好处,即父脚本可以从分叉的子进程接收事件,也可以发送回去。 一个常见的示例是父脚本杀死其分叉的子代。
runningScripts.forEach(runningScript => runningScript.kill());
有关更多可用事件和方法,请参见ChildProcess
文档
#14楼
就我而言,我有两个项目,一个是UI ,另一个是API ,两个项目在各自的package.json
文件中都有自己的脚本。
所以,这就是我所做的。
npm run --prefix react start& npm run --prefix express start&
#15楼
我一直在使用npm-run-all一段时间,但是我一直不满意 ,因为在监视模式下命令的输出不能很好地协同工作。 例如,如果我在监视模式下启动create-react-app
和jest
,则只能看到我运行的最后一条命令的输出。 所以大多数时候,我都是手动运行所有命令...
这就是为什么我实现自己的lib 运行屏幕 。 它仍然是一个非常年轻的项目(从昨天开始:p),但是值得一看,在您的情况下,它将是:
run-screen "npm run start-watch" "npm run wp-server"
然后,按数字键1
查看wp-server
的输出,然后按0
查看start-watch
的输出。
#16楼
您可以将一个&
用于并行运行脚本
"dev": "npm run start-watch & npm run wp-server"
#17楼
简单的节点脚本,无需太多麻烦即可开始工作。 使用readline合并输出,这样行就不会混乱。
const { spawn } = require('child_process');
const readline = require('readline');
[
spawn('npm', ['run', 'start-watch']),
spawn('npm', ['run', 'wp-server'])
].forEach(child => {
readline.createInterface({
input: child.stdout
}).on('line', console.log);
readline.createInterface({
input: child.stderr,
}).on('line', console.log);
});
#18楼
我的解决方案类似于Piittis,尽管使用Windows时遇到了一些问题。 所以我必须验证win32。
const { spawn } = require("child_process");
function logData(data) {
console.info(`stdout: ${data}`);
}
function runProcess(target) {
let command = "npm";
if (process.platform === "win32") {
command = "npm.cmd"; // I shit you not
}
const myProcess = spawn(command, ["run", target]); // npm run server
myProcess.stdout.on("data", logData);
myProcess.stderr.on("data", logData);
}
(() => {
runProcess("server"); // package json script
runProcess("client");
})();
上一篇: 数据挖掘项目笔记——使用joblib中的Parallel并行运行程序
下一篇: C# 实现键值映射