简体   繁体   English

Gulp.js,保存文件时监视任务运行两次

[英]Gulp.js, watch task runs twice when saving files

Given the following piece of code from my gulpfile.js, everytime I save or change a file, the task runs twice instead of one single time, why is that? 鉴于我的gulpfile.js中的以下代码,每次保存或更改文件时,任务运行两次而不是一次,为什么? I just want it to run one time. 我只想让它运行一次。

var gulp = require('gulp');

gulp.task('default', function() {

  gulp.watch('server/**/*.js', function(){
    console.log('This runs twice everytime I change/save a javascript file located at server/**/*.js');
  }); 

});

I have also experienced the same with grunt and the plugin called grunt-contrib-watch. 我也经历了与grunt和插件grunt-contrib-watch相同的经历。

The problem is occurring because your editor, in this case Coda 2, is modifying the file twice on save. 问题出现了,因为您的编辑器(在本例中是Coda 2)在保存时将文件修改两次。 The same problem occurs in vim because of how vim creates buffer backups on save . vim中出现同样的问题,因为vim 在保存时如何创建缓冲区备份

The solution to the problem in vim is to add 在vim中解决问题的方法是添加

set nowritebackup

to your ~/.vimrc file. 到你的~/.vimrc文件。 This changes the default save protocol to only make one edit to the original file. 这会将默认保存协议更改为仅对原始文件进行一次编辑。

In other words, the default save protocol is as follows: 换句话说,默认保存协议如下:

  1. Write the buffer to the backup file 将缓冲区写入备份文件
  2. Delete the original file 删除原始文件
  3. Rename the backup to the name of the original file 将备份重命名为原始文件的名称

And adding set nowritebackup simply replaces the original file on save. 添加set nowritebackup只需在保存时替换原始文件。 This protocol exists to reduce risk of data loss in the event of an I/O error on save. 此协议用于在保存时发生I / O错误时降低数据丢失的风险。

I add the same problem in Espresso and you can "fix" it in Gulp by using the debounceDelay option like this : 我在Espresso中添加了相同的问题,您可以使用debounceDelay选项在Gulp中“修复”它,如下所示:

gulp.watch('/**/*.less', {debounceDelay: 2000}, ['less']);

That did the trick for me. 这对我有用。 But it's a pain to add it to every gulp.watch I don't know if we can put this option globaly... 但是将它添加到每个gulp.watch是一个痛苦我不知道我们是否可以将这个选项全局...

This worked for me 这对我有用

.pipe(watch('/**/*.less', { awaitWriteFinish: true }))

https://github.com/paulmillr/chokidar#api https://github.com/paulmillr/chokidar#api

You should be able to use gulp-batch to batch the changes, since it has a debounce option. 您应该能够使用gulp-batch批量更改,因为它具有debounce选项。

Something like this: 像这样的东西:

gulp.src(['server/**/*.js'], batch({debounce: 50}, function(events) {
    return events
        .pipe(...); // your code here
}));

Hint: the debounce parameter only works for the SAME file/event. 提示:debounce参数仅适用于SAME文件/事件。 If multiple events/files change, it won't help. 如果多个事件/文件发生变化,则无济于事。 Sometimes (eg I copied files into the a directory being served by my local server) gulp-cached might help, sometimes excluding certain files/patterns (eg the sourcemaps files) might help (use ! to negate the selection). 有时(例如我将文件复制到我的本地服务器所服务的目录中) gulp-cached可能有所帮助,有时排除某些文件/模式(例如源映射文件)可能会有所帮助(使用!来否定选择)。 eg 例如

gulp.watch(['js/**/*', '!js/**/*.map'])

我看到了类似的问题,但这是因为在多个标签/窗口中打开了页面。

One year later ... 一年之后 ...

Using 运用

  • nodejs 0.10.25 nodejs 0.10.25
  • gulp 3.8.10 吞咽 3.8.10

Gaz debounceDelay option did not change anything for me, neither did I understand how to use gulp-batch callback argument :/ ... Gaz debounceDelay选项对我没有任何改变,也没有理解如何使用gulp-batch回调参数:/ ...

