-
Notifications
You must be signed in to change notification settings - Fork 72
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
RFC: Task / Plugin Unification #291
Comments
Wow! Thank you for writing this up! This is the first RFC I've received, and it's pretty awesome 😄 Here are my initial thoughts, I may be wrong or misspeak as I go 😇 But I'll definitely be revisiting this a few times as it sinks in & I can think about it more:
I played with a similar approach before arriving at Fly 2.0. My "big idea" was to make the The only form that "worked" massively spiked in memory usage, and Taskr itself added a couple of pounds. This "final form" has been in production for a year now & has been performing exceptionally well across multiple use cases. I'm not saying "it will never change!" by any means -- however, I fundamentally disagree with (what I think is) the premise of this RFC: Plugins and Tasks are not the same thing, by design. Tasks encapsulate plugins, which then allows you to run anything within a Task under any mode or condition. And because of this, Tasks themselves are quickly portable and interchangeable. Plugins, by design, "globally" add or alter what Tasks can perform. Tasks perform and can tell others how to perform, too. Gunna interrupt myself here; but the main the point is that Tasks and Plugins are two very distinct vocabularies and therefore deserve slightly distinct definitions. This line in the sand makes & keeps it clear in discerning what-is-what... but it's also only a line in the sand, as opposed to a solid brick wall. There's still plenty of room for flexibility, extensibility, and modularity when it comes to Taskr imo. As we've both pointed out, everything presented (except Please let me know if I missed something important, or just flat-out misunderstood a point. 😆 Thank you again 🙌 |
Thanks for such a detailed response! It's always nice to get a picture into a project's philosophy, I can definitely see the wisdom in explicitly separating the concerns of tasks and plugins. I'll clean up my thoughts based on your response and dig a little deeper into the source since it seems like a good amount was existing (it may just be a matter of clearing it up in the docs). |
After thinking about it more based on your responses, what I was thinking can be boiled down to one suggested change: Allow function of string option for start, serial, and parallel This would go a long way to composing tasks without having to export everything including tasks that are not meant to be called directly. function * build(task) {
yield task.parallel([js, css]);
}
// "internal" functions
function * js(task) {}
function * css(task) {}
module.exports = {
build
}; On the question of merge, it was intended to be used in plugins like module.exports = {
name: 'merge',
every: false,
*func(files, tasks) {
// key is `this` = `task` in plugin, so chaining is available with `this.start`
// (might be able to do this with parallel, not sure what is returned though)
const results = yield Promise.all(tasks, task => this.start(task));
for (const result of results) {
// Merge result._.files/globs into this._.files/globs...
}
}
}; Great work on the library, really nice to find out most of what I was looking for was already available! |
Hey, great! That looks like something that can be done 🎉 Do you mind copy/pasting that "pass a function" bit into a new issue? We can close this & it'll be easier for tracking. Yes, that way of "merging" can be done right now. However, the Promise.all(tasks.map(task => this.start(task));
// or
Promise.all(tasks.map(this.start)) |
👍 #292 |
Thanks @lukeed and @jbucaran for your work on taskr! I wanted to present an idea I'd had on a potential API change.
Summary
This RFC presents an alternative plugin API that matches the current task API.
Unifying tasks and plugins should encourage task reuse (as plugins), simplify the overall API,
and allow a single core mental model for how taskr tasks and plugins function.
Detailed Design
Generally, a unified task or plugin has the following shape:
Bluebird.coroutine
, so all function types, including async functions and generators, are supported.Task
is returned, taskr will continue work from that task's state, allowing task chains to be created (more details below).val
approach is used, to pass values to subsequent tasks.To utilize this new approach in a semver-minor-friendly manner, plugins using the unified model are denoted with named exports and use
peerDependencies
to specify a minimum supported taskr version. This should allow changes while maintaining compatibility with the existing ecosystem.It's fairly straightforward to match existing functionality with wrapper utilities:
To accommodate this new approach, an updated form of
task.run
is introduced which runs the task/plugin directly.(see an example implementation here: example gist)
Finally, to allow chaining, tasks continue from a previous task if a
Task
is returned.In addition to allowing for chaining, this removes unexpected side effects from tasks run in succession, see #289, by returning a new task from each step rather than mutating the initial task.
Future Possibilities
This new approach allows for many interesting future possibilities, e.g. merging tasks:
Conditional tasks:
Drawbacks
While the side-effect free approach of chaining tasks may be preferred for its "correctness", it may cause compatibility issues with existing systems. Task changes will have to be approached carefully.
Alternatives
These examples are possible with the current version of taskr, but they should be much more straightforward to implement with the unified system.
The text was updated successfully, but these errors were encountered: