Marius Schulz
Marius Schulz
Front End Engineer

Merging Two Gulp Streams

When you use gulp as your task runner as is common in JavaScript development these days, your gulpfile.js contains a series of tasks. Some of those tasks might depend on each other so that a certain execution order has to be ensured. After all, you don't want to clean a directory right after you've written files to it.

Within a gulp task, you usually read some files using gulp.src, pass them through various transformations using the pipe function, and finally write them back to disk by piping to gulp.dest:

var gulp = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");

gulp.task("scripts", function () {
  return gulp
    .src(["src/**/*.js"])
    .pipe(concat("bundle.min.js"))
    .pipe(uglify())
    .pipe(gulp.dest("dist/"));
});

Note that there's a return statement which returns the created stream. Without it, the task system wouldn't be able to detect when asynchronous operations finish and thus couldn't await the result of the task. Plus, the task runner would incorrectly display very short task execution times.

So, to make sure asynchronous operations are handled correctly, you should always return the created stream. But what if there are multiple streams within a single task? Which one do you return? Somehow, these multiple streams have to be combined into a single stream that can be handed back to gulp's task system.

Of course, there's an NPM package that does precisely that: merge-stream creates a stream that emits events from multiple other streams. Here's how it's used:

gulp.task("copy-vendor-files", function () {
  var vendorStyles = gulp
    .src("src/styles/vendor/*.css")
    .pipe(gulp.dest("dist/styles/vendor"));

  var vendorScripts = gulp
    .src("src/scripts/vendor/*.js")
    .pipe(gulp.dest("dist/scripts/vendor"));

  return merge(vendorStyles, vendorScripts);
});

Two separate streams read vendor library files and copy them to different folders within the dist directory. The copy-vendor-files task is only finished once both individual streams are finished, so the latter are merged into a single stream which is being returned to gulp's task system. That's it!