To avoid consecutives task calls after several files have been changed, I used the oldschool setTimeout function: 为了避免在几个文件被更改后连续的任务调用,我使用了oldschool setTimeout函数:

// ...
var
SRC = ['js/*.js', '!js/*.min.js'], DEST = 'js',
processJs = function(){
    util.log('Processing: ['+ SRC.join(' | ') +']');
    var stream = gulp.src(SRC)
        .pipe(uglify())
        .pipe(concat('scripts.min.js'))
        .pipe(gulp.dest(DEST));
    return stream;
};


gulp.task('default', function(){
    var delay = 2000, timer,
        watcher = gulp.watch(
            SRC,
            // Callback triggered whatever the event type is (added / changed / deleted)
            function(event) { // .path | .type
                // If the timer was assigned a timeout id few time ago..
                // Prevent last postpone task to be run
                if(timer){
                    clearTimeout(timer);
                }
                // Postpone the task
                timer = setTimeout(
                    function(){processJs();timer=0;}
                    ,delay
                );
            }
        );
    util.log("/!\\ Watching job "+ Array(25).join('~'));
});

Had the same issue and it turns out, that gulp-sourcemaps causes it (see -> Using source maps causes task to run twice ) 有相同的问题,事实证明,gulp-sourcemaps导致它(请参阅 - > 使用源映射导致任务运行两次

Get a solution with gulp-notify and the attribute onLast: 使用gulp-notify和属性onLast获取解决方案:

.pipe(notify({message: 'YOUR MESSAGE', onLast: true}));

Seems like the answer to this question is a feature of the editor that was used, Coda 2. Based on some of the comments here and testing with multiple editors, it seems like Coda 2 saves a temporary file or similar and that causes the gulp watch function to be run twice. 似乎这个问题的答案是使用的编辑器的一个功能,Coda 2.基于这里的一些评论和多个编辑器的测试,似乎Coda 2保存了一个临时文件或类似的,这导致gulp手表功能要运行两次。

I have not found a viable solution to this when using Coda 2, ended up with switching to Sublime Text 3. 在使用Coda 2时,我没有找到可行的解决方案,最终切换到Sublime Text 3。

Aside from editor specific solutions, I wrote a little gulp plugin that solves the problem. 除了编辑器特定的解决方案,我写了一个小gulp插件,解决了这个问题。 You can use gulp-debounce like so: 你可以像这样使用gulp-debounce

npm install --save-dev gulp-debounce

var debounce = require('gulp-debounce'),
    watch    = require('gulp-watch'),
    through  = require('through2');

gulp.watch('server/**/*.js')
.pipe(debounce({ wait: 1000 }))
.pipe(through.obj(function(vinyl) {
  console.log("this won't fire multiple times in 1000ms", vinyl.path);
});

I write here my experience, maybe helps someone. 我在这里写下我的经历,也许可以帮助别人。 This cost me 1 week to detect. 这花了我一个星期的时间来检测。 I made every possible debug. 我做了所有可能的调试。 Removed files, reinstalled clean node packages. 删除文件,重新安装干净的节点包。 Removed Sublime plugins. 删除了Sublime插件。 Reported as a bug to Sublime github and plugins github pages. 报告为Sublime github和插件github页面的bug。

My solution Close dropbox if open. 我的解决方案如果打开则关闭dropbox。 I use Dropbox for my project and work there. 我将Dropbox用于我的项目并在那里工作。 When Dropbox is open, tasks run twice because Dropbox detects file change and does something. 当Dropbox打开时,任务会运行两次,因为Dropbox会检测到文件更改并执行某些操作。 Specially Typescript files, i don't know why. 特别是Typescript文件,我不知道为什么。

I tried debounce and awaitWriteFinish. 我试过debounce和awaitWriteFinish。 It didn't work. 它没用。 This did: 这样做:

const gulp = require("gulp");
const exec = require('child_process').exec;
let run = false;

gulp.task("watch", () => {
  console.log("watching ..");
  gulp.watch("**/*.js", ["browserify"]);
});

gulp.task("browserify", () => {
  if (run) { return; }
  run = true;
  console.log("calling browserify");
  exec("browserify app.js -o bundle.js");
  setTimeout(() => {
    run = false;
  }, 1000);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM