lukeed / taskr

A fast, concurrency-focused task automation tool.
MIT License
2.53k stars 75 forks source link

Why Fly? #3

Closed quangbuule closed 7 years ago

quangbuule commented 9 years ago

Can you please tell me why I would use Fly? I am using gulp now. Thanks.

riston commented 9 years ago

The main difference is code style, in Gulp you use the streaming concept and in Fly this done using the generators and promises ?

ghost commented 9 years ago

@riston Correct.

@quangbuule Thanks for the question. Fly is still a newborn, and there are many plugins that need to be written as well as improvements to make, but here are some of Fly features:

Currently tasks are generators powered by a macro co-routine. You can yield your own async functions that return promise/s while still having the flexibility of creating pipeline sequences with filters and transformers. Out of the box.


Further Reading

Fly does make some opinionated assumptions (concat, watch, clear, etc, are all built-ins), however, it is definitely not a magical system.

If you looked at the Flyfile and thought it was magical, is because you have been coaxed into believing build files have to be in a certain way. Fyfiles are simple because Fly's API model is based on the powerful idea of promises.

Some convenient default behavior like loading your imported fly-* plugins automatically and watching over the default task (if you don't specify which tasks to watch) does add some sugar, but this is not set in stone, if the community does not like this, it can go away.

I will limit the debate to gulp, arguably the most popular build system out there in the node community. Other systems like Grunt that favor configuration over code, let's not discuss this time.

Some people praise gulp for using streams, but streams are also a complex abstraction. There are transform wrappers out there like through and may I pitch in my own kthulhu that help, but I find having to deal with all this when writing gulp plugins dreadful. Fly has no additional abstractions like vinyl either, which one needs to know at some point if you are writing non trivial plugins.

But I think most plugins should be straightforward wrappers for whatever utilities you are trying to incorporate into the build system. A build system should deal with the complexity of streams, promises, processes, you name it, for me, and even in large systems my build tasks should be no more than one page, because if you end up doing too much, you may as well automate your tasks with shell / npm scripts.

Now, in Fly, sometimes you don't even have to write a plugin, just wrap your transformer function with Fly.prototype.filter (or Fly.prototype.defer if you have an async function):

exports.map = function* () {
  yield this
    .source("strings/*.txt")
    .filter((s) => s.toUpperCase())
    .filter((s) => s.split("").reverse().join(""))
    .target("strings/out")
}

Complexity is hard to measure, but...

Not trying to cause any discord here, so take the following with a grain of salt, gulp-mocha is ~ 60 LOC + several dependencies, on the other hand fly-mocha is less than 15 LOC and just the one necessary dependency, it's also written in ES5 (slightly more verbose than ES6) and still likely to get simpler. Definitely, not a perfect comparison, but it hints at something.

One more thing I am proud of Fly is that it favors a functional coding style, whereas gulp is flat out the king of imperative code with callbacks and plenty of mutation. I try to avoid let, using const instead and the assignment operator = only for initialization. There are no for, while, break, and mutation is scarce. Current plugins follow this convention as well, although there is still room for improvement.

Another thing is that while gulp is indeed spot on with the streaming metaphor, there are tasks like code analysis, linting, testing, etc., that do not fit this reasoning as well as transforms do. Once again, take gulp-mocha as an example:

var gulp = require("gulp"), mocha = require("gulp-mocha")

gulp.task("default", function () {
    return gulp.src("test.js", { read: false }).pipe(mocha({ reporter: "dot"}))
})

Here is how you roll with Fly:

exports.default = function* () {
  yield this.source("test").mocha({ reporter: "dot" })
  // yield another.promise
}
adriancooney commented 9 years ago

Great write up! I've been looking for new build system because gulp-* installations take an insane amount of time with an obscene amount of dependencies.

Quick question, if were using ES6 here, why not the use it's module system? Instead of:

exports.default = function* () {
   // ...
}

Why not:

export default function *() {
   // ...
}

// And
export function myTask* () {
   // ...
}
quangbuule commented 9 years ago

@adriancooney modules is not supported on node.js yet.

ghost commented 9 years ago

tl;dr

While Fly is itself written in ES6, it does not require you to use ES6, but you could.

@adriancooney Sure! If you are already using ES6 that is, but since Fly also supports node >= 11 I decided to write the documentation in ES5 first.

Do notice that ATM there is no builtin support for this, so you need to transpile your Flyfile with Babel for example. Having this feature out of the box would be kind of nice though and its implementation would be trivial as well...

Roadmap!!

adriancooney commented 9 years ago

@quangbuule, @bucaran I see now, that was actually quite a silly question! Great job on this guys, looks great. I'll be giving it a shot in my next project.

ghost commented 8 years ago

Unlocking this issue. If anyone has any questions regarding Fly's philosophy, goal, purpose and whether it deserves to be taken seriously or whatnot, please leave your comments / thoughts below.

polarathene commented 8 years ago

@bucaran This was a useful issue to read through, especially your detailed answer. Perhaps link to it or a blog post covering "Why Fly" or "Fly vs Gulp", it would be interesting to see how a full featured Gulp 4 vs Fly file compares. Perhaps there are some projects with large/complicated Gulp tasks that Fly can shine in comparison too, much like how Gulp did to Grunt.

vedam commented 8 years ago

hey, first of all, thx for fly, I'm totally thrilled. After an odysee through trial-n-error (grunt, gulp, jspm, browserify and what-not) it took me under 5min with your examples, to get a 'scss-src to css-out incl. watching' done. It was a breeze and it's fast. Don't tell us, there's no magic behind ;-)

Unfortunately now I got stucked with the babel-example from the examples-folder:

  - SyntaxError: bar.js: Unexpected token (1:6)
  - > 1 | async function later () {
  -     |       ^
  -   2 |   await new Promise((cb) => setTimeout(cb, 1000));
  -   3 | }

any help appreciated.

In any case. I'll keep on building with fly. Ease of use from my scss-experience convinced me. No more words needed and more important, no googling through the dev-jungle. ;-) And I really believe, I'll get this babel-thing done. Fortunately I saved an immense amount of time on the scss-part ;D

cheers achim

ghost commented 8 years ago

@vedam Thanks. Can you confirm any examples work at all? What about the babel sample?

vedam commented 8 years ago

@bucaran As described above. I installed fly global: npm install -g fly and it took me under 5min with the css-sample to got it working with scss

Then I tried the babel-sample: copied the folder and inside done the: npm install

as I tried fly I've got the error you'll see above. I've changed nothing on the files. Just the babel-sample as is.

don't want to pollute comments with the whole error msg: https://gist.github.com/vedam/05399162295984f315ab

thx in advance

lukeed commented 7 years ago

Closing because is outdated & should be answered by Readme content