能否使用 Gulp 覆盖所有的源文件?

31

假设我想替换许多位于子目录中的文件中的版本号。我将通过gulp-replace将这些文件传输到正则表达式替换函数中;但我最终会希望覆盖所有原始文件

任务可能看起来像这样:

gulp.src([
    './bower.json',
    './package.json',
    './docs/content/data.yml',
    /* ...and so on... */
  ])
  .pipe(replace(/* ...replacement... */))
  .pipe(gulp.dest(/* I DONT KNOW */);

那么我该如何结束它,使每个src文件只会覆盖自己原来的位置呢?我是否可以传递一些参数给gulp.dest()来实现这一点?


你想要更改的文件是 .json 文件吗?还是纯文本文件?你可以为你想要更改的每个文件运行 gulp.src(<one file>)... - Gntem
1
是的,但这正是我想避免的:为每个单独的文件指定gulp.src()并将每个文件都通过自己的regex-replace管道处理。相反,我想使用一组globbing模式。 - davidtheclark
你可以使用 gulp-if 来实现某些功能,但只要源文件不在同一个文件夹中,我认为你无法在一次调用中实现这个。 - Gntem
4个回答

40
我可以想到两种解决方案:
  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);
    

3
#1 对我很有用!谢谢。看起来在Gulp文档中没有解释,是吧? - davidtheclark
6
你是正确的。base 选项来自于 glob-stream 包,该包又来自于 vinyl-fs 包,而所有这些都属于 gulp.src。追踪起来不容易。 - OverZealous
1
哦,我的上帝啊,如果新建的内容比文件先前的数据短,那么旧内容的结尾将会留在文件中。换句话说,在写入之前不会截断文件。 - flq

15

告诉gulp将文件写入到所在的基础目录,就像这样:

    .pipe(
        gulp.dest(function(data){

            console.log("Writing to directory: " + data.base);
            return data.base;
        })
    )

(数据参数是vinyl文件对象

这种方法的优点在于,如果您有来自多个源的文件,每个文件嵌套在文件结构的不同层级中,这种方法允许您正确地覆盖每个文件。(与在管道链的上游设置一个基本目录相反)


得爱那些未记录的功能!https://github.com/wearefractal/vinyl-fs/blob/5572793954b63e1ec00983bad716af01e02476ef/lib/prepareWrite.js#L19-L26 - jedmao
1
谢谢你!我已经到处寻找了! - Ash Clarke

0

如果你正在使用 gulp-rename,这里有另一个解决方法:

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");

如果您想要源文件和目标文件都是绝对路径,

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");

0

我不确定为什么有些人会把它复杂化,但只要在你的目标路径前加上"./"就可以了。

比如路径是'dist/css',那么你可以这样使用:.pipe(gulp.dest("./dist/css"));

就是这样,我在我的每个项目中都使用这种方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接