runlikenpm
runlikenpm
spawns commands much like npm would, but without running npm.
Typical use under gulp
:
var gulp = require('gulp');
var run = require('@garthk/runlikenpm');
gulp.task('babel', run('babel -r -s inline src -d dist'));
run
with a single argument returns a function that takes a callback;
gulp.task
calls it. Boom.
Usage
run(command) # returns function taking callback
run(command)(callback) # spawns and calls back
run(command, callback) # spawns and calls back
run
will:
- Throw an assertion error if its arguments are unexpected types;
- Spawn the command under the guidance of the appropriate shell;
- Let its output hit your terminal on the fly without buffering until exit;
- Not modify your
process.env
or current working directory; and - Call back only once.
Why, oh why?
First, I assume we need gulp
, having pushed the use of
npm as a build tool as far as we could. Seriously, give it a shot.
There are limits, but they're further out than you expect.
Still here? Me, too. I wanted:
- To shell out to commands to keep my
gulpfile.js
small, vs long pipeline boilerplate; with - Behaviour similar to
npm run-script
; especially - The path adjusted so we can run scripts in
node_modules/.bin
; and - Everything still working on Windows; but
- Without having to shell out through
npm
to get that.
TL;DR: I couldn't find anything that did both, either amongst:
-
gulp
plugins - Packages that don't have
gulp
in their name
Alternative gulp plugins
Yes, we should use packages directly rather than writing yet another gulp plugin destined for the blacklist. That said: sometimes the code to do so gets long enough we're at risk of endless duplication of bad code for which we can't ship bug-fixes.
Anyone else trying to solve the problem of writing clean looking gulpfiles
is probably going to ship it with gulp
in the name, so that's how I searched.
Options I found before giving up due to exhaustion in the face of 1500 plugins:
-
gulp-exec
(blessed over the others by the blacklist) gulp-run
gulp-shell
gulp-spawn
They all wear the gulp
prefix because they're designed to hook up standard
input and output to vinyl
streams.
I don't need that. If you do, submit bug reports for their Windows handling and
use whomever gets it right first.
gulp-exec
and gulp-spawn
don't fix the path (#19 and #11 respectively).
gulp-run
does, but not always on Windows because it hard-codes the
environment variable name as PATH
, when it might be Path
. gulp-shell
has the same problem. None of them set windowsVerbatimArguments
so that
PATHEXT
will work. I lost interest before checking to see whether any of them
take comspec
into account.
Alternative regular packages
Outside the gulp
universe, I found:
-
cross-spawn
: very popular, supports shebangs, escapes arguments, has good tests; but you'll need to break up the arguments yourself and deal with theEventEmitter
API -
exec
: also popular, but no Windows support, calls back with strings forstdout
andstderr
instead of letting them write to the TTY -
Many others along the same lines
Scope Restrictions
-
No streaming. Use the alternatives above if you don't need Windows support.
-
No promises. You can promisify it yourself using your favourite package.
-
No environment variables from your package configuration. I think you're best off spawning
npm run
in this case. It'll be slower, but why take the risk on a third party re-implementation of that functionality?
Dependencies
I'm taking a dependency on Tim Oxley's
npm-path
to fix the path.
Caveats
-
I no longer have a Windows box handy on which to test.
-
I'm worried the check for
process.env.comspec
is hard-coded for lower case. I'll leave it for now, asnpm
itself seems to share the limitation.