javascriptnode.jsgruntjsgrunt-plugins

How to run createReadStream(a stream) in a grunt plugin?


I am trying to create a stream within a grunt plugin and failing miserably...

This code works as a standalone node script:

var fs = require('fs');

var sourceFile = 'testfile.log';

fs
    .createReadStream( sourceFile )
    .on('data', function() {
        console.log('getting data');
    })
    .on('end', function() {
        console.log('end!');
    });

Output

$ node test.js
getting data
end!

Now when putting this into a grunt plugin:

'use strict';

var fs = require('fs');

module.exports = function(grunt) {

    grunt.registerMultiTask('test', 'Testing streams', function() {

        var sourceFile = 'testfile.log';

        fs
            .createReadStream( sourceFile )
            .on('data', function() {
                console.log('getting data');
                grunt.log.oklns('anything?');
            })
            .on('end', function() {
                console.log('end!');
                grunt.log.oklns('nothing?');
            });

    });

};

Output

$ grunt test
Running "test" (test) task

Done, without errors.

I am testing with:

var stats = fs.lstatSync( sourceFile );
if( !stats.isFile() ) { /*etc*/ }

If the file exists but my node test app is in the same folder and has access... Any help is appreciated. I know it mustn't be very hard to do ;)


Solution

  • You are using async code inside a Grunt task. When doing so you must tell grunt to wait for it to complete. This is done by the following:

        // Within the task
    
        var done = this.async();
    
        // inside a callback of an async function, 
        // i.e. when the read stream is closed */ 
    
        function(){
          done(true);
        }
    

    Calling done with a true condition tells Grunt the task is complete. If this.async() is not called, the task executes synchronously. In your case, the grunt tasks completes before the read stream receives any data.

    You may read more about this particular feature here (inside-tasks#this.async).

    As a side note, the code you've provided registers the task as a Multi Task, but the code (at least in its current state) is a basic task rather than a Multi Task. You can read about the differences in the official documentation here (basic tasks) and here (multi tasks).