How to replace in stream using Gulp? - node.js

I try to switch from Grunt to Gulp and I have an issue:
I read two streams from two files
var fileStream = gulp.src(file);
var injectionStream = gulp.src(injection)
.pipe(replace('#class-name#', argv.cname));
If my console argument "--remove" is absent I have no problem to concatenate these streams
.pipe(concat('animation.styl'))
.pipe(gulp.dest('./dist'))
However when '--remove' is true I want to delete injection, in other words, subtract injectionStream from fileStream.
I tried:
var es = require('event-stream');
es.replace()
var replace = require('gulp-replace');
It works with strings, but I cannot succeed with streams read from files. Can anybody give me a small hint?
And maybe it is an incorrect tool for generation task and I should stay with Grunt and\or other tools like yo,etc?
Thank you for your time!

Nice work :) Looks like gulp-replace might be an easier way for folk coming here from google..
var replace = require('gulp-replace');
gulp.task('templates', function(){
gulp.src(['file.txt'])
.pipe(replace(/foo(.{3})/g, '$1foo'))
.pipe(gulp.dest('build/file.txt'));
});

I finally found the solution!
fs.readFile(injectionFile, 'utf8', function (err, injStr) {
injStr = injStr.replace(/svv/g, cname);
fileStream
.pipe(gulpif(rm!=true,injectString.append(injStr),replace(injStr,'')))
.pipe(concat(initialFile))
.pipe(gulp.dest(animation))
...
It took a while, but I AM HAPPY it's over.
Thank you

Related

Redirect Readable object stdout process to file in node

I use an NPM library to parse markdown to HTML like this:
var Markdown = require('markdown-to-html').Markdown;
var md = new Markdown();
...
md.render('./test', opts, function(err) {
md.pipe(process.stdout)
});
This outputs the result to my terminal as intended.
However, I need the result inside the execution of my node program. I thought about writing the output stream to file and then reading it in at a later time but I can't figure out a way to write the output to a file instead.
I tried to play around var file = fs.createWriteStream('./test.html'); but the node.js streams rather give me headaches than results.
I've also looked into the library's repo and Markdown inherits from Readable via util like this:
var util = require('util');
var Readable = require('stream').Readable;
util.inherits(Markdown, Readable);
Any resources or advice would be highly appreciated. (I would also take another library for parsing the markdown, but this gave me the best results so far)
Actually creating a writable file-stream and piping the markdown to this stream should work just fine. Try it with:
const writeStream = fs.createWriteStream('./output.html');
md.render('./test', opts, function(err) {
md.pipe(writeStream)
});
// in case of errors you should handle them
writeStream.on('error', function (err) {
console.log(err);
});

Creating multiple files from Vinyl stream with Through2

I've been trying to figure this out by myself, but had no success yet. I don't even know how to start researching for this (though I've tried some Google searchs already, to no avail), so I decided to ask this question here.
Is it possible to return multiple Vinyl files from a Through2 Object Stream?
My use case is this: I receive an HTML file via stream. I want to isolate two different sections of the files (using jQuery) and return them in two separate HTML files. I can do it with a single section (and a single resulting HTML file), but I have absolutely no idea on how I would do generate two different files.
Can anyone give me a hand here?
Thanks in advance.
The basic approach is something like this:
Create as many output files from your input file as you need using the clone() function.
Modify the .contents property of each file depending on what you want to do. Don't forget that this is a Buffer, not a String.
Modify the .path property of each file so your files don't overwrite each other. This is an absolute path so use something like path.parse() and path.join() to make things easier.
Call this.push() from within the through2 transform function for every file you have created.
Here's a quick example that splits a file test.txt into two equally large files test1.txt and test2.txt:
var gulp = require('gulp');
var through = require('through2').obj;
var path = require('path');
gulp.task('default', function () {
return gulp.src('test.txt')
.pipe(through(function(file, enc, cb) {
var c = file.contents.toString();
var f = path.parse(file.path);
var file1 = file.clone();
var file2 = file.clone();
file1.contents = new Buffer(c.substring(0, c.length / 2));
file2.contents = new Buffer(c.substring(c.length / 2));
file1.path = path.join(f.dir, f.name + '1' + f.ext);
file2.path = path.join(f.dir, f.name + '2' + f.ext);
this.push(file1);
this.push(file2);
cb();
}))
.pipe(gulp.dest('out'));
});

Gulp: Passing through to a stream depending on the contents of a stream

I have the following simplified gulp task:
gulp.src(...)
.pipe(stuff())
.pipe(moreStuff())
.pipe(imagemin())
.pipe(yetMoreStuff());
I only want the imagemin stream to be called when the file path contains "xyz", but I want the other three streams to always be called.
Called gulp.src() in another place is not appropriate—this example is massively simplified, and duplicating everything would be messy as hell.
So far, I've got this far:
var through = require('through2');
gulp.src(...)
.pipe(stuff())
.pipe(moreStuff())
.pipe(through.obj(function (file, enc, cb) {
console.log(file.path.indexOf('hero') !== -1);
// file has a pipe method but what do I do?!
}))
.pipe(yetMoreStuff());
Doesn't do anything. I don't know vinyl / streams well enough to be able to do this by myself :(
How do I do this?
It sounds like gulp-filter might be what you're looking for.
var Filter = require('gulp-filter');
var filter = Filter(['**xyz**']);
gulp.src(...)
.pipe(stuff())
.pipe(moreStuff())
.pipe(filter)
.pipe(imagemin())
.pipe(filter.restore())
.pipe(yetMoreStuff());

How can I use factor-bundle with browserify programmatically?

I want to use factor-bundle to find common dependencies for my browserify entry points and save them out into a single common bundle:
https://www.npmjs.org/package/factor-bundle
The factor-bundle documentation makes it seem very easy to do on the command line, but I want to do it programmatically and I'm struggling to get my head around it.
My current script is this (I'm using reactify to transform react's jsx files too):
var browserify = require('browserify');
var factor = require('factor-bundle')
var glob = require('glob');
glob('static/js/'/**/*.{js,jsx}', function (err, files) {
var bundle = browserify({
debug: true
});
files.forEach(function(f) {
bundle.add('./' + f);
});
bundle.transform(require('reactify'));
// factor-bundle code goes here?
var dest = fs.createWriteStream('./static/js/build/common.js');
var stream = bundle.bundle().pipe(dest);
});
I'm trying to figure out how to use factor-bundle as a plugin, and specify the desired output file for each of the input files (ie each entry in files)
This answer is pretty late, so it's likely you've either already found a solution or a work around for this question. I'm answering this as it's quite similar to my question.
I was able to get this working by using factor-bundle as a browserify plugin. I haven't tested your specific code, but the pattern should be the same:
var fs = require('fs'),
browserify = require('browserify'),
factor = require('factor-bundle');
var bundle = browserify({
entries: ['x.js', 'y.js', 'z.js'],
debug: true
});
// Group common dependencies
// -o outputs the entry files without the common dependencies
bundle.plugin('factor-bundle', {
o: ['./static/js/build/x.js',
'./static/js/build/y.js',
'./static/js/build/z.js']
});
// Create Write Stream
var dest = fs.createWriteStream('./static/js/build/common.js');
// Bundle
var stream = bundle.bundle().pipe(dest);
The factor-bundle plugin takes output options o which need to have the same indexes as the entry files.
Unfortunately, I haven't figured out how to do anything else with these files after this point because I can't seem to access factor-bundle's stream event. So for minification etc, it might need to be done also via a browserify plugin.
I have created grunt-reactify to allow you to have a bundle file for a JSX file, in order to make it easier to work with modular React components.
All what you have to do is to specify a parent destination folder and the source files:
grunt.initConfig({
reactify: {
'tmp': 'test/**/*.jsx'
},
})

NodeJS: Asynchronous file read problems

New to NodeJS.
Yes I know I could use a framework, but I want to get a good grok on it before delving into the myriad of fine fine tools that are out there.
my problem:
var img = fs.readFileSync(path);
the above works;
fs.readFile(path, function (err, data)
{
if (err) throw err;
console.log(data);
});
the above doesn't work;
the input path is : 'C:\NodeSite\chrome.jpg'
oh and working on Windows 7.
any help would be much appreciated.
Fixed
Late night/morning programming, introduces errors that are hard to spot. The path was being set from two different places, and so the source path were different in both cases. Thankyou for your help. I am a complete numpty. :)
If you are not setting an encoding when reading a file, you will get the binary content.
So for example, the following snippet will output the content of the test file using UTF-8 encoding. If you don't use an encoding, you will get an output like "" on your console (raw binary buffer).
var fs = require('fs');
var path = "C:\\tmp\\testfile.txt";
fs.readFile(path, 'utf8', function (err, data) {
if (err) throw err;
console.log(data);
});
Another issue (especially on windows-based OS's) can be the correct escaping of the target path. The above example shows how path's on Windows have to be escaped.
java guys will just use this javascript asynchronous command as if in pure java , troublefreely :
var fs = require('fs');
var Contenu = fs.readFileSync( fILE_FULL_Name , 'utf8');
console.log( Contenu );
That should take care of small & big files.

Resources