882

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.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Andre Pena
  • 56,650
  • 48
  • 196
  • 243
  • 194
    `&&` will run your scripts *sequentially* while `&` will run them in **parallel**. – vsync May 30 '19 at 08:22
  • 8
    A quick way of doing it is `npm run start-watch & npm run wp-server`. This will run the first command as a background thread. This works really well when one of the commands is not long running and does not need to be manually exited later. Something like `concurrently` allows you to kill all the threads at the same time with CTRL-C. – Joshua Pinter Nov 08 '19 at 18:59
  • 5
    @vsync Does that apply to Windows? – Clonkex Feb 09 '21 at 03:31
  • @Clonkex - Yes, Windows – vsync Feb 09 '21 at 17:58
  • 5
    @vsync Are you sure? Other comments are saying that's not how it works, and it didn't work in practice for me. – Clonkex Feb 09 '21 at 23:10
  • 5
    @Clonkex, yes **BUT** it's unreliable and I use [concurrently](https://www.npmjs.com/package/concurrently) *npm package* instead, which works well, and I only use Windows – vsync Feb 11 '21 at 09:26
  • 1
    I'm not sure what everyone is talking about. & does NOT work for me either. If I have `"runtwo": "npm run alpha & npm run beta`, alpha runs, but beta definitely does not run. Not sure what everyone is smoking. I'm on Windows. – Tim Hardy Mar 09 '23 at 23:09

31 Answers31

990

Use a package called concurrently.

npm i concurrently --save-dev

Then setup your npm run dev task as so:

"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""
Soviut
  • 88,194
  • 49
  • 192
  • 260
