How do you create an empty stream in Gulp?
Asked Answered
D

6

21

SSCCE:

gulp.task('foo', [], function() {
    var barFiles = getBarFiles();
    var bazFiles = getBazFiles();

    var barStream, bazStream;
    if (barFiles && barFiles.length > 0) {
        barStream = gulp.src(barFiles);
    }
    if (bazStream && bazStream.length > 0) {
        bazStream = gulp.src(bazStream);
    }
    return eventStream
        .merge(barStream, bazStream)
        .pipe(g.concat('bar-and-baz'))
        .pipe(gulp.dest('./foo-output/'));
});

getBarFiles() or getBazFiles() may return an empty array, which is not allowed by gulp.src(): Error: Invalid glob argument, hence the need to wrap the creation of the stream with an if condition.

So the question is, how do I create an empty stream, so that it can be merged with the other empty on non-empty stream?

Duckworth answered 1/9, 2014 at 12:4 Comment(3)
You could look into using gulp-util.noop to create an empty stream.Lampert
@Lampert so, "a stream that does nothing but pass data straight through", doesn't need to have a gulp.src to pipe data through?Duckworth
That is how I understand it to act. However, I don't have any expirence using this method, so you would need to look in to whether this answers your question (which is why I posted this as a comment, rather than as an answer).Lampert
O
9

How about using:

return gulp.src('.');

For newer Gulp its possible you will need to add allowEmpty: true option as follows:

return gulp.src('.', {allowEmpty: true});

As I assume it should just pass current directory in the stream with no actions on it. Works for me.

Overdye answered 7/12, 2018 at 1:22 Comment(2)
Not working anymore without allowEmpty : true parameterFirstly
@loenix So add the parameter and enjoy :)Carleton
S
7

A function for creating an empty stream for use in gulp (gleaned from vinyl-fs source) is this:

var through2 = require('through2');

function createEmptyStream() {
    var pass = through2.obj();
    process.nextTick(pass.end.bind(pass));
    return pass;
}

If you make barFiles = createEmptyStream() in the example, it is functionally the same.

Current version of gulp (3.9.1) and vinyl-fs (0.3.0) on 2016-03-05 allows for an empty src array (from my testing). It uses something similar to the above to create an empty stream. Your example works (mostly as-is) in current versions:

var eventStream = require('event-stream');
var gulp = require('gulp');
var g = require('gulp-load-plugins')();

function getBarFiles() {
    return [
    ];
}

function getBazFiles() {
    return [
        'baz.txt'
    ];
}

gulp.task('foo', [], function() {
    var barFiles = getBarFiles();
    var bazFiles = getBazFiles();
    var barStream = gulp.src(barFiles);
    var bazStream = gulp.src(bazFiles);

    return eventStream
        .merge(barStream, bazStream)
        .pipe(g.concat('bar-and-baz.txt'))
        .pipe(gulp.dest('./'));
});

gulp.task('default', [ 'foo' ]);

The file bar-and-baz.txt is a concatenation of the contents of all files in the globs returned from those two functions. An empty list of globs is accepted.

Soutine answered 2/5, 2015 at 9:19 Comment(1)
Anyone has insight as to why they call the stream's end method asynchronously with process.nextTick instead of just calling it directly right after creating it? Because from my tests with gulp tasks the synchronous version seems to work correctly.Stickseed
U
4

Maybe my answer is too simplistic, but I had exactly the same question as the OP, and I was able to solve it without importing any additional modules:

if (platform != 'android') {
    // Android doesn't need anything here
    return gulp.src([]); // empty stream
}

In other words, gulp.src() doesn't work, but gulp.src([]) seems to work fine. Or am I missing something?

EDIT 18 Mar 2020: Apparently, Gulp 4.0 now requires the allowEmpty flag for this to work:

if (platform != 'android') {
    // Android doesn't need anything here
    return gulp.src([], {allowEmpty: true}); // empty stream
}

See Artur Stępień's answer to this question, or this related SO question.

Unassuming answered 23/1, 2018 at 18:20 Comment(8)
@GrumpyCrouton It may look superficially similar, but it isn't. The answer you refer to uses an additional module, 'event-stream'. My answer uses only what's already present in the gulp module. To me, that's an important difference; why would I want to pull in an unrelated module just to create something I can already make without it?Unassuming
@GrumpyCrouton As for what it adds to the question, I'd say simplifying the previous answers is more than enough. And the age of the question isn't relevant; SO questions are meant to be a reference to future readers, not just the person who originally asked the question.Unassuming
That is an important difference to make, I didn't have enough experience in the subject to realize that difference (Which is why I was asking for clarification) and as such, I apologize. In the future, perhaps you should indicate the differences in your code versus other similar (Even superficially similar) questions to avoid confusion with people who are just moderating "the best they can" because the answer didn't look any different to the other. Thank you for the clarification. In this case, I believe your answer exceeds the others and may be the best answer to-date if what you say is true.Soppy
I've modified the answer to make it a little clearer that it doesn't require importing additional modules. Thanks for a good suggestion, and for doing your share of moderation to make SO better.Unassuming
Trying this I get Error: Invalid glob argumentEctopia
I also get Error: Invalid glob argumentMook
@Mook and @Morgz, add {allowEmpty: true}.Unassuming
On Gulp 4.0.2, I got Error: Invalid glob argument, even with {allowEmpty: true}. I changed the empty array to '.' and it works! return src('.', {allowEmpty: true});Dispensatory
S
3

Another solution that met my needs quite well was to use gulp-tap:

var config = require('./config');
var gulp = require('gulp');
var tap = require('gulp-tap');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

var noop = function() {};

gulp.task('mytask', function() {
  return gulp.src('*.js')
    .pipe(config.production ? uglify() : tap(noop))
    .pipe(concat('code.min.js'))
    .pipe(gulp.dest('dist'));
});

This allows you to easily create an empty stream which you can pass inside a .pipe() so you don't have to have an if statement outside.

Note: As I just figured out, you shouldn't store the tap(noop) into a variable and attempt to use it across multiple tasks as that may actually mix your streams and cause erratic behavior.

Skeet answered 9/7, 2016 at 19:53 Comment(0)
M
2

I use this:

https://github.com/dominictarr/event-stream

es.merge([]);

It works!

Milissamilissent answered 21/3, 2016 at 8:59 Comment(1)
Thanks for the clue, I used merge2 in the same way and it worked as wellMckinnie
D
0

One solution:

gulp.task('foo', [], function() {
    var barFiles = getBarFiles();
    var bazFiles = getBazFiles();

    var barStream, bazStream;
    if (barFiles && barFiles.length > 0) {
        barStream = gulp.src(barFiles);
    }
    if (bazStream && bazStream.length > 0) {
        bazStream = gulp.src(bazStream);
    }
    var mergedStream;
    if (barStream && bazStream) {
        mergedStream = eventStream
            .merge(barStream, bazStream);
    }
    else if (barStream || bazStream) {
        mergedStream = barStream || bazStream;
    }
    if (mergedStream) {
        return mergedStream
            .pipe(g.concat('bar-and-baz'))
            .pipe(gulp.dest('./foo-output/'));
    }
});

This side-steps the the need to create an empty stream by testing each of the streams, and merging them only when both are present.

However, I would still like to know of a way to create an empty stream in gulp.

Duckworth answered 1/9, 2014 at 12:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.