gulp-exec icon indicating copy to clipboard operation
gulp-exec copied to clipboard

Support function arguments

Open perrin4869 opened this issue 5 years ago • 7 comments

Sometimes the command to execute depends on state other than the filename. For example, you might want to execute different commands if the target file already exist or if it doesn't. The current template format does not allow for this kind of usage. One simple solution to support this usage is that exec accept a function:

gulp.src(myfiles)
  .pipe(
    exec(file => accessAsync(file.path, F_OK)
      .then(() => 'command to execute if file exists')
      .catch(() => 'command to execute if file does not exist'))
  );

I can put together a PR to support this over the weekend.

perrin4869 avatar Jan 30 '20 17:01 perrin4869

It looks like you're looking for gulp-if

robrich avatar Jan 31 '20 03:01 robrich

hm... yup totally missed it, what I wrote above can be done with gulp-if (using accessSync of course). Wouldn't it be a stronger API, however, if exec accepted a function instead of a loadash template (and additionally, the function could return a Promise).

perrin4869 avatar Jan 31 '20 16:01 perrin4869

It totally would, but arguably that breaks gulp-exec's "do one thing". I suspect we're quickly reaching the point where you've outgrown gulp-exec. Here's another strategy:

const through = require('through2');

gulp.task('task', function () {
  return gulp.src('/path/to/*.files')
    .pipe(through.obj(function (file, enc, callback) {
      const self = this;
      if (file.stat.isFile()) {
        exec('some-command', function(err, stdout, stderr) {
          this.push(file);
          callback();
        });
      } else {
        exec('other-command', function (err, stdout, stderr) {
          this.push(file);
          callback();
        });
      }
    }))
    .pipe(gulp.dest('/path/to/dist');
});

... granted this gets really cool when using async/await rather than callbacks. :D

robrich avatar Jan 31 '20 17:01 robrich

Hm... interesting that you say that it breaks gulp-exec do one thing. I see that gulp-exec dates all the way back to 2013, which explains the choice of the now awkward-looking lodash template. Removing the lodash dependency and leaving interpolation up to the user (who will, presumably, use ES6 backtick) makes gulp-exec lighter and more "do one thing". Adding support for async commands in the form of Promise would be a nice simple bonus, since most libs support this by now. It is unfortunate though that through2 still only has a callback based api though haha

perrin4869 avatar Jan 31 '20 18:01 perrin4869

Good point. Arguably all of gulp is "legacy". I typically don't use gulp directly anymore, leveraging Webpack instead. For the rare case where I do need to pipe files through a process I use vinyl-fs and through2, then after the last thing, I turn the stream into a promise using stream-promise, stream-to-promise, or this simple fn and then await it.

function waitStreamDone(stream) {
  return new Promise((resolve, reject) => {
    stream
      .on('error', reject)
      .on('end', resolve)
      .on('finish', resolve);
  });
}

robrich avatar Feb 01 '20 01:02 robrich

Well, gulp still has its place in 2020, doesn't it? It is a general task runner after all, you do not need to run streams on it necessarily. webpack provides an easy solution to bundle a website, but what about other applications, for example, something like electron? Or what if you do not want to use webpack, but are like me and want to build all parts of the application separately with rollup, postcss, minify images, manage gettext files (for which I want to use this plugin btw), etc. What do you think about a major version of gulp-exec that accepts either a plain string command, or a function (file: VinylFile) => String? Adding promise support, now that I think about it, is not critical, because most fs functions have a sync version anyways. Although there is probably some use-case for them.

perrin4869 avatar Feb 01 '20 14:02 perrin4869

Check out gulp-exec 5.0.0. It removes lodash templates and uses a sync function for resolving the command.

robrich avatar Jun 10 '20 20:06 robrich