Gulps gulp.watch未对新文件或已删除文件触发?

154
以下是Gulpjs任务,当编辑符合 glob 匹配规则的文件时,它能够正常工作:
// watch task.
gulp.task('watch', ['build'], function () {
    gulp.watch(src + '/js/**/*.js', ['scripts']);
    gulp.watch(src + '/img//**/*.{jpg,jpeg,png,gif}', ['copy:images']);
    gulp.watch(src + '/less/*.less', ['styles']);
    gulp.watch(src + '/templates/**/*.{swig,json}', ['html']);
});

// build task.
gulp.task('build', ['clean'], function() {
    return gulp.start('copy', 'scripts', 'less', 'htmlmin');
});

然而它不能用于新的或已删除的文件(不会触发)。我是否遗漏了什么?

编辑:即使使用grunt-watch插件,似乎也无法正常工作:

gulp.task('scripts', function() {
    return streamqueue(
        { objectMode: true },
        gulp.src([
            vendor + '/jquery/dist/jquery.min.js',
            vendor + '/bootstrap/dist/js/bootstrap.min.js'
        ]),
        gulp.src([
            src + '/js/**/*.js'
        ]).pipe(plugins.uglify())
    )
    .pipe(plugins.concat(pkg.name + '.min.js'))
    .pipe(gulp.dest(dest + '/js/'));
});

gulp.task('watch', ['build'], function () {
    plugins.watch({glob: src + '/js/**/*.js'}, function () {
        gulp.start('scripts');
    });
});

编辑:已解决,原因是这个问题。以./开头的通配符(即src的值)似乎目前不起作用。


2
如果您能将接受的答案更改为Nestor Urquiza的答案,那就太好了。这是真正的答案,而不是添加其他插件。 - Justin Noel
@alexk的答案是最简单的,不需要添加gulp-watch,例如gulp.watch('js/**/*.js', {cwd: src}, ['scripts']); - Horse
7个回答

130

编辑:显然,gulp.watch现在可以使用新的或删除的文件。当问这个问题时,它还不支持。

我的其余答案仍然适用:gulp-watch通常是更好的解决方案,因为它只让您对已修改的文件执行特定操作,而gulp.watch则只能让您运行完整的任务。对于一个相当大的项目来说,后者将很快变得太慢而无法使用。


你没有遗漏任何东西。gulp.watch不支持新文件或已删除文件的监视。它是为简单项目设计的简单解决方案。

为了获取可以查找新文件的文件监视,请使用 gulp-watch 插件,该插件更加强大。使用方法如下:

var watch = require('gulp-watch');

// in a task
watch({glob: <<glob or array of globs>> })
        .pipe( << add per-file tasks here>> );

// if you'd rather rerun the whole task, you can do this:
watch({glob: <<glob or array of globs>>}, function() {
    gulp.start( <<task name>> );
});

就个人而言,我推荐第一种选择。这样可以实现更快的单文件处理。只要不将文件连接起来,在使用livereload进行开发时效果非常好。

您可以使用我的lazypipe或者使用一个函数和stream-combiner简单地包装您的流:

var combine = require('stream-combiner');

function scriptsPipeline() {
    return combine(coffeeescript(), uglify(), gulp.dest('/path/to/dest'));
}

watch({glob: 'src/scripts/**/*.js' })
        .pipe(scriptsPipeline());

更新 2014年10月15日

正如 @pkyeck 在下面指出的那样,显然 gulp-watch 的1.0版本稍微改变了格式,所以上述示例现在应该是:

var watch = require('gulp-watch');

// in a task
watch(<<glob or array of globs>>)
        .pipe( << add per-file tasks here>> );

// if you'd rather rerun the whole task, you can do this:
watch(<<glob or array of globs>>, function() {
    gulp.start( <<task name>> );
});

var combine = require('stream-combiner');

function scriptsPipeline() {
    return combine(coffeeescript(), uglify(), gulp.dest('/path/to/dest'));
}

watch('src/scripts/**/*.js')
        .pipe(scriptsPipeline());

谢谢帮忙,但还是无法正常工作。我对Gulp很陌生(之前只用过Grunt几次),也许我的主任务设置有误...不确定。请看我更新后的问题。 - gremo
18
起始于 './' 的通配符没有被触发。我的 src 变量确切地是 '-/'。找到问题了!谢谢! - gremo
1
找到那个 bug 真是太好了。希望它能帮助其他人解决同样的问题! - OverZealous
@JHannes 你在回复什么? 这个答案就是在解释这个问题。 - OverZealous
2
gulp.start 是对非公共 API 方法的调用。是否有其他执行任务的方法? - Richard Collette
显示剩余9条评论

87

gulp.watch()require('gulp-watch')() 都可以在新建/删除文件时触发,但如果使用绝对目录,则不会触发。顺便提一下,我的测试中没有对相对目录使用"./"

