Search code examples
gulpsharp

What is the right way to use sharp with gulp?


I am trying to convert a bunch of svgs to png. But due to the sad state of gulp-svg2png and gulp-sharp I'm evaluating other options; sharp looks promising enough.

Versions:

$ gulp --version
CLI version: 2.2.0
Local version: 4.0.2
$ node -
Welcome to Node.js v13.6.0.
Type ".help" for more information.
> require('./package.json').dependencies.sharp
'^0.24.0'

Unfortunately the following

gulp.task('svg-convert', function() {
  var sharp = require('sharp')
  gulp.src(config.svg2png)
  .pipe(sharp().png())
  .pipe(gulp.dest('./dist/images'))
});

sends this error:

TypeError [ERR_INVALID_ARG_TYPE] [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer. Received an instance of File
    at validChunk (_stream_writable.js:285:10)
    at Sharp.Writable.write (_stream_writable.js:324:23)
    ...
    (stacktrace continues)

Has someone solved this?

Or is there a better way to deal with this particular need?


Edited after @AllainLG answer.

These are my two takes. Unfortunately both are failing.

gulp.task('svg2png', function() {
  var sharp = require('sharp');
  return gulp.src(c.svg2png)
  .pipe(plug.each(function(content, file, callback) {
    var newContent = sharp(content).png(); // here content is a buffer containing the image, newContent should be too?
    // var newContent = sharp(content).png().toBuffer(); // this sends a Promise and fails
    return callback(null, newContent);
  }), 'buffer')
  .pipe(plug.rename(function(path) {
    return path.extname = ".png";
  }))
  .pipe(plug.imagemin())
  .pipe(gulp.dest('./dist/images'));
});

This pipes nothing to the destination: nothing in ./dist/images.

This second attempt uses gulp-tap.

gulp.task('svg2png2', function() {
  var sharp = require('sharp');
  return gulp.src(c.svg2png)
  .pipe(plug.tap(function(file) {
    return file.contents = sharp(file.contents).png();
  }))
  .pipe(plug.rename(function(path) {
    return path.extname = ".png";
  }))
  // .pipe(plug.imagemin()) // sends "Streaming not supported"
  .pipe(gulp.dest('./dist/images'));
});

This generates empty files in the destination (with the right names).


Solution

  • The following works, with the minor bonus of an ~100ms (average 10 complex svgs ~430ms) time improvement over gulp-svg2png (average 10 complex svgs ~540ms).

    It uses through2.

    I'll accept this answer in around a month unless someone has a better answer.

    gulp.task('svg2png', function() {
      var sharp, through2;
      sharp = require('sharp');
      through2 = require('through2');
    
      return gulp.src(c.svg2png)
      .pipe(through2.obj(function(file, _, cb) {
        return sharp(file.contents).png().toBuffer().then(function(buffer) {
          file.contents = buffer;
          return cb(null, file);
        }).catch(function(err) {
          console.error(err);
          return cb(null, file);
        });
      }))
      .pipe(plug.rename(function(path) {
        return path.extname = ".png";
      }))
      .pipe(plug.imagemin())
      .pipe(gulp.dest('./dist/images'));
    });