如何并行运行多个npm脚本?

问题描述 投票:413回答:17

在我的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"

...但是在运行start-watch之前,等待wp-server完成。

我怎样才能并行运行这些?请记住,我需要查看这些命令的output。此外,如果您的解决方案涉及构建工具,我宁愿使用gulp而不是grunt,因为我已经在另一个项目中使用它。

javascript node.js build
17个回答
480
投票

使用名为concurrently的包。

npm i concurrently --save-dev

然后设置你的npm run dev任务:

"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""

7
投票

您可以使用一个&作为并行运行脚本

"dev": "npm run start-watch & npm run wp-server"

Refrence link


6
投票

Quick Solution

在这种情况下,我会说最好的选择 如果此脚本用于仅在基于* 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并行执行它们。您可以增强脚本以将分叉进程的pids输出到如下文件:

"serve-bundle": "npm run bundle & echo \"$!\" > build/bundle.pid && npm run serve & echo \"$!\" > build/serve.pid && npm run open-browser",

Google就像bash控制运算符一样,可以分析它如何运作。我还提供了一些关于在以下Node项目中利用Unix技术的进一步背景:

Further Context RE: Unix Tools & Node.js

如果您不在Windows上,Unix工具/技术通常可以很好地实现Node脚本,因为:

  1. 很多Node.js都非常喜欢Unix原理
  2. 您正在使用* nix(包括OS X),NPM正在使用shell

Nodeland中用于系统任务的模块通常也是Unix工具的抽象或近似,从fsstreams


6
投票
npm-run-all --parallel task1 task2

编辑:

您需要预先安装npm-run-all。另请查看this page以了解其他使用方案。


3
投票

我遇到了&|的问题,分别退出状态和错误抛出。

其他解决方案想要运行具有给定名称的任何任务,例如npm-run-all,这不是我的用例。

所以我创建了npm-run-parallel,它以异步方式运行npm脚本,并在完成后报告。

所以,对于你的脚本,它是:

npm-run-parallel wp-server start-watch


3
投票

How about forking

运行多个Node脚本的另一个选择是使用单个Node脚本,这可以使fork更多其他脚本。在Node中本地支持分叉,因此它不添加依赖项并且是跨平台的。


Minimal example

这将按原样运行脚本并假设它们位于父脚本的目录中。

// 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));

Verbose example

这将使用参数运行脚本,并由许多可用选项配置。

// 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
});

Communicating with forked scripts

分叉还有一个额外的好处,即父脚本可以从分叉子进程接收事件以及发回。一个常见的例子是父脚本杀死它的分叉子节点。

 runningScripts.forEach(runningScript => runningScript.kill());

有关更多可用事件和方法,请参阅ChildProcess documentation


1
投票

我一直在使用npm-run-all一段时间,但我从来没有相处,因为在监视模式下命令的输出不能很好地协同工作。例如,如果我在监视模式下启动create-react-appjest,我将只能看到我运行的最后一个命令的输出。所以大多数时候,我手动运行所有命令......

这就是为什么,我实现自己的lib,run-screen。它仍然是非常年轻的项目(从昨天开始:p)但看起来可能更糟糕,在你的情况下它会是:

run-screen "npm run start-watch" "npm run wp-server"

然后按数字键1查看wp-server的输出并按0查看start-watch的输出。


0
投票

在我的情况下,我有两个项目,一个是UI,另一个是API,两个都在各自的package.json文件中有自己的脚本。

所以,这就是我所做的。

npm run --prefix react start&  npm run --prefix express start&

0
投票

简单的节点脚本,让您无需太多麻烦。使用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);
});

301
投票

使用Concurrently包工作,但您不需要它来完成此任务。您可以在基于UNIX的计算机上使用管道来运行并发任务。我建议使用这种方法,因为它可以使您不必添加额外的依赖项。

"dev": "npm run start-watch > /dev/null | npm run wp-server"

注意:第一个命令将忽略其输出


93
投票

如果您使用的是类UNIX环境,只需使用&作为分隔符:

"dev": "npm run start-watch & npm run wp-server"

否则,如果您对跨平台解决方案感兴趣,可以使用npm-run-all模块:

"dev": "npm-run-all --parallel start-watch wp-server"

60
投票

从windows cmd你可以使用start

"dev": "start npm run start-watch && start npm run wp-server"

以这种方式启动的每个命令都在自己的窗口中启动


48
投票

你应该使用npm-run-all(或concurrentlyparallelshell),因为它可以更好地控制启动和查杀命令。运营商&|是糟糕的想法,因为你需要在所有测试完成后手动停止它。

这是通过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驱动程序。


17
投票

更好的解决方案是使用&

"dev": "npm run start-watch & npm run wp-server"

11
投票

如果用单个&符号替换双和号,则脚本将同时运行。


10
投票

我已经检查了几乎所有上面的解决方案,只有npm-run-all我才能解决所有问题。与所有其他解决方案相比的主要优势是run script with arguments的能力。

{
  "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-pnpm-run-all --paraller的捷径

这允许我使用像npm run test:watch -- Something这样的参数运行命令。

编辑:

option还有一个有用的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时终止所有进程。当您运行HTTP服务器和使用该服务器的另一个脚本时,这尤其有用。

  "test": "run-p -r test:static-server \"test:jest -- {*}\" --",

10
投票

我有一个没有任何附加模块的跨平台解决方案。我正在寻找类似try catch块的东西,我可以在cmd.exe和bash中使用它们。

解决方案是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)将适用于所有平台!


推荐问答