Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing variables between "pipes" in Gulp

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?

like image 455
gargantuan Avatar asked Feb 25 '14 21:02

gargantuan


People also ask

What is Gulpfile used for?

Gulp is a task runner that uses Node. js as a platform. Gulp purely uses the JavaScript code and helps to run front-end tasks and large-scale web applications. It builds system automated tasks like CSS and HTML minification, concatenating library files, and compiling the SASS files.

What is gulp Gulpfile?

Gulpfile explained A gulpfile is a file in your project directory titled gulpfile. js (or capitalized as Gulpfile. js , like Makefile), that automatically loads when you run the gulp command.

How does gulp pipe work?

Gulp actually work with Streams i.e. the gulp. src() method reads files as Stream from source and pass it to a gulp plugin through pipe() method for doing a task. So, the pipe() method reads the stream from the gulp. src(), execute the plugin task and passes it to destination stream via gulp.


1 Answers

The issue here is that you are creating the second prompt ('You said ' + myVar) before the first prompt has been executed:

  1. Set myVar to 'MONKEY'
  2. Create streams
    1. Create src stream, which is asynchronous
    2. Create first prompt, and add it to the src stream
    3. Create second prompt using current value of myVar, and add it to the first prompt stream
  3. Only now are the streams executed processed
    1. Load sources
    2. Run first prompt, set the myVar
    3. 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.

like image 125
OverZealous Avatar answered Sep 21 '22 12:09

OverZealous