Allow a turbo task to define its own script/command #10654
ethanresnick
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Goals
I love turbo but, ironically, as one starts to rely on turbo more and more, the interaction between tasks defined in turbo and package.json scripts gets less and less ergonomic. (See background below.)
Prior to the introduction of turbo Package Configurations, reading a task's script from
package.jsonwas essential, as it was the only way for each package to customize the task's behavior. Now that Package Configurations exist, though, there's an opportunity to majorly simplify the interaction between turbo, the package manager, and their separate config files.Non-goals
No response
Background
As a project leans on turbo more and more, here's what happens:
Many
package.jsonscripts end up being of little use to run directly (i.e. without turbo), because they're written to assume that turbo will have already run the tasks they depend on. Someone trying to run the package.json script through their package manager would need to know all its dependencies, which are usually documented only in the turbo config and change over time. So these scripts live in package.json, but are really only useful to turbo.Meanwhile, even for a
package.jsonscript that could be run effectively without turbo — because no turbo tasks depend on it, and it depends on no turbo tasks — it ends up being useful to add the script intoturbo.jsonas a task with an empty task config (e.g.,"some-leaf-task": {}). Doing that simplifies the developer's local workflow, because it lets them run everything through turbo — rather than having to run some tasks through turbo, some through their package manager, and having to keep track of tasks should be run in which way. Running even these leaf tasks through turbo is also more future-proof and makes for more stable docs, because, if the task later does need to depend on some task, developers won't have to change their workflows to start running the task through turbo instead of through their package manager.Finally, some important turbo tasks end up without a corresponding script in
package.json. For example, a package'sdevtask in turbo might be defined to run two commands in parallel (e.g."with": ["a:watch", "b:watch"]), but there wouldn't be a"dev"script inpackage.json.Given all this, a dev team can choose to always add every
package.jsonscript as a turbo task, and then always run all commands via turbo. However, that results in a lot of duplication/syncing between the two config files.Alternatively, if not every script is added as a turbo task, devs must look in both
package.jsonandturbo.jsonto see the full list of available tasks (point three above), and be prepared to switch which tasks they run through turbo and which tasks they don't as task dependencies evolve. (I.e., if a task is defined in turbo, always run it through turbo; otherwise, run the corresponding script through the package manager.)Both options are a bit annoying.
Proposal
I propose adding a
"command"key to each turbo task's definition; if present, turbo will run this key's command instead of anypackage.jsonscript.It would probably be ideal for the command to execute as though it were a package.json script being run by the package manager (i.e., so it would have access to binaries from installed packages, etc.), but I don't think this is necessary.
By adding such a key to a task's config, it should be possible for a package to remove all of its package.json scripts and simply rely on the package-specific
turbo.json.turbo.jsonbecomes a superchargedpackage.jsonthat defines not just the scripts but also the graph information needed to orchestrate them.Small example with my proposal:
Without this proposal, we'd have:
As you can see, the solution without this proposal:
turbo.jsonneeds a dummy, empty task forlint:eslint.linttask doesn't have apackage.jsonscript; a developer can only discover it by also looking inturbo.json.db:migrateandlint:db:schemalinttasks exist in package.json, but can't actually be run successfully through the package manager alone unless the developer knows their (current) dependencies.Assuming the root
turbo.jsoncan also define a task's"command", which would get inherited just like anything else, then this also solves the concerns aboutpackage.jsonscript duplication that have been raised in prior discussions. But I see that as a bonus.The biggest thing here, imo, is that devs shouldn't have to know when to run a task through turbo and when to use their package manager, and making everything runnable through turbo shouldn't require arbitrarily duplication.
Beta Was this translation helpful? Give feedback.
All reactions