31

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?

davidtheclark
  • 4,398
  • 4
  • 28
  • 42
  • the files that you want to change are `.json` files? or plaintext? you could could run `gulp.src()...` for each file you want to change. – Gntem Mar 15 '14 at 09:59
  • 1
    Yeah, but that's precisely what I want to avoid: specifying `gulp.src()` for every individual file and piping each one through its own regex-replace that is in fact the same. I'd like to use an array of globbing patterns, instead. – davidtheclark Mar 15 '14 at 13:40
  • you could work with `gulp-if` to achieve something, but as long as the source files aren't in the same folder i don't think you could achieve this in one call. – Gntem Mar 15 '14 at 14:00

4 Answers4

40

I can think of two solutions:

  1. 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.)

  2. 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);
    
lesmana
  • 22,750
  • 8
  • 73
  • 83
OverZealous
  • 38,206
  • 15
  • 95
  • 97
  • 3
    #1 worked for me! Thanks. Doesn't seem to be explained anywhere in the Gulp docs, huh? – davidtheclark Mar 15 '14 at 15:27
  • 6
    You are correct. The `base` option comes from the `glob-stream` package, which comes from the `vinyl-fs` package, which is all `gulp.src` is. It's not easy to track down. – OverZealous Mar 15 '14 at 15:52
  • 1
    oh dear lord, if the new-built content is shorter than the previous data of the file, the old content's end will stay in te file. In other words, file does not get truncated before write... – flq Aug 03 '15 at 21:10
15

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)

Yiling
  • 2,454
  • 2
  • 19
  • 27
  • Gotta' love those undocumented features! https://github.com/wearefractal/vinyl-fs/blob/5572793954b63e1ec00983bad716af01e02476ef/lib/prepareWrite.js#L19-L26 – jedmao Apr 30 '15 at 07:17
  • 1
    Thank you for this! Been looking everywhere! – Ash Clarke Feb 25 '17 at 22:27
0

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");
danyamachine
  • 1,460
  • 14
  • 21
0

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.

Mosia Thabo
  • 2,753
  • 1
  • 9
  • 21