GULP: Modify a watched file in place without causi

2019-04-11 23:26发布

问题:

Im trying to use gulp and jscs to prevent code smell. I also want to use watch so that this happens when ever a change is made. The problem I'm running into is jscs is modify the source file that is being watched. This causes gulp to go into an infinite loop of jscs modifying the file and then watch seeing the change and firing off jscs again and again and again ...

const gulp = require('gulp');

gulp.task('lint', function() {
    return gulp.src('/src/**/*.js')
        .pipe(jscs({
            fix: true
        }))
        .pipe(jscs.reporter())
        .pipe(gulp.dest('/src'));
});

gulp.task('watch', function() {
    gulp.watch('/src/**/*.js', ['lint']);
});

回答1:

It's generally a bad idea to override source files from a gulp task. Any Editors/IDEs where those files are open might or might not handle that gracefully. It's generally better to write the files into a separate dist folder.

That being said here's two possible solutions:

Solution 1

You need to stop the gulp-jscs plugin from running a second time and writing the files again, thus preventing the infinite loop you're running into. To achieve this all you have to do is add gulp-cached to your lint task:

var cache = require('gulp-cached');

gulp.task('lint', function() {
  return gulp.src('/src/**/*.js')
    .pipe(cache('lint'))
    .pipe(jscs({
        fix: true
    }))
    .pipe(cache('lint'))
    .pipe(jscs.reporter())
    .pipe(gulp.dest('/src'));
});

The first cache() makes sure that only files on disk that have changed since the last invocation of lint are passed through. The second cache() makes sure that only files that have actually been fixed by jscs() are written to disk in the first place.

The downside of this solution is that the lint task is still being executed twice. This isn't a big deal since during the second run the files aren't actually being linted. gulp-cache prevents that from happening. But if you absolutely want to make sure that lint is run only once there's another way.

Solution 2

First you should use the gulp-watch plugin instead of the built-in gulp.watch() (that's because it uses the superior chokidar library instead of gaze).

Then you can write yourself a simple pausableWatch() function and use that in your watch task:

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

function pausableWatch(watchedFiles, tasks) {
  var watcher = watch(watchedFiles, function() {
    watcher.close();
    gulp.start(tasks, function() {
      pausableWatch(watchedFiles, tasks);
    });
  });
}

gulp.task('watch', function() {
  pausableWatch('/src/**/*.js', ['lint']);
});

In the above the watcher is stopped before the lint task starts. Any .js files written during the lint task will therefore not trigger the watcher. After the lint task has finished, the watcher is started up again.

The downside of this solution is that if you save a .js file while the lint task is being executed that change will not be picked up by the watcher (since it has been stopped). You have to save the .js file after the lint task has finished (when the watcher has been started again).