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
файл. Это изменяет протокол сохранения по умолчанию, чтобы сделать только одно редактирование исходного файла.
Другими словами, протокол сохранения по умолчанию выглядит следующим образом:
- Запишите буфер в файл резервной копии
- Удалить оригинальный файл
- Переименуйте резервную копию в имя исходного файла
И добавление set nowritebackup
просто заменяет оригинальный файл при сохранении. Этот протокол существует для снижения риска потери данных в случае ошибки ввода-вывода при сохранении.
Это сработало для меня
.pipe(watch('/**/*.less', { awaitWriteFinish: true }))
Вы должны иметь возможность использовать 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);
});