58

I've been trying for a day to write two pipe functions, one that compiles less files and another one that concats these files. I want to learn how to write transform streams/pipes for more complex plugins.

So I want to know how to read data from another pipe, and how to alter that data and send it to the next pipe. This is what I have so far:

 gulp.src(sources)
   .pipe(through.obj(function (chunk, enc, cb) {

     var t = this;
     // console.log("chunk", chunk.path);
     fs.readFile(chunk.path, enc, function (err,data) {
       if (err) { cb(err); }

       less.render(data, {
         filename : chunk.path,
         sourceMap : {
           sourceMapRootpath : true
         }
       })
       .then(function (outputCss) {
          // console.log("less result",outputCss);
          t.push(chunk);// or this.push(outputCss) same result
          cb();
       });

     });

   }))
   .pipe(through.obj(function (chunk, enc, cb) {
     console.log("chunk", chunk.path); // not event getting called.
     cb();
   }))

I can't get the outputCSS for each file in the second pipe. How can I send it?

Preview
  • 35,317
  • 10
  • 92
  • 112
Vlad Nicula
  • 3,577
  • 6
  • 32
  • 50
  • 1
    https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/dealing-with-streams.md might help some people. – Shanimal Mar 25 '17 at 03:09

1 Answers1

68

Well, you don't need to use fs here, you already got the stream of file (here your chunk).

Another point, you're not sending back to the pipe the files, so I guess that's why nothing is called on your second one.

const through = require('through2')

gulp.src(sources)
  .pipe(through.obj((chunk, enc, cb) => {
    console.log('chunk', chunk.path) // this should log now
    cb(null, chunk)
  }))

In ES2015:

import through from 'through2'

gulp.src(sources)
  .pipe(through.obj((chunk, enc, cb) => cb(null, chunk)))

And for your specific example:

.pipe(through.obj((file, enc, cb) => {
  less.render(file.contents, { filename: file.path, ... }) // add other options
    .then((res) => {
      file.contents = new Buffer(res.css)
      cb(null, file)
    })
}))

This is still pretty basic, I don't check for errors, if it's not a stream and so on, but this should give you some hint on what you've missed.

Preview
  • 35,317
  • 10
  • 92
  • 112
  • Thanks for taking the time to answer my question. What I understand from your code is that the file object contents needs to be replaced by a buffer of the css string generated by less, and in order to send it to the next pipe transform/write instance I need to pass this file as the second argument to the cb function. I will try this today and see how it works. – Vlad Nicula Jan 14 '15 at 08:39
  • 2
    @vsync Simple _in gulp_, it may be easier in different languages – Preview Nov 06 '15 at 00:26
  • @vsync the word would be basic, not simple I guess. Most gulp pipe functions need to send data thru them this way. – Vlad Nicula Dec 10 '15 at 12:40
  • @VladNicula - a simple answer wouldn't include any unneeded code (like `through` and so on) but only the most basic things, which this example does not show. So a person who comes from google, and sees this title, is looking for the very basic example and not 50% lines of code which are not related. – vsync Dec 10 '15 at 13:56
  • 6
    @vsync, are you using something else instead of `through` for this? If so, please write a better answer. It will benefit us all :) – Vlad Nicula Dec 10 '15 at 14:05
  • 13
    @vsync I think you're crossing the line. The question is about how to write a simple pipe function. I've provided and answer to this question, if you want to know how gulp works, you should go to their repository. Stackoverflow is "only" a Q&A website you know. – Preview Dec 10 '15 at 19:17
  • where does `through.obj` come from? I tried requiring "through" but it says that `obj` is not a function. Do I need to npm install something? – rob Feb 04 '16 at 21:47
  • 1
    Yes there is through and through2 npm packages if I recall correctly – Preview Feb 04 '16 at 21:49
  • Thanks! `npm install through2` and `var through = require('through2');` did the trick – rob Feb 04 '16 at 21:50
  • @rob Nice, I will add it in the answer for future users ;) – Preview Feb 04 '16 at 22:23
  • 1
    If I use this and have .on('end', something) as the next step in my pipe, the 'end' never happens? – Bemmu Apr 26 '19 at 03:55