60

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.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
soenguy
  • 1,332
  • 3
  • 11
  • 23

10 Answers10

58

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

Try gulp-cached instead.

nktssh
  • 2,171
  • 21
  • 23
37

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());
  });
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Brad Berger
  • 572
  • 4
  • 6
  • 2
    If you use this method, then you will have to handle the relative destination path of the file yourself, because gulp doesn't do itself.. at least it works at end :) – Manuel Di Iorio Oct 27 '15 at 19:52
  • 1
    This is perfect. I just needed the pattern to edit only specific files which get changed. – mythicalcoder Apr 17 '17 at 09:08
  • 1
    It's so weird that the gulp website [says](https://gulpjs.com/docs/en/getting-started/watching-files/#using-the-watcher-instance), "You likely won't use this feature," when it seems really useful. I wish they wouldn't do that. Makes it seem like I shouldn't use it. – General Grievance Feb 18 '22 at 16:26
21

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'));
});
lofihelsinki
  • 2,491
  • 2
  • 23
  • 35
9

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);
}
mark.monteiro
  • 2,609
  • 2
  • 33
  • 38
3

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

dman
  • 10,406
  • 18
  • 102
  • 201
1

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());
});
urban_raccoons
  • 3,499
  • 1
  • 22
  • 33
1

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.

Kevinleary.net
  • 8,851
  • 3
  • 54
  • 46
  • 1
    This is the most straight-forward answer, and it doesn't rely on processing every file and comparing with a cached version. Thanks! – Allen Jun 21 '19 at 18:12
0

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');
  }
};
luis19mx
  • 393
  • 4
  • 6
0

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);
}
mark.monteiro
  • 2,609
  • 2
  • 33
  • 38
0

I found my solution for a similar issue with on change event using changedFilePath variable. (gulp v4.0.2)

I have .js for each .cshtml page in .net core. and I want to minify them all in a single folder with the same name on change.

"use strict";
var gulp = require("gulp"),
  jsmin = require("gulp-terser"),
  rename = require('gulp-rename'),
  changedFilePath = '';


/* Gulp to minify JS files */
gulp.task("minify-js", function () {
  return gulp.src(changedFilePath)
    .pipe(jsmin())
    .pipe(rename(function (path) {
      path.basename = path.basename.replace('.cshtml', '.min').toLowerCase();
    }))
    .pipe(gulp.dest("wwwroot/bundle/dist/js/pages"));
});

gulp.task('default', function () {
  gulp.watch("Views/**/*.cshtml.js").on('change', function (filepath) {
    changedFilePath = filepath;
    gulp.series('minify-js')();
    return
  });
});
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Madhav
  • 1
  • 3