在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服务器之前等待开始监视完成。

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


当前回答

来一份老式的Makefile怎么样?

这允许您进行大量控制,包括如何管理子外壳、脚本之间的依赖关系等。


# run both scripts
start: server client

# start server and use & to background it
server:
    npm run serve &

# start the client
client:
    npm start

调用此Makefile,然后您可以键入

让一切开始。因为当您使用ctrl-C时,服务器命令实际上是在start命令的子进程中运行的,所以服务器命令也会停止,这与您自己在shell中备份不同。Make还可以完成命令行,至少在我使用的shell上是这样。另外,第一个命令将始终运行,因此您可以在这里自己键入make。

我总是在我的项目中加入一个makefile,这样我就可以在以后快速扫描每个项目的所有常用命令和参数。

其他回答

Windows CMD的简单本机方式

"start /b npm run bg-task1 && start /b npm run bg-task2 && npm run main-task"

(启动/b表示在后台启动)

我的解决方案类似于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");
})();

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

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

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

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

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

分叉怎么样

运行多个节点脚本的另一种选择是使用单个节点脚本,它可以派生许多其他脚本。在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 runningScripts= [];

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文档