Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Async file transformers #112

Open
teehemkay opened this issue Apr 29, 2016 · 13 comments
Open

Feature request: Async file transformers #112

teehemkay opened this issue Apr 29, 2016 · 13 comments

Comments

@teehemkay
Copy link

Unless I'm mistaken, file transformers cannot be async, right?

If that's the case, it's quite unfortunate because it means that one has to chose between async or caching but can't have both?

For example: I want to have a gobble plugin for imagemin. Since optimizing is onerous and a 1-to-1 op, I'd rather use a file transform.

But imagemin processors are async so it's a no go 😞

So this is my request for making file transformers async just like directory transformers.
I think it would make gobble much more powerful.

@Rich-Harris
Copy link
Contributor

In principle this makes a lot of sense, and I'm all for it. Tricky part is determining whether it's async or not – returning a Promise is easy enough, but for transformers that are callback-based, adding a third done argument would mean that the transformer was mistaken for a directory transformer.

So, I see a couple of potential solutions:

  1. Rather than using the function arity trick, require all plugins to be directory transformers, but have a helper for file transformers...
var fileTransformer = require( 'gobble-file-transformer' );
var myPlugin = fileTransformer( ( input, options ) => {...});

...but I'm not really a fan of this approach for lots of reasons.

  1. Never pass a done callback – instead, do something like
function myPlugin ( input, options ) {
  const done = this.async();
  doSomethingWith( input, options, done );
}

So file transformers would continue to have two arguments, and the fourth argument to directory transformers could be gradually phased out.

@fskreuz
Copy link

fskreuz commented May 5, 2016

Suggesting dropping callbacks and just use promises to be uniform in returns as well as accommodate both synchronous and asynchronous transforms. Callback-based transforms can just migrate to using promises.

function fileTransform(input, options){.
  return Promise.resolve(stuff); // The usual return values are accepted as resolution.
  return Promise.reject(error);
}

function dirTransform(input, output, options){
  return Promise.resolve(); // Not sure if stuff is needed. We're working directly on the fs.
  return Promise.reject(error);
}

@Rich-Harris
Copy link
Contributor

Trouble is a lot of libraries still use node-style callbacks, and insisting on promises means this sort of nonsense:

function myPlugin ( inputdir, outputdir, options ) {
  return new Promise( function ( fulfil, reject ) {
    legacyBullshit( inputdir, outputdir, options, function ( err, result ) {
      if ( err ) return reject( err );
      fulfil( result );
    });
  });
}

// as opposed to
function myPlugin ( inputdir, outputdir, options ) {
  var done = this.async();
  legacyBullshit( inputdir, outputdir, options, done );
}

// or even
function myPlugin ( inputdir, outputdir, options ) {
  legacyBullshit( inputdir, outputdir, options, this.async() );
}

@teehemkay
Copy link
Author

teehemkay commented May 6, 2016

👍 on proposal 2) above (using this.async). I also think it's premature to go the "promise-only" route.

@MartinKolarik
Copy link
Contributor

👍 for this.async() for the very same reason @Rich-Harris mentioned above.

@teehemkay
Copy link
Author

teehemkay commented May 6, 2016

On second thought (sorry, I'm on vacation), this.async bothers me a little bit: I'd much prefer being explicit that a transformer is async (using a callback)

How about requiring that async file transformers have transformer.defaults.async === true

This way we can still distinguish between a file transformer with a callback and a directory transformer.

@martypdx
Copy link

martypdx commented May 6, 2016

Why not disambiguate and add a different method for file transforms? Async would only be in new method, could be done in non-breaking fashion by logging deprecation warnings for use of .transform as file transformer.

@fskreuz
Copy link

fskreuz commented May 6, 2016

So we can have transformFile and transformDirectory and have new implementation on them while keeping the old transform covered with deprecation notices? Sounds good to me 👍 . We can also throw in a Promise+callback hybrid with no issues.

@martypdx
Copy link

martypdx commented May 6, 2016

@fskreuz right, but with @Rich-Harris's supreme naming skills we'd have even cooler, more obvious names like whammo and vamoose ;)

@teehemkay
Copy link
Author

Looking at the code, I see that the transform calling context already has other properties (such asthis.log, this.src and this.destamong others which maybe should be mentioned tin the docs?).

So on third thought, this.async makes more sense in this context (no pun intended)

@cprecioso
Copy link

While this is being worked out, I thought it'd be nice to have it for Promise-based transforms ASAP, as it is very simple and covers at least a percentage of this use case. Also, for imagemin (the reason @teehemkay created this issue and the reason I ended up here), that works just fine.

The PR is #124.

@teehemkay
Copy link
Author

👍

@legomind
Copy link

legomind commented Dec 1, 2016

Any chance of this happening?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants