972

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.

7
  • 244
    && will run your scripts sequentially while & will run them in parallel. Commented May 30, 2019 at 8:22
  • 10
    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. Commented Nov 8, 2019 at 18:59
  • 6
    @vsync Does that apply to Windows? Commented Feb 9, 2021 at 3:31
  • 5
    @vsync Are you sure? Other comments are saying that's not how it works, and it didn't work in practice for me. Commented Feb 9, 2021 at 23:10
  • 6
    @Clonkex, yes BUT it's unreliable and I use concurrently npm package instead, which works well, and I only use Windows Commented Feb 11, 2021 at 9:26

32 Answers 32

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

Sign up to request clarification or add additional context in comments.

Comments

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

Comments

1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.