Can Gulp overwrite all src files? - node.js

Let's say I want to replace the version number in a bunch of files, many of which live in subdirectories. I will pipe the files through gulp-replace to run the regex-replace function; but I will ultimately want to overwrite all the original files.
The task might look something like this:
gulp.src([
'./bower.json',
'./package.json',
'./docs/content/data.yml',
/* ...and so on... */
])
.pipe(replace(/* ...replacement... */))
.pipe(gulp.dest(/* I DONT KNOW */);
So how can I end it so that each src file just overwrites itself, at its original location? Is there something I can pass to gulp.dest() that will do this?

I can think of two solutions:
Add an option for base to your gulp.src like so:
gulp.src([...files...], {base: './'}).pipe(...)...
This will tell gulp to preserve the entire relative path. Then pass './' into gulp.dest() to overwrite the original files. (Note: this is untested, you should make sure you have a backup in case it doesn't work.)
Use functions. Gulp's just JavaScript, so you can do this:
[...files...].forEach(function(file) {
var path = require('path');
gulp.src(file).pipe(rename(...)).pipe(gulp.dest(path.dirname(file)));
}
If you need to run these asynchronously, the first will be much easier, as you'll need to use something like event-stream.merge and map the streams into an array. It would look like
var es = require('event-stream');
...
var streams = [...files...].map(function(file) {
// the same function from above, with a return
return gulp.src(file) ...
};
return es.merge.apply(es, streams);

Tell gulp to write to the base directory of the file in question, just like so:
.pipe(
gulp.dest(function(data){
console.log("Writing to directory: " + data.base);
return data.base;
})
)
(The data argument is a vinyl file object)
The advantage of this approach is that if your have files from multiple sources each nested at different levels of the file structure, this approach allows you to overwrite each file correctly. (As apposed to set one base directory in the upstream of your pipe chain)

if you are using gulp-rename, here's another workaround:
var rename = require('gulp-rename');
...
function copyFile(source, target){
gulp.src(source)
.pipe(rename(target))
.pipe(gulp.dest("./"));
}
copyFile("src/js/app.js","dist/js/app.js");
and if you want source and target to be absolute paths,
var rename = require('gulp-rename');
...
function copyFile(source, target){
gulp.src(source.replace(__dirname,"."))
.pipe(rename(target.replace(__dirname,".")))
.pipe(gulp.dest("./"));
}
copyFile("/Users/me/Documents/Sites/app/src/js/app.js","/Users/me/Documents/Sites/app/dist/js/app.js");

I am not sure why people complicate it but by just starting your Destination path with "./" does the job.
Say path is 'dist/css' Then you would use it like this
.pipe(gulp.dest("./dist/css"));
That's it, I use this approach on everyone of my projects.

Related

How to manipulate by relative output path of Vinyl file inside gulp pipeline?

In the below gulp task, targetFile.relative (property of Vinyl instance)
will bee concatenated to dest path. For example if targetFile.relative is images/icons/HamburgerMenu__Icon.svg, output path will be <Project absolute path>/dest/images/icons/HamburgerMenu__Icon.svg
gulp.src('source/singletonComponents/**/*.+(png|jpg|gif|svg)')
.pipe(gulp.dest( targetVinylFile => {
return 'dest'
}));
What if we want to change targetFile.relative? For example, we want to output to dest/pictures/icons/HamburgerMenu__Icon.svg, but we don't want to rename source forlder images to pictures.
Because in this question we are considering the output path manipulation, please, not not touch source files/directories, and also 'source/singletonComponents/**/*.+(png|jpg|gif|svg)' in solutions.
And also: it you think that it's not possible, please answer such as.
With the specific example you gave, you can trivially get the effect you wan with:
gulp.src('source/singletonComponents/images/icons/**/*.+(png|jpg|gif|svg)')
.pipe(gulp.dest('dest/pictures/icons'));
The pattern above changes what is stored in the relative field of the files. They are now all relative to source/singletonComponents/images/icons/, which allows you in gulp.dest to alter the path to get the result you want.
If your real situation is more complicated you can manipulate the paths yourself through pipe:
const gulp = require("gulp");
const map = require("map-stream");
const path = require("path");
gulp.task("default", () =>
gulp.src('source/singletonComponents/**/*.+(png|jpg|gif|svg)')
.pipe(map((file, cb) => {
file.path = path.join(file.base, file.relative.replace(/images/, "pictures"));
cb(null, file);
}))
.pipe(gulp.dest('dest')));
Note that Gulp 4 does not allow modifying file.relative directly. You get an error if you try to do it. That's because it is derived from file.base and file.path. So you have to modify one of these or both if you want to change file.relative. Remember that file.path is the absolute path of the file. That's why we joint file.base to the modified value of file.relative.

Unable to use variables in fs functions when using brfs

I use browserify in order to be able to use require. To use fs functions with browserify i need to transform it with brfs but as far as I understood this results in only being able to input static strings as parameters inside my fs function. I want to be able to use variables for this.
I want to search for xml files in a specific directory and read them. Either by searching via text field or showing all of their data at once. In order to do this I need fs and browserify in order to require it.
const FS = require('fs')
function lookForRoom() {
let files = getFileNames()
findSearchedRoom(files)
}
function getFileNames() {
return FS.readdirSync('../data/')
}
function findSearchedRoom(files) {
const SEARCH_FIELD_ID = 'room'
let searchText = document.getElementById(SEARCH_FIELD_ID).value
files.forEach((file) => {
const SEARCHTEXT_FOUND = file.includes(searchText.toLowerCase())
if (SEARCHTEXT_FOUND) loadXML(file)
})
}
function loadXML(file) {
const XML2JS = require('xml2js')
let parser = new XML2JS.Parser()
let data = FS.readFile('../data/' + file)
console.dir(data);
}
module.exports = { lookForRoom: lookForRoom }
I want to be able to read contents out of a directory containing xml files.
Current status is that I can only do so when I provide a constant string to the fs function
The brfs README contains this gotcha:
Since brfs evaluates your source code statically, you can't use dynamic expressions that need to be evaluated at run time.
So, basically, you can't use brfs in the way you were hoping.
I want to be able to read contents out of a directory containing xml files
If by "a directory" you mean "any random directory, the name of which is determined by some form input", then that's not going to work. Browsers don't have direct access to directory contents, either locally or on a server.
You're not saying where that directory exists. If it's local (on the machine the browser is running on): I don't think there are standardized API's to do that, at all.
If it's on the server, then you need to implement an HTTP server that will accept a directory-/filename from some clientside code, and retrieve the file contents that way.

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'));
});

how to debug gulp-sourcemaps not doing anything?

I have a fairly standard use case for gulp-sourcemaps
https://github.com/floridoo/gulp-sourcemaps
gulp.src( bundle.src)
.pipe(sourcemaps.init())
.pipe(concat(bundle.dst + '.' + opts.ext))
.pipe(uglify())
.pipe(sourcemaps.write())
.pipe(gulp.dest('./public/built'));
This produces appropriately concatenated and uglyified files. However there are no source map additions to them. bundle.src is an array of file paths. Not sure how to debug this.
You should look into gulp-util. It may give you some insight into what is actually happening.
var gutil = require('gulp-util')
...
.pipe(sourcemaps.init().on('error', gutil.log))
I had to specify where to write, like so:
.pipe(sourcemaps.write('./').on('error', gutil.log))
This didn't work: (no .map files generated)
.pipe(sourcemaps.write().on('error', gutil.log)

How to rename all files in a folder using gulp js?

I have a bunch of html files in a partials directory. Using gulp js, I want to minify and rename these files to .min.html. Please show me how to achieve this.
See here, using gulp-rename, if you just want to rename the files.
Something in the line of below should do:
var rename = require('gulp-rename');
gulp.src("./partials/**/*.hmtl")
.pipe(rename(function (path) {
path.suffix += ".min";
}))
.pipe(gulp.dest("./dist"));
In order to minify, you can use gulp-htmlmin. Pretty straightforward from the documentation:
var htmlmin = require('gulp-htmlmin');
gulp.task('compress', function() {
gulp.src('./partials/**/*.html')
.pipe(htmlmin())
.pipe(gulp.dest('dist'))
});
You can certainly combine the two to obtain the desired effect.

Resources