How to use npm scripts within javascript
Answer
I do something like this for my Webpack bundles. You can simply use child_process.spawn
to execute command-line programs and handle the process in a node script.
Here's an example:
var spawn = require('child_process').spawn
// ...
// Notice how your arguments are in an array of strings
var child = spawn('./node_modules/.bin/webpack-dev-server', [
'--progress',
'--colors',
'<YOUR ENTRY FILE>'
]);
child.stdout.on('data', function (data) {
process.stdout.write(data);
});
child.stderr.on('data', function (data) {
process.stdout.write(data);
});
child.on('exit', function (data) {
process.stdout.write('I\'m done!');
});
You can handle all of the events you like. This is a fairly powerful module that allows you to view the process' PID (child.pid
) and even kill the process whenever you choose (child.kill()
).
Addendum
A neat trick is to throw everything into a Promise
. Here's a simplified example of what my version of script.js
would look like:
module.exports = function () {
return new Promise(function (resolve, reject) {
var child = spawn('./node_modules/.bin/webpack', [
'-d'
]);
child.stdout.on('data', function (data) {
process.stdout.write(data);
});
child.on('error', function (data) {
reject('Webpack errored!');
});
child.on('exit', function () {
resolve('Webpack completed successfully');
});
});
}
Using this method, you can include your script.js
in other files and make this code synchronous in your build system or whatever. The possibilities are endless!
Edit The child_process.exec
also lets you execute command-line programs:
var exec = require('child_process').exec
// ...
var child = exec('webpack-dev-server --progress --colors <YOUR ENTRY FILES>',
function(err, stdout, stderr) {
if (err) throw err;
else console.log(stdout);
});
The accepted answer doesn't work on Windows and doesn't handle exit codes, so here's a fully featured and more concise version.
const spawn = require('child_process').spawn
const path = require('path')
function webpackDevServer() {
return new Promise((resolve, reject) => {
let child = spawn(
path.resolve('./node_modules/.bin/webpack-dev-server'),
[ '--progress', '--colors' ],
{ shell: true, stdio: 'inherit' }
)
child.on('error', reject)
child.on('exit', (code) => code === 0 ? resolve() : reject(code))
})
}
path.resolve()
properly formats the path to the script, regardless of the host OS.
The last parameter to spawn()
does two things. shell: true
uses the shell, which appends .cmd
on Windows, if necessary and stdio: 'inherit'
passes through stdout and stderr, so you don't have to do it yourself.
Also, the exit code is important, especially when running linters and whatnot, so anything other than 0 gets rejected, just like in shell scripts.
Lastly, the error
event occurs when the command fails to execute. When using the shell, the error is unfortunately always empty (undefined
).