[javascript] How can I run multiple npm scripts in parallel?

In my package.json I have these two scripts:

  "scripts": {
    "start-watch": "nodemon run-babel index.js",
    "wp-server": "webpack-dev-server",
  }

I have to run these 2 scripts in parallel everytime I start developing in Node.js. The first thing I thought of was adding a third script like this:

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

... but that will wait for start-watch to finish before running wp-server.

How can I run these in parallel? Please keep in mind that I need to see the output of these commands. Also, if your solution involves a build tool, I'd rather use gulp instead of grunt because I already use it in another project.

This question is related to javascript node.js build

The answer is


In my case I have two projects, one was UI and the other was API, and both have their own script in their respective package.json files.

So, here is what I did.

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

npm-run-all --parallel task1 task2

edit:

You need to have npm-run-all installed beforehand. Also check this page for other usage scenarios.


Simple node script to get you going without too much hassle. Using readline to combine outputs so the lines don't get mangled.

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

I've checked almost all solutions from above and only with npm-run-all I was able to solve all problems. Main advantage over all other solution is an ability to 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",
}

Note run-p is shortcut for npm-run-all --parallel

This allows me to run command with arguments like npm run test:watch -- Something.

EDIT:

There is one more useful option for 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.

Add -r to your npm-run-all script to kill all processes when one finished with code 0. This is especially useful when you run a HTTP server and another script that use the server.

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

... but that will wait for start-watch to finish before running wp-server.

For that to work, you will have to use start on your command. Others have already illustrated but this is how it will work, your code below:

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

Should be :

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

What this will do is, it will open a separate instance for each command and process them concurrently, which shouldn't be an issue as far as your initial issue is concerned. Why do I say so? It's because these instances both open automatically while you run only 1 statement, which is your initial goal.


I have been using npm-run-all for some time, but I never got along with it, because the output of the command in watch mode doesn't work well together. For example, if I start create-react-app and jest in watch mode, I will only be able to see the output from the last command I ran. So most of the time, I was running all my commands manually...

This is why, I implement my own lib, run-screen. It still very young project (from yesterday :p ) but it might be worth to look at it, in your case it would be:

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

Then you press the numeric key 1 to see the output of wp-server and press 0 to see the output of start-watch.


You should use npm-run-all (or concurrently, parallelshell), because it has more control over starting and killing commands. The operators &, | are bad ideas because you'll need to manually stop it after all tests are finished.

This is an example for protractor testing through 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 = Run commands in parallel.

-r = Kill all commands when one of them finishes with an exit code of zero.

Running npm run test will start Selenium driver, start http server (to serve you files) and run protractor tests. Once all tests are finished, it will close the http server and the selenium driver.


You can use one & for parallel run script

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

Reference link


In a package.json in the parent folder:

"dev": "(cd api && start npm run start) & (cd ../client && start npm run start)"

this work in windows


My solution is similar to Piittis', though I had some problems using Windows. So I had to validate for 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");
})();

I ran into problems with & and |, which exit statuses and error throwing, respectively.

Other solutions want to run any task with a given name, like npm-run-all, which wasn't my use case.

So I created npm-run-parallel that runs npm scripts asynchronously and reports back when they're done.

So, for your scripts, it'd be:

npm-run-parallel wp-server start-watch


If you replace the double ampersand with a single ampersand, the scripts will run concurrently.


If you're using an UNIX-like environment, just use & as the separator:

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

Otherwise if you're interested on a cross-platform solution, you could use npm-run-all module:

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

I have a crossplatform solution without any additional modules. I was looking for something like a try catch block I could use both in the cmd.exe and in the bash.

The solution is command1 || command2 which seems to work in both enviroments same. So the solution for the OP is:

"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"
}

Then simple npm start (and npm run dev) will work on all platforms!


Quick Solution

In this case, I'd say the best bet If this script is for a private module intended to run only on *nix-based machines, you can use the control operator for forking processes, which looks like this: &

An example of doing this in a partial package.json file:

{
  "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 &"
  }

You'd then execute them both in parallel via npm run serve-bundle. You can enhance the scripts to output the pids of the forked process to a file like so:

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

Google something like bash control operator for forking to learn more on how it works. I've also provided some further context regarding leveraging Unix techniques in Node projects below:

Further Context RE: Unix Tools & Node.js

If you're not on Windows, Unix tools/techniques often work well to achieve something with Node scripts because:

  1. Much of Node.js lovingly imitates Unix principles
  2. You're on *nix (incl. OS X) and NPM is using a shell anyway

Modules for system tasks in Nodeland are also often abstractions or approximations of Unix tools, from fs to streams.


npm install npm-run-all --save-dev

package.json:

"scripts": {
  "start-watch": "...",
  "wp-server": "...",
  "dev": "npm-run-all --parallel start-watch wp-server"
}

More info: https://github.com/mysticatea/npm-run-all/blob/master/docs/npm-run-all.md


Just add this npm script to the package.json file in the root folder.

{
  ...
  "scripts": {
    ...
    "start": "react-scripts start", // or whatever else depends on your project
    "dev": "(cd server && npm run start) & (cd ../client && npm run start)"
  }
}

From windows cmd you can use start:

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

Every command launched this way starts in its own window.


This worked for me

{
"start-express": "tsc && nodemon dist/server/server.js",
"start-react": "react-scripts start",
"start-both": "npm -p -r run start-react && -p -r npm run start-express"
}

Both client and server are written in typescript.

The React app is created with create-react-app with the typescript template and is in the default src directory.

Express is in the server directory and the entry file is server.js

typescript code and transpiled into js and is put in the dist directory .

checkout my project for more info: https://github.com/nickjohngray/staticbackeditor

UPDATE: calling npm run dev, to start things off

{"server": "tsc-watch --onSuccess \"node ./dist/server/index.js\"",
"start-server-dev": "npm run build-server-dev && node src/server/index.js",
"client": "webpack-dev-server --mode development --devtool inline-source-map --hot",
"dev": "concurrently \"npm run build-server-dev\"  \"npm run server\" \"npm run client\""}

How about forking

Another option to run multiple Node scripts is with a single Node script, which can fork many others. Forking is supported natively in Node, so it adds no dependencies and is cross-platform.


Minimal example

This would just run the scripts as-is and assume they're located in the parent script's directory.

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

This would run the scripts with arguments and configured by the many available options.

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

Communicating with forked scripts

Forking also has the added benefit that the parent script can receive events from the forked child processes as well as send back. A common example is for the parent script to kill its forked children.

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

For more available events and methods see the ChildProcess documentation


A better solution is to use &

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

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to build

error: This is probably not a problem with npm. There is likely additional logging output above Module not found: Error: Can't resolve 'core-js/es6' WARNING in budgets, maximum exceeded for initial How can I change the app display name build with Flutter? Error - Android resource linking failed (AAPT2 27.0.3 Daemon #0) Still getting warning : Configuration 'compile' is obsolete and has been replaced with 'implementation' Could not find com.android.tools.build:gradle:3.0.0-alpha1 in circle ci Error:Execution failed for task ':app:compileDebugKotlin'. > Compilation error. See log for more details Component is part of the declaration of 2 modules Maven build Compilation error : Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project Maven