Neil Kistner
  • 11,623
  • 2
  • 18
  • 17
  • 1
    You can also use `\`npm bin\`/concurrent`. – Patrick Burtchaell Sep 12 '15 at 17:58
  • 22
    There is also [parallelshell](https://www.npmjs.com/package/parallelshell). I actually recommend that one as `concurrently` uses multiple streams that mess with console output (colors may go weird, cursor gone) whereas `parallelshell` doesn't have [that issue](https://github.com/kimmobrunfeldt/concurrently/issues/8). – Stijn de Witt Jan 05 '16 at 21:33
  • 10
    The bugs in concurrently mentioned by @StijndeWitt have now been fixed in [2.0.0 release](https://github.com/kimmobrunfeldt/concurrently/releases/tag/2.0.0). You can use `--raw` mode to preserve colors in output. – Kimmo Feb 20 '16 at 15:21
  • @rane `"concurrent" command is deprecated, use "concurrently" instead.` – congusbongus Mar 14 '16 at 04:02
  • 41
    @StijndeWitt parallelshell has been deprecated in favor of npm-run-all https://github.com/keithamus/parallelshell#currently-not-maintained-see-consolidation-of-multiple-similar-libraries – jtzero Jun 20 '16 at 23:18
  • I'm trying to do `npm dev` but it's not recognized (like `npm start` or `npm test`). So I have to do `npm run dev`. Why is that? – olefrank Dec 25 '16 at 22:05
  • 1
    @olefrank Because custom npm scripts need to be run with the `run` or `run-script` commands. Commands like `npm test` are aliases for recommended script names, but you can run your custom script with `npm run dev`. – Nick McCurdy Jan 08 '17 at 10:25
  • `--kill-others` killed my code without reason. I just removed it and it works. – Damjan Pavlica Feb 23 '18 at 13:27
  • 36
    There has to be a better way for us to manage Javascript build/run scripts. Everything for this platform seems tacked together. quotes with escaped quotes and npm builds to call other 'npm run' builds.. This is getting pretty painful. – Andrew T Finnell Mar 21 '18 at 13:42
  • 7
    If you're running `npm run` commands, you case use a nifty shorthand and do `concurrently "npm:server" "npm:watch" "npm:electron"`. Clean and prefixes the output correctly in the stdout. Perfection. – Joshua Pinter Sep 09 '18 at 17:03
  • 2
    @AndrewTFinnell There are other solutions involving external config files such as https://github.com/pawelgalazka/tasksfile or before that grunt and gulp or you could build your own cli or use your chosen framework's cli. Tools like concurrently win because they are simple and don't obfuscate the commands that are being run - you don't have to look in another file, you don't have a large api surface layer that can contain bugs. Also by simply running `npm run` you can see exactly which commands are being run. You can also use `concurrently` programmatically... – vaughan Sep 26 '20 at 19:50
281

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"
Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138
  • 28
    I do this - from time to time when I "ctrl-c" npm, the command keeps hanging on in background... Any ideas? – Kamil Tomšík Mar 15 '16 at 13:03
  • I always thought it was `&&` but this doesn't work and I didn't know you could use `&` and I had not considered `|` all of which are subtly different.. – snakeoil Nov 16 '16 at 18:52
  • 22
    `a && b` starts `b` after `a` finished successfully, but nodemon never stops without errors, so that can't work. `a & b` starts `a`, moves it to the background and starts `b` right away. Win! `a | b` pipes the stdout of `a` to the stdin of `b` which requires both running simultaneously. Although this might seem to have the desired effect, you shouldn't use it here. – j2L4e Dec 06 '16 at 13:00
  • 25
    @KamilTomšík `&` is a really bad idea as it detaches the process. It means that `npm` will not be the parent process anymore. You'll end up with a zombie `npm run start-watch` that won't be killed with `ctrl-c`. – ngryman Dec 31 '16 at 10:25
  • 11
    Just add `wait` to mitigate problem with hanging processes: `"dev": "npm run start-watch & npm run wp-server & wait"` – Ruslan Prakapchuk Jan 25 '17 at 07:14
  • 4
    It’s not a zombie. But `&` on unix prevents the command from responding to C-c/C-z and also prevents its return code from propagating in case of a failure. – binki Aug 05 '18 at 18:22
  • 3
    Down voting this because daemonize is not the optimal way to run multiple commands. – Vicary Oct 11 '18 at 12:15
  • I'm working with Webstorm using Windows 10's default cmd and single & works fine – Benjamin Apr 09 '19 at 09:47
  • 3
    I think npm-run-all is a better solution if you are developing a public library or some situations like for example running babel watch and webpack watch simultaneously and keeping logs of both shown in the console. – Rong.l May 06 '20 at 05:16
  • Where to add this dev I am adding this in script but it still not allowing me to run two "npm-start" – HarshitMadhav Jun 07 '20 at 18:31
  • two notes: 1) should an error occur in the full command, `&` will cause the backgrounded process to become [orphaned](https://en.wikipedia.org/wiki/Orphan_process), not [zombied](https://en.wikipedia.org/wiki/Zombie_process). 2) adding `& wait` on the end backgrounds the last command, preventing it from accepting keyboard input since`wait` is now in the foreground. this may or may not be a problem for you. (it will be a problem if you are running a fancy interactive program like `jest --watch` as the last command.) – wrksprfct Jul 13 '21 at 20:49
128

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.

Oleg
  • 24,465
  • 8
  • 61
  • 91
  • 4
    Perfect solution! I love that it launches the new window. Great for VS2015 package.json needs – TetraDev May 06 '16 at 21:34
  • 29
    This does not work if you have watcher tasks because `&&` waits for the first command to finish before starting the second command and a watcher task will never finish. – Benny Code May 15 '17 at 15:02
  • 8
    @BennyNeugebauer The commands are preceded with the "start" command which opens up a new command line for each of the commands. I was confused at first as well because I thought "using the && operator will not work". This solution is very simple and requires no additional packages/work from the developer. – Addison Aug 09 '17 at 12:52
  • 6
    This is wrong. Command will be run sequentially. On Windows you have to use a plugin in order to run commands simultaneously. – zhekaus Nov 21 '17 at 12:19
  • 3
    Isn’t this Windows-specific? – binki Aug 05 '18 at 18:23
  • 5
    it also now means i have to use windows work on your projects. – airtonix Sep 09 '18 at 02:18
  • 1
    This is a good solution without any further dependency of the external libs – frank Mar 05 '19 at 02:11
  • 1
    @zhekaus: I actually just tried it. Windows 10. No plugins. Multiple simultaneous watchers, each in a window. – recursive Nov 27 '21 at 07:03
98

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.

RyanZim
  • 6,609
  • 1
  • 27
  • 43
nir
  • 3,050
  • 2
  • 20
  • 19
  • 4
    I wonder how this works properly for running the tests, though. Whilst webdriver-start and http-server can run in parallel, the protractor task should only run after the first two. – asenovm Dec 16 '16 at 11:26
  • @asenovm for order dependant tasks, why not just use `gulp` and `gulp-sync`? – r3wt Aug 03 '17 at 21:47
34

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 -- {*}\" --",
Darkowic
  • 661
  • 8
  • 17
  • 1
    Another useful option is -l or --print-labels - it prints the task name as a prefix on each line of output, so you can tell them apart. Nicely colored also. – Brian Burns Feb 11 '21 at 08:44
22

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!

Entity Black
  • 3,401
  • 2
  • 23
  • 38
  • 1
    Double `||` didn't seem to work on my Windows 10 PowerShell, however, a single `|` seems to do _fine_ even on PowerShell. I tried it with just two commands and could only see the output of 2nd part and not 1st one. – Harshit Gupta Feb 23 '22 at 19:35
  • @HarshitGupta `||` might not be implemented in Windows Ppowershell. Apparently it was introduced in PowerShell [Core] 7.0 but might not be backported into Windows Powershell. Sadly my solution isn't bulletproof. – Entity Black Mar 12 '22 at 14:54
17

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

Neil Girardi
  • 4,533
  • 1
  • 28
  • 45
13

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

Boaz
  • 19,892
  • 8
  • 62
  • 70
10

Use concurrently to run the commands in parallel with a shared output stream. To make it easy to tell which output is from which process, use the shortened command form, such as npm:wp-server. This causes concurrently to prefix each output line with its command name.

In package.json, your scripts section will look like this:

 "scripts": {
    "start": "concurrently \"npm:start-watch\" \"npm:wp-server\"",
    "start-watch": "nodemon run-babel index.js",
    "wp-server": "webpack-dev-server"
  }
Edward Brey
  • 40,302
  • 20
  • 199
  • 253
9
npm-run-all --parallel task1 task2

edit:

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

koders
  • 5,654
  • 1
  • 25
  • 20
8

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.

james_womack
  • 10,028
  • 6
  • 55
  • 74
  • 1
    Nope, as `&` operator is not supported on Windows. – Stijn de Witt Jan 02 '16 at 21:45
  • 3
    @StijndeWitt my post says "If you're not on Windows...". 0% of the folks I work with, at one of the largest tech companies in the world, run Node on Windows. So clearly my post is still valuable to many developers. – james_womack Jan 04 '16 at 23:27
  • 2
    It's kind of a circular way of reasoning isn't it though? If you write your npm scripts like this you will not *be able to* use Windows because it won't work. So no one uses Windows, so it doesn't matter that it does not work... You end up with platform dependent software. Now if the thing that needs to be done is very hard to do cross-platform, than that might be a good trade-off to make. But this problem right here is *very easy* to do with standard npm scripts such as [concurrently](https://www.npmjs.com/package/concurrently) and [parallelshell](https://www.npmjs.com/package/parallelshell). – Stijn de Witt Jan 05 '16 at 21:27
  • 2
    @StijndeWitt None of my reasoning was circular. I made a statement of fact sans reasoning. We're posting techniques common to Node developers, many of whom build & deploy on Linux servers. Yes, it should work on Windows if it's a userland script, but the majority of npm scripts are for development and deployment—mostly on *nix machines. Regarding the modules you mentioned a) it's an enormous stretch to call concurrently and parallelshell "standard" (~1500 downloads a day is far from standard in NPMland) and b) if you need additional software for a parallel process, you might as well use Gulp. – james_womack Jan 07 '16 at 00:12
  • @StijndeWitt I appreciate being made aware of those modules though—thank you – james_womack Jan 07 '16 at 00:14
  • @You're welcome and sorry if I came off as harsh. My `nope` was directed at the statement that bash shell scripts are `the best bet`. You see I am one of those poor Windows devs for who all those scripts break so for me it's a recurring annoyance to have to find workarounds / fixes for them. I feel that as NodeJS / NPM is multi-platform we should strive for our packages to be so as well... But it all depends on the situation of course. – Stijn de Witt Jan 07 '16 at 00:28
  • What I meant with circular reasoning was that if we write our script to only work on *nix, it's should be no surprise that almost all devs run Node on *nix. But we can get Windows devs to join the party if we tweak our scripts to work on Windows as well. – Stijn de Witt Jan 07 '16 at 00:30
  • Re: circular reasoning, gotcha – james_womack Jan 07 '16 at 04:34
  • This idea that “0% of devs run Node on Windows” comes across as a bit presumptuous. Hopefully, you’ll agree this is no longer the case in 2023. I also work at one of the largest companies in the world and on my team 100% of the developers run Windows! – Will Jul 07 '23 at 13:54
  • @Will I believe I said 0% of the devs I *worked with* at the time, not 0% of all Node devs. Nevertheless, I wouldn’t respond the same way today in 2023 that I did in 2016. I know there are plenty of Node devs using Windows, I think that’s great. – james_womack Jul 07 '23 at 18:23
8

with installing npm install concurrently

"scripts": {
    "start:build": "tsc -w",
    "start:run": "nodemon build/index.js",
    "start": "concurrently  npm:start:*"
  },
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
6

step by step guide to run multiple parallel scripts with npm. install npm-run-all package globally

npm i -g npm-run-all

Now install and save this package within project where your package.json exists

npm i npm-run-all --save-dev

Now modify scripts in package.json file this way

"scripts": {
    "server": "live-server index.html",
    "watch": "node-sass scss/style.scss --watch",
    "all": "npm-run-all --parallel server watch"
},

now run this command

npm run all

more detail about this package in given link npm-run-all

Muhammad Muzamil
  • 1,013
  • 2
  • 18
  • 25
4
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

Artem Belik
  • 472
  • 4
  • 7
4

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

SB3NDER
  • 63
  • 5
4

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)"
  }
}
gmspacex
  • 642
  • 5
  • 12
4

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

Mosia Thabo
  • 4,009
  • 1
  • 14
  • 24
  • I got this error. Where from start command. Error: spawn start ENOENT at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19) at onErrorNT (internal/child_process.js:467:16) at processTicksAndRejections (internal/process/task_queues.js:82:21) – myfreax Jun 19 '21 at 03:09
  • @Freax Check this out: https://stackoverflow.com/questions/57054403/problem-with-npm-start-error-spawn-cmd-enoent – Mosia Thabo Jun 22 '21 at 11:15
3

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

ian
  • 168
  • 1
  • 1
  • 7
3

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.

Thomas Ebert
  • 447
  • 6
  • 15
Alexandre
  • 3,088
  • 3
  • 34
  • 53
3

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");
})();
3

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\""}
nick
  • 601
  • 7
  • 7
3

You can also use pre and post as prefixes on your specific script.

  "scripts": {
    "predev": "nodemon run-babel index.js &",
    "dev": "webpack-dev-server"
  }

And then run: npm run dev

woutvdd
  • 771
  • 1
  • 9
  • 20
2

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&
Callat
  • 2,928
  • 5
  • 30
  • 47
Vikash Mishra
  • 635
  • 5
  • 7
  • Like your solution. Also have **UI** (`node app`) and **API** (Angular in a subfolder _src_, guess is `cd src/ng serve`), only the first part works. For example `node app& cd src& ng serve`. – Jeb50 Apr 03 '19 at 04:05
2

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);
});
Piittis
  • 318
  • 2
  • 7
2

A simple and native way for Windows CMD

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

(start /b means start in the background)

AlexRMU
  • 47
  • 1
  • 6
  • 1
    Great this works, this works in Windows as well. – Firez May 11 '22 at 09:54
  • 1
    Works like a charm in a pinch. I noticed, however, that CTRL-C does not terminate the background process. This limits the usefulness of this solution somewhat. – Christoph Dec 01 '22 at 05:31
2

How about a good old fashioned Makefile?

This allows you a lot of control including how you manage subshells, dependencies between scripts etc.


# run both scripts
start: server client

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

# start the client
client:
    npm start

call this Makefile and then you can just type

make start to start everything up. Because the server command is actually running in a child process of the start command when you ctrl-C the server command will also stop - unlike if you just backgrounded it yourself at the shell. Make also gives you command line completion, at least on the shell i'm using. Bonus - the first command will always run so you can actually just type make on it's own here.

I always throw a makefile into my projects, just so I can quickly scan later all the common commands and parameters for each project as I flip between them.

dcsan
  • 11,333
  • 15
  • 77
  • 118
2

I think the best way is to use npm-run-all as below:

1- npm install -g npm-run-all <--- will be installed globally
2- npm-run-all --parallel server client

Jamal
  • 811
  • 5
  • 15
1