但是,如果整个目录被删除,则两者都不会触发。

   var watch = require('gulp-watch');
   //Wont work for new files until gaze is fixed if using absolute dirs. It  won't trigger if whole directories are deleted though.
   //gulp.watch(config.localDeploy.path + '/reports/**/*', function (event) {

   //gulp.watch('src/app1/reports/**/*', function (event) {
   // console.log('*************************** Event received in gulp.watch');
   // console.log(event);
   // gulp.start('localDeployApp');
   });

   //Won't work for new files until gaze is fixed if using absolute dirs. It  won't trigger if whole directories are deleted though. See https://github.com/floatdrop/gulp-watch/issues/104
   //watch(config.localDeploy.path + '/reports/**/*', function() {

   watch('src/krfs-app/reports/**/*', function(event) {
      console.log("watch triggered");
      console.log(event);
      gulp.start('localDeployApp');
   //});

2
优秀而简洁的回答。 - Subtubes
3
是的,许多关于gulp的示例都在其路径中以“./”开头,实际上这似乎是不好的做法。参考链接:https://github.com/floatdrop/gulp-watch/issues/1 - rmorse
1
谢谢你。我刚刚在费尽心思地尝试让 gulp-watch 正常工作,以便在新文件或删除文件时触发。不需要了!gulp.watch 可以这样做。从路径中删除所有的 ./ 解决了问题。太棒了。 - The Qodesmith
2
这可能是正确的答案 - 我不想安装另一个插件来观看。从所有的全局通配符中删除了“./”,完美地解决了问题!谢谢! - 0Neji
1
这是最佳答案,无需额外的模块或理解疯狂的语法。 - realappie
显示剩余2条评论

57
如果 src 是一个以 / 开头的绝对路径,你的代码将无法检测到新创建或删除的文件。但是还有一种方法:
而不是:
gulp.watch(src + '/js/**/*.js', ['scripts']);

撰写:

gulp.watch('js/**/*.js', {cwd: src}, ['scripts']);

它会起作用的!


12
{ cwd: src } 这个提示是我的解决方案。非常感谢! - wiredolphin
1
非常感谢 @alexk,{ cwd: src } 解决了我的问题。 - kaxi1993
@DanielTonon 你是不是误把它放在文件数组里了?应该直接作为“watch”的参数。 - Horse
4
好的。为了进一步补充,如果你不想更改每个glob模式,只需添加{cwd:'./'},并保持glob模式不变,那么它将变为gulp.watch('src/js/**/*.js', {cwd: './'}, ['scripts']); - Aakash
它适用于新文件,但对于已删除的文件不起作用。 - shuangwhywhy
显示剩余2条评论

7

必须指定Globs的单独基本目录,并且该基本位置不得在glob本身中指定。

如果您有lib/*.js,它将在当前工作目录下查找,即process.cwd()

Gulp使用Gaze来监视文件,在Gulp API文档中,我们可以看到我们可以向watch函数传递Gaze特定选项:gulp.watch(glob[, opts], tasks)

现在在Gaze文档中,我们可以找到当前工作目录(glob基本目录)是cwd选项。

这就引导我们来看alexk的答案:gulp.watch('js/**/*.js', {cwd: src}, ['scripts']);


3
我知道这是一个较旧的问题,但我想分享我想出的解决方案。我找到的所有gulp插件都无法通知我有新文件或已重命名的文件。因此,最终我将monocle封装在一个方便的函数中。

以下是该函数的使用示例:

watch({
    root: config.src.root,
    match: [{
      when: 'js/**',
      then: gulpStart('js')
    }, {
      when: '+(scss|css)/**',
      then: gulpStart('css')
    }, {
      when: '+(fonts|img)/**',
      then: gulpStart('assets')
    }, {
      when: '*.+(html|ejs)',
      then: gulpStart('html')
    }]
  });

我应该指出,gulpStart也是我制作的一个便利函数。
这里是实际的监视模块。
module.exports = function (options) {
  var path = require('path'),
      monocle = require('monocle'),
      minimatch = require('minimatch');

  var fullRoot = path.resolve(options.root);

  function onFileChange (e) {
    var relativePath = path.relative(fullRoot, e.fullPath);

    options.match.some(function (match) {
      var isMatch = minimatch(relativePath, match.when);
      isMatch && match.then();
      return isMatch;
    });
  }

  monocle().watchDirectory({
    root: options.root,
    listener: onFileChange
  });
};

相当简单,对吧?整个东西可以在我的gulp起始套件上找到:https://github.com/chrisdavies/gulp_starter_kit

1
嘿,伙计,还没有足够的人为此点赞!它像魔法一样运行良好,非常感谢你。答案省略了“gulpStart”的功能,因此可能会令人困惑,如果有人感兴趣,请访问链接并转到“utils”文件夹。 - Augie Gardner

1
重要提示:看起来 gulp.watch 在 Windows 系统上只报告更改和删除的文件,但默认情况下会在 OSX 系统上监听新建和删除的文件。

https://github.com/gulpjs/gulp/issues/675


0

在处理新建、重命名或删除的文件时,应该使用 'gulp-watch' 而不是 gulp.watch。

var gulpwatch = require('gulp-watch');
var source = './assets',  
destination = './dest';
gulp.task('copy-changed-assets', function() {
    gulpwatch(source+'/**/*', function(obj){
        gulp.src( obj.path, { "base": source})
        .pipe(gulp.dest(destination));
    });
});

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