Gulp.js, при сохранении файлов запускается двойное задание

Учитывая следующий фрагмент кода из моего gulpfile.js, каждый раз, когда я сохраняю или изменяю файл, задача выполняется дважды, а не один раз. Почему? Я просто хочу, чтобы он запускался один раз.

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

});

Я также испытал то же самое с grunt и плагином grunt-contrib-watch.

12 ответов

Решение

Похоже, что ответом на этот вопрос является особенность редактора, который использовался, Coda 2. На основании некоторых комментариев здесь и тестирования с несколькими редакторами, кажется, что Coda 2 сохраняет временный файл или аналогичный, и это заставляет глотать часы функция будет запущена дважды.

Я не нашел жизнеспособного решения для этого при использовании Coda 2, в конечном итоге с переключением на Sublime Text 3.

Я добавляю ту же проблему в Espresso, и вы можете "исправить" ее в Gulp, используя опцию debounceDelay, например так:

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

Это помогло мне. Но мне больно добавлять его в каждый gulp.watch, я не знаю, сможем ли мы включить эту опцию глобально...

Проблема возникает из-за того, что ваш редактор, в данном случае Coda 2, дважды изменяет файл при сохранении. Та же проблема возникает в vim из-за того, как vim создает резервные копии буфера при сохранении.

Решением проблемы в vim является добавление

set nowritebackup

на ваш ~/.vimrc файл. Это изменяет протокол сохранения по умолчанию, чтобы сделать только одно редактирование исходного файла.

Другими словами, протокол сохранения по умолчанию выглядит следующим образом:

  1. Запишите буфер в файл резервной копии
  2. Удалить оригинальный файл
  3. Переименуйте резервную копию в имя исходного файла

И добавление set nowritebackup просто заменяет оригинальный файл при сохранении. Этот протокол существует для снижения риска потери данных в случае ошибки ввода-вывода при сохранении.

Это сработало для меня

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

https://github.com/paulmillr/chokidar

Вы должны иметь возможность использовать gulp-batch для пакетной обработки изменений, так как он имеет debounce вариант.

Что-то вроде этого:

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

Подсказка: параметр debounce работает только для ТОГО ЖЕ файла / события. Если несколько событий / файлов изменятся, это не поможет. Иногда (например, я копировал файлы в каталог, обслуживаемый моим локальным сервером) может помочь gulp-cached, иногда может помочь исключение определенных файлов / шаблонов (например, файлов sourcemaps) (используйте!, Чтобы отменить выбор). например

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

Была такая же проблема, и оказалось, что gulp-sourcemaps вызывает ее (см. -> Использование исходных карт приводит к тому, что задача запускается дважды)

Получите решение с gulp-notify и атрибутом onLast:

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

Я видел похожую проблему, но она была вызвана тем, что страница открывалась в нескольких вкладках / окнах.

Год спустя...

С помощью

  • nodejs 0.10.25
  • глоток 3.8.10

Gaz debounceDelay опция ничего не изменила для меня, и я не понял, как использовать аргумент обратного вызова gulp-batch :/...

Чтобы избежать последовательных вызовов задач после изменения нескольких файлов, я использовал функцию 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('~'));
});

Я пишу здесь свой опыт, может быть, кто-то помогает. Это стоило мне 1 недели, чтобы обнаружить. Я сделал все возможные отладки. Удалены файлы, переустановлены чистые пакеты узлов. Удалены Sublime плагины. Сообщается как об ошибке в Sublime github и плагинах github страниц.

Мое решение Закройте Dropbox, если он открыт. Я использую Dropbox для своего проекта и работаю там. Когда Dropbox открыт, задачи запускаются дважды, потому что Dropbox обнаруживает изменение файла и что-то делает. Специально для Typescript, я не знаю почему.

Я попытался debounce и awaitWriteFinish. Это не сработало. Это сделал:

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

Помимо конкретных решений для редакторов, я написал небольшой плагин, который решает проблему. Ты можешь использовать 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);
});
Другие вопросы по тегам