I had a similar need, and found using GNU parallel the simplest. My package.json looks like this:

"scripts": {
  "foo": "<invoke_foo>",
  "bar": "<invoke_bar>",
  "both": "parallel --ungroup 'npm run' ::: foo bar"
},

Then run both foo and bar with npm run both

Lou Zell
  • 5,255
  • 3
  • 28
  • 23
  • If you use the output `--ungroup` is typically a bad choice. Try `--lb` or nothing if you use the output. – Ole Tange Jun 12 '23 at 00:18
1

Native solution in VScode using parallel tasks:

Ejecute it directly from the task manager F1 -> Task: Run Task -> Development and it will run both tasks in two separated shells in parallel using your scripts.

package.json

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

.vscode\tasks.json

See the line with the following: "dependsOrder": "parallel"
Note: works in vscode in windows and linux

{
    "version": "2.0.0",
    "tasks": [
        {
          "label": "start-watch in package.json",
          "type": "npm",
          "script": "start-watch",
          "presentation": {
            "clear": true,
            "reveal": "silent",
            "showReuseMessage": true
          }
        },
        {
          "label": "wp-server in package.json",
          "type": "npm",
          "script": "wp-server",
          "presentation": {
            "clear": true,
            "reveal": "silent",
            "showReuseMessage": false
          }
        },
        {
          "label": "Development",
          "dependsOrder": "parallel",
          "dependsOn": ["start-watch in package.json", "wp-server in package.json"]
        },
        {
          "label": "Terminate All Tasks",
          "type": "shell",
          "command": "echo ${input:terminate}",
          "problemMatcher": []
        },
    ]
}

The only problem here is that unlike concurrently which runs the commands in the same shell where you run the concurrently command and you can kill both processes (ctrl+C) at the same time, with task they run in two different shells inside the VSCode terminal and can only be terminated separately or we could define another task that will terminate all the open tasks (see the task called Terminate All Task)

fender0ne
  • 281
  • 4
  • 13
0

Using just shell scripting, on Linux.

"scripts": {
  "cmd": "{ trap 'trap \" \" TERM; kill 0; wait' INT TERM; } && blocking1 & blocking2 & wait"
}

npm run cmd and then ^C will kill children and wait for clean exit.

Peter M. Elias
  • 1,204
  • 10
  • 22
0

As you may need to add more and more to this scripts it will become messy and harder to use. What if you need some conditions to check, variables to use? So I suggest you to look at google/zx that allows to use js to create scripts.

Simple usage:

  1. install zx: npm i -g zx
  2. add package.json commands (optional, you can move everything to scripts):
  "scripts": {
    "dev": "zx ./scripts/dev.mjs", // run script
    "build:dev": "tsc -w", // compile in watch mode
    "build": "tsc", // compile
    "start": "node dist/index.js", // run
    "start:dev": "nodemon dist/index.js", // run in watch mode
  },
  1. create dev.mjs script file:
#!/usr/bin/env zx

await $`yarn build`; // prebuild if dist is empty
await Promise.all([$`yarn start:dev`, $`yarn build:dev`]); // run in parallel

Now every time you want to start a dev server you just run yarn dev or npm run dev.

It will first compile ts->js and then run typescrpt compiler and server in watch mode in parallel. When you change your ts file->it's will be recompiled by tsc->nodemon will restart the server.


Advanced programmatic usage

Load env variables, compile ts in watch mode and rerun server from dist on changes (dev.mjs):

#!/usr/bin/env zx
import nodemon from "nodemon";
import dotenv from "dotenv";
import path from "path";
import { fileURLToPath } from "url";

// load env variables
loadEnvVariables("../env/.env");

await Promise.all([
  // compile in watch mode (will recompile on changes in .ts files)
  $`tsc -w`,
  // wait for tsc to compile for first time and rerun server on any changes (tsc emited .js files)
  sleep(4000).then(() =>
    nodemon({
      script: "dist/index.js",
    })
  ),
]);

function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

function getDirname() {
  return path.dirname(fileURLToPath(import.meta.url));
}

function loadEnvVariables(relativePath) {
  const { error, parsed } = dotenv.config({
    path: path.join(getDirname(), relativePath),
  });

  if (error) {
    throw error;
  }

  return parsed;
}
ZiiMakc
  • 31,187
  • 24
  • 65
  • 105