Search code examples
asynchronousgulpgulp-watchwebp

Gulp webp function not respecting watch command


Ok, so I am using the typical image minification process. I have functions for jpg, pngs and I have a separate function to convert those to webp.

I have the following gulpfile (only the relevant parts are here):

    function clean(done) {
      rimraf(folder.public_img, done);
    }

    function images() {
      return gulp.src([folder.preimages+'/**/*.{gif,png,jpg,svg}'])
        .pipe(cache(imagemin([
          imageminPngquant({
              speed: 1,
              quality: [0.95, 1]
          }),
          imageminZopfli({
              more: true
          }),
          imageminMozjpeg({
              quality: 65
          }),
        ])))
        .pipe(gulp.dest(folder.public_img));
    }

    gulp.task('webp', () =>
        gulp.src([folder.preimages+'/**/*.{gif,png,jpg}'])
            .pipe(webp({
                quality: 65,
                method: 6
            }))
            .pipe(gulp.dest(folder.public_img))
    );

    function serve() {
        gulp.watch(folder.preimages+"/**/*.{gif,png,jpg,svg}", images);
        gulp.watch(folder.preimages+"/**/*.{gif,png,jpg}", webp);
    }

    gulp.task('clean', clean);
    gulp.task('images', images);
    gulp.task('serve', gulp.series('clean', 'images', 'webp', serve));
    gulp.task('default', gulp.series('clean', 'images', 'webp', serve));

So, basically when I run gulp the first time, all the processes run fine and the webp images are generated. BUT, if I add a new image, the images() function runs, but for some reason the webp() function doesn't execute, it's as if it doesn't see changes, and I have it configured the same way as images.

I tried two alternatives:

  1. I added the webp process directly inside the images() function, but that way my JPG and PNG files were directly converted to webp and I didn't have fallback images.
  2. I tried to create the webp function with the same format as the others function webp() { ... }, but when I tried to run gulp it showed this error:

    The following tasks did not complete: default, Did you forget to signal async completion?

So I found that I could use the format above gulp.task('webp', () =>... and that works, but doesn't respect the watch function. I think it could be related to the function to name assignation in the end of the file, but I am not that familiar with the syntax.

What should I change so that it watches correctly?


Solution

  • I was able to recreate your code and get it to work as follows:

    In creating your gulp tasks, something goofy seems to be happening because you've created a series of tasks to run with your gulp.task('serve'). Instead, you can write out your tasks like this:

    gulp.task(clean);
    gulp.task(images);
    gulp.task(serve);
    gulp.task('default', gulp.series(clean, images, webp, serve));
    

    You may want to call your webp function something else - I was getting a conflict because of also importing gulp-webp as const = webp. You also don't need to put quotation marks around the name of the function in the task and then also reference it in the task again. So gulp.task(clean) works just fine. You don't need gulp.task('clean', clean).

    You can probably also write your default task as follows:

    gulp.task('default', gulp.series(clean, serve);
    

    This had the same effect for me as also including the images and webp tasks in the series. This setup worked for me. Running gulp, it first ran the clean function to remove the public_img folder, then ran images followed by webp. It worked up the initial run as well as when I added a new image to the preimages folder.

    Update

    Here's the complete gulpfile I got to work:

    const gulp = require('gulp');
    const imagemin = require('gulp-imagemin');
    const rimraf = require('rimraf');
    const webp = require('gulp-webp');
    
    const folder = {
      preimages: 'src/images',
      public_img: 'src/public_img',
    };
    
    function clean(done) {
      rimraf(folder.public_img, done);
    }
    
    function images() {
      return gulp
        .src([folder.preimages + '/**/*.{gif,png,jpg,svg}'])
        .pipe(imagemin())
        .pipe(gulp.dest(folder.public_img));
    }
    
    function webpTask() {
      return gulp
        .src([folder.preimages + '/**/*.{gif,png,jpg}'])
        .pipe(webp())
        .pipe(gulp.dest(folder.public_img));
    }
    
    function serve() {
      gulp.watch(folder.preimages + '/**/*.{gif,png,jpg,svg}', images);
      gulp.watch(folder.preimages + '/**/*.{gif,png,jpg}', webpTask);
    }
    
    gulp.task('clean', clean);
    gulp.task('images', images);
    gulp.task('default', gulp.series('clean', 'images', webpTask, serve));
    

    Notes: I removed the gulp serve task. I couldn't get that to work under any configuration. I think you are running into a conflict by naming both the task and the function serve, although I'm not 100% positive. I changed the webp task name to webpTask, as I was getting a conflict by naming both the webp import and the webp function webp. I didn't include any of the webp() or imagemin() configuration options, but that shouldn't matter.

    You should also be able to remove the calls for both the images and webpTask functions in the gulp default task, as running the serve function should trigger both of those.

    This setup worked for me both when adding new images to my preimages folder while the gulp default task was running as well as when restarting the gulp default task.

    FYI: I'm using gulp version 4.0.1., but I don't think that should make a difference for this.