Piping concatenated Gulp stream file.contents to s

2019-06-24 07:23发布

问题:

I suspect this comes from a limited understanding of streams but I've looked everywhere and cannot get it to work. In short, I want to take a Gulp stream and pass the concatenated contents of the stream to an express response directly without writing to the file system.

This is how I got the idea (which works fine):

app.get('*', function(req, res){
    var stream = fs.createReadStream(__dirname + '/app/index.html');
    stream.pipe(res);
});

But I want to apply the same concept using a Gulp stream:

app.get('/app/js/concatenated-js-files.js', function(req, res){
    gulp.src('app/js/**/*.js')
        .pipe(concat())
        .pipe(res);
});
app.listen(5555, function() {
    console.log('Listening on port 5555');
});

Which does not work and yields the following when requesting /app/js/concatenated-js-files.js from the browser:

[gulp] Error in plugin 'gulp-concat': Missing fileName option for gulp-concat
    at module.exports (/Users/lgomez/Projects/index-packager/node_modules/gulp-concat/index.js:10:24)
    at Object.handle (/Users/lgomez/Projects/index-packager/index.js:83:15)
    at next_layer (/Users/lgomez/Projects/index-packager/node_modules/express/lib/router/route.js:103:13)
    at Route.dispatch (/Users/lgomez/Projects/index-packager/node_modules/express/lib/router/route.js:107:5)
    at /Users/lgomez/Projects/index-packager/node_modules/express/lib/router/index.js:213:24
    at Function.proto.process_params (/Users/lgomez/Projects/index-packager/node_modules/express/lib/router/index.js:284:12)
    at next (/Users/lgomez/Projects/index-packager/node_modules/express/lib/router/index.js:207:19)
    at Layer.expressInit [as handle] (/Users/lgomez/Projects/index-packager/node_modules/express/lib/middleware/init.js:23:5)
    at trim_prefix (/Users/lgomez/Projects/index-packager/node_modules/express/lib/router/index.js:255:15)
    at /Users/lgomez/Projects/index-packager/node_modules/express/lib/router/index.js:216:9

That error is expected. gulp-concat was written to output to file.

I'd like to avoid writing a gulp plugin that would be very similar to gulp-concat. I may fork and suggest it but, for now, is there another way to achieve this?

Thank you!

Here's the complete code if you'd like to try it.

var express = require('express');
var gulp    = require('gulp');
var concat  = require('gulp-concat');
var app     = express();
app.get('/app/js/concatenated-js-files.js', function(req, res){
    gulp.src('app/js/**/*.js')
        .pipe(concat())
        .pipe(res);
});
app.listen(5555, function() {
    console.log('Listening on port 5555');
});
// http://localhost:5555/app/js/concatenated-js-files.js

回答1:

gulp works on streams of virtual File objects, not physical files. As such, gulp-concat doesn't write to the file system no matter what name you give it. However, you will still have a problem because you cannot send these file objects directly to the res response.

You need to write the contents of the virtual file(s) to res. An easy way to do this is to use through to make a stream that reads the gulp input and writes the files' contents to res. If your stream handles multiple files, then you don't need concat.

var through = require('through');

// create a stream that reads gulp File objects and outputs their contents
function sendTo(res) {   
    return through(
        function write(data) {    // this will be called once for each file
            res.write(data.contents);
        },
        function end() {    // this will be called when there are no more files
            res.end()
        }
    );
}

app.get('/app/js/concatenated-js-files.js', function(req, res){
    gulp.src('app/js/**/*.js')
        .pipe(sendTo(res));
});

Also, gulp internally uses vinyl-fs to read the files, so you can use vinyl-fs directly if have no other need for gulp.