91

I have some custom testing script, which I can run with npm run test command, which executes some Node script for starting e2e/unit tests. But before it I must start webpack dev server with npm run dev (it's a some custom Node script too, details doesn't matter) in other terminal window. So, I want to omit npm run dev manually executing and move it to custom npm run test script, i.e. I want to execute webpack dev server programmatically in Node script. How can I execute npm run dev programmatically using Node script and stop it then?

"dev": "node node_modules/webpack-dev-server/bin/webpack-dev-server.js --host 0.0.0.0 --history-api-fallback --debug --inline --progress --config config/config.js"
6
  • 1
    Why not create an npm start that runs the other two scripts? Like "start": "npm run dev & npm run test" Commented Jun 25, 2016 at 19:12
  • @elclanrs npm run test should not start before npm run dev Commented Jun 25, 2016 at 19:17
  • Why not run webpack-dev-server programmatically? Commented Jun 25, 2016 at 19:57
  • @robertklep - it's a good suggestion, I'll try Commented Jun 25, 2016 at 19:58
  • @malcoauri if it doesn't work out, check out this answer, which explains how to run NPM programmatically. Commented Jun 25, 2016 at 20:00

6 Answers 6

99

You can use execSync to run npm scripts one by one:

const { execSync } = require('child_process');
const isWindows = process.platform === `win32`;
const npm = isWindows ? `npm.cmd` : `npm`;

execSync(`${npm} run dev`);
execSync(`${npm} run test`);
Sign up to request clarification or add additional context in comments.

4 Comments

error: expected a function and UnhandledPromiseRejectionWarning: Unhandled promise rejection.
The UnhandledPromiseRejectionWarning error is because the series param expects an array of functions. So you can resolve this error by doing series([ () => exec('npm run dev'), () => exec('npm run test') ]);
what I got working and what I think is the correct pattern is (cb) => exec('npm run dev', cb)
Just FYI, this relies on an external package: npmjs.com/package/async
37

Here is a solution that should work reliably across all platforms. It's also very concise. Put this into build.js, then run node build.

const {execSync} = require('child_process')

execSync("npm run clean")
execSync("npm run minify")
execSync("npm run build_assets")

It will immediately abort on abnormal npm termination.

3 Comments

To show console output with the above method, attach stdio as per stackoverflow.com/a/31104898/5771199
upvote for this because it doesn't require an external library
This times out for me... It's close though...
29

(As @fariz-luqman notes below, this (may) have been removed in npm 8.0.0.)

Just install npm:

npm install npm

Then in your program:

npm.commands.run('dev', (err) => { ... });

See the source for more info. The npm.commands object is an unofficial API for npm. Note that using exec or spawn to execute npm is safer, since the API is unofficial.

10 Comments

Though there are advantages to @foysal-osmany's answer. See stackoverflow.com/questions/15957529/…
Also note that I agree that using exec is safer. The reason that I used the npm module directly was in order to avoid spinning up a second node.js runtime.
@Xunnamius, no this is not the correct answer. Please refer to your own link. It is not safe to call npm as a module for several reasons.
@JulianKnight You're right. Though I don't remember my usecase, I believe I used exec instead. Though I'm curious what you mean by "not safe" and "several reasons"? Do you just mean the size and unstable API?
The unstable API and the fact that there have previously been issues between specific versions of npm/node.js
|
14

An npm blog post recommends using shelljs:

let shell = require("shelljs");

shell.exec("echo shell.exec works");
shell.exec("npm run dev");

See https://blog.npmjs.org/post/118810260230/building-a-simple-command-line-tool-with-npm.html

2 Comments

This is actually a good answer, it prints out the logs as well.
That's not npm documentation, it's a blog post with a warning that the blog has been discontinued. Npm is not node, and the node docs cover the child_process.exec command: docs.npmjs.com/cli/v10/commands/npm-exec.
1

Use PM2, it is really usefull and easy...

npm install pm2
const pm2 = require('pm2');

pm2.start({
    script: 'npm -- run monitorTheWeather',
    autorestart : false 
  }, (err, apps) => {
    pm2.disconnect()
    if (err) { throw err }
  })

1 Comment

Using your code I get the following error: ` C:\givingway\gw-ts\t.js:11 throw err ^ [ Error: Script not found: C:\givingway\gw-ts\npm -- run test`
0

work for me :

import { series } from "async";
import { exec } from "child_process";
series([
    (cb) => {
        exec("commands here", (err, std, stderr) => {
            // your callback here
            return cb(); // series callback here
        });
    },
    (cb) => {
        exec("commands here", (err, std, stderr) => {
            // your callback here
            return cb(); // series callback here
        });
    },
]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.