How to run a task ONLY on modified file with Gulp watch

GulpGulp Watch

Gulp Problem Overview


I have the current gulp task which I use in a gulpfile. Path are from a config.json and everything works perfectly:

//Some more code and vars...

gulp.task('watch', function() {
    gulp.watch([config.path.devfolder+"/**/*.png", config.path.devfolder+"/**/*.jpg", config.path.devfolder+"/**/*.gif", config.path.devfolder+"/**/*.jpeg"], ['imagemin-cfg']);
})

//Some more code ...

gulp.task('imagemin-cfg', function () {
    return gulp.src([config.path.devfolder+"/**/*.png", config.path.devfolder+"/**/*.jpg", config.path.devfolder+"/**/*.gif", config.path.devfolder+"/**/*.jpeg"], {read: false})
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngcrush()]
        }))
        .pipe(gulp.dest(buildType))
        .pipe(connect.reload());
});

But I still have an issue, the number of images in my project is huge and this task takes ages. I'm looking for a way to run my task ONLY on modified files. If I had an image or modify it, imagemin() will only run on this image, and not on all.

Once again everything is working perfectly fine, but the run time is really long.

Thanks.

Gulp Solutions


Solution 1 - Gulp

"gulp-changed" is not a best solution for doing this, because it watch only modified filed in "buildType" folder.

Try gulp-cached instead.

Solution 2 - Gulp

Another option is to used the gulp.watch on("change") option.

gulp
  .watch([config.path.devfolder+"/**/*.png", config.path.devfolder+"/**/*.jpg", config.path.devfolder+"/**/*.gif", config.path.devfolder+"/**/*.jpeg"])
  .on("change", function(path) {
      gulp
        .src(path)
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngcrush()]
        }))
        .pipe(gulp.dest(buildType))
        .pipe(connect.reload());
  });

Solution 3 - Gulp

No need for plugins, this can be achieved with just gulp.watch.

With gulp.watch, you can target the changed file like this.

gulp.watch(["src/**/*"], function (obj) {
 return gulp.src(obj.path, {"base": "src/"})
 .pipe(gulp.dest("dest"));
});

Edit: for Gulp v4.0.2 - Now fixed:

const { watch, src, dest } = require('gulp');

var watcher = watch(["src/**/*"]);
watcher.on('change', function(fileName){
    return src(fileName, {base: 'src/'})
        .pipe(dest('dest'));
});

Solution 4 - Gulp

Incremental builds are supported natively in Gulp without any plugins since version 4.0. Here is the example taken from the project README:

const paths = {
  ...
  images: {
    src: 'src/images/**/*.{jpg,jpeg,png}',
    dest: 'build/img/'
  }
}

function images() {
  return gulp.src(paths.images.src, {since: gulp.lastRun(images)})
    .pipe(imagemin())
    .pipe(gulp.dest(paths.images.dest));
}

function watch() {
  gulp.watch(paths.images.src, images);
}

Solution 5 - Gulp

May I suggest gulp-newy in which you can manipulate the path and filename in your own function. Then, just use the function as the callback to the newy(). This gives you complete control of the files you would like to compare.

This will allow 1:1 or many to 1 compares.

newy(function(projectDir, srcFile, absSrcFile) {
  // do whatever you want to here. 
  // construct your absolute path, change filename suffix, etc. 
  // then return /foo/bar/filename.suffix as the file to compare against
}

enter image description here

Solution 6 - Gulp

Yeah, gulp-changed does exactly that:

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

gulp.task('imagemin-cfg', function () {
return gulp.src([config.path.devfolder+"/**/*.png", config.path.devfolder+"/**/*.jpg", config.path.devfolder+"/**/*.gif", config.path.devfolder+"/**/*.jpeg"], {read: false})
    .pipe(changed(buildType))
    .pipe(imagemin({
        progressive: true,
        svgoPlugins: [{removeViewBox: false}],
        use: [pngcrush()]
    }))
    .pipe(gulp.dest(buildType))
    .pipe(connect.reload());
});

Solution 7 - Gulp

Here's a real-world example I use all the time to do this without the need for any additional packages. I use this to minify, rename and compile any .js file in the js directory. Compiled files are saved to a dist directory with .min appended before the extension.

// Compile JS
var compileJS = function( file ) {
	var currentDirectory = process.cwd() + '/';
	var modifiedFile = file.path.replace( currentDirectory, '' );

	gulp.src( modifiedFile )
		.pipe( uglify() )
		.pipe( rename( {
			suffix: ".min"
		} ) )
		.pipe( livereload() )
		.pipe( gulp.dest( 'dist' ) );
};

// Watch for changes
gulp.watch( 'js/*.js', [ 'js' ] ).on( "change", compileJS );

The above answers seemed partially incomplete and a little unclear to me, hopefully this is helpful for anyone else looking for a basic example.

Solution 8 - Gulp

In the task or callback, you'll have an event parameter, which has a type property, which will tell you if the file was added, deleted or changed. Best bet is to make use of that in a conditional on your task.

gulp.watch('path to watch', function(event){
  if(event.type === 'changed') { 
    gulp.start('your:task');
  }
};

Solution 9 - Gulp

Define the main task so that it accepts a parameter for the .src() input pattern. Define a wrapper function to pass a default src value for the task so that you can still call it directly like gulp images:

const imageFilePattern = '/src/path/to/input';

function images() {
  getImagesTask(imageFilePattern);
}

function imagesTask(src) {
  return gulp.src(src)
	.pipe(imagemin())
	.pipe(gulp.dest('dest'));
}

Now you can easily define the watch task to only process changed files:

function watch() {
  return gulp.watch(imageFilePattern).on("change", imagesTask);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsoenguyView Question on Stackoverflow
Solution 1 - GulpnktsshView Answer on Stackoverflow
Solution 2 - GulpBrad BergerView Answer on Stackoverflow
Solution 3 - GulplofihelsinkiView Answer on Stackoverflow
Solution 4 - Gulpmark.monteiroView Answer on Stackoverflow
Solution 5 - GulpdmanView Answer on Stackoverflow
Solution 6 - Gulpurban_raccoonsView Answer on Stackoverflow
Solution 7 - GulpKevin LearyView Answer on Stackoverflow
Solution 8 - Gulpluis19mxView Answer on Stackoverflow
Solution 9 - Gulpmark.monteiroView Answer on Stackoverflow