I'm trying to write a gulp tasks that takes some user input via the gulp-prompt plugin. But I'm having trouble passing that input along to other eg:
gulp.task('userinput', function(){
var myVar = 'MONKEY';
gulp.src('./templates/_component.*')
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}))
.pipe(prompt.confirm('You said ' + myVar));
});
Assuming I enter hello
at the prompt, I was expecting the confirmation to say You said Hello
, but it says You said MONKEY
.
Is this possible with Gulp?
The issue here is that you are creating the second prompt ('You said ' + myVar
) before the first prompt has been executed:
- Set
myVar
to 'MONKEY'
- Create streams
- Create
src
stream, which is asynchronous
- Create first prompt, and add it to the src stream
- Create second prompt using current value of
myVar
, and add it to the first prompt stream
- Only now are the streams executed processed
- Load sources
- Run first prompt, set the
myVar
- Run the second prompt using previously generated message
The only solution if you want to keep it all as a single stream is to use the variable within something that allows for a closure (function). Some plugins already accept a closure as an argument, but most don't.
One solution to wrap a stream in a closure that would work here is gulp-tap, which isn't designed for this scenario specifically, but should work. it looks like this:
var tap = require('gulp-tap');
//...
gulp.task('userinput', function(){
var myVar = 'MONKEY';
gulp.src('./templates/_component.*')
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}))
.pipe(tap(function(file, t) {
// format is t.through(stream-function, [arguments...])
return t.through(prompt.confirm, ['You said ' + myVar]);
});
});
Because this is wrapped in a closure, and evaluated for each file, it will pick up the current value for the variable. However, because it works on each file, you'll see the prompt once for each file processed.
An better solution would be to separate your task into multiple, dependent tasks. That would look something like this:
var myVar = 'MONKEY';
gulp.task('userinput1', function(){
return gulp.src('./templates/_component.*', {read: false})
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}));
});
gulp.task('userinput', ['userinput1'], function() {
return gulp.src('./templates/_component.*')
.pipe(prompt.confirm('You said ' + myVar));
});
Now the first task (userinput1
) will run and complete before the second one is processed (userinput2
), so the variable will be set correctly.
NOTE: Make sure you return
the stream from your tasks, otherwise they are processed synchronously, and your variable won't get set.
Finally, it might make more sense to forgo the gulp-prompt
task altogether, because it doesn't really have much to do with the stream. You'd probably be better off using straight Node JavaScript within your task to gather the user's input (preferably in a synchronous manner), then processing your files in a gulp-stream after that.