-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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] don't spin up an intermediate process when yarn run
runs a script that yarn run
s
#3732
Comments
Indeed, it'd be a good thing. Since we parse and evaluate the scripts it should be doable, although a little tricky. Perhaps as a first step |
Ah, that's a much more clever idea. If I understand correctly, that would also allow my |
Okay, I poked around this a little bit, and it certainly seems possible, though definitely tricky. The biggest blocker I've discovered so far is A possible solution is to follow the pattern of There is also other global state to think about. For instance, if a custom plugin fiddles with, say, With these kinds of things in mind, I'd really like to get your gut feeling on this before I spend much more time on it. Do you think:
Thoughts? |
Honestly it's difficult to say 😕 I knew env would be a thorny point, and even now I'm not quite sure what's the best way to deal with it. One option that seems relatively enticing would be to use The problem is that this approach is very novel and would involve quite a bit of R&D with trial-and-error process. Should this async state be managed inside Clipanion? Or inside the shell itself? My gut feeling would tend to say that the answer is a bit of both, which sounds quite complicated. |
Interesting; I had not considered AsyncLocalStorage. It's more ergonomic than dependency-injecting I'm thinking that I may need to take a more scoped-down and/or buyer-beware approach, as the nature of the plugin architecture makes it very difficult or impossible to reason about every edge case (see: my example about I don't think I'll have time in the near future to give this another good go given what it seems to be becoming, but here are the directions I'm considering, in no particular order:
(I'm not expecting any response here, but I'd welcome any input regardless. This is primarily a list for my future self or anyone else who may become interested in picking up this feature.) |
Describe the user story
I have a monorepo with ~200 packages. I use a combination of
workspaces foreach
,npm-run-all
and common script names to do operations across the whole repo. For instance, a common pattern we have allows linting invocations to be configured per-package, which looks like:(where
g:prettier
andg:eslint
are global scripts provided by a package that wraps those tools with some configuration, etc.)This is useful when e.g. you are transitioning linters or linter configuration, but only part the project has been ported so far.
This is run as (among other ways)
yarn workspaces foreach run lint
. This spins up a LOT of processes just for this package:workspaces foreach
, which executes the selected scripts in-process, except thatnpm-run-all
is a opaque binary, which then invokes [followinglint:prettier
as an example]yarn run
puts the newyarn
on$PATH
), which sees a call to Yarn, so it spins upprettier
(Steps i-iii being repeated for ESLint as well.)
With ~200 packages, you can imagine this eats up a lot of memory for near-useless overhead (there's a surprising amount of memory used for an idle Yarn 2 in this repo, but that's another issue). I've spent some time noodling CI configuration, parallelism, etc., but ultimately these intermediates are just wasting memory and occasionally OOMing the CI machines.
Describe the solution you'd like
I think Yarn can safely and transparently collapse these invocations together, or at least, provide more-featureful hooks to allow third parties to do so.
Idea 1:
yarn run
inspects the script it's about to run. If it determines that it's going to invokerun
again, and only run, it simply pulls the arguments, constructs the new command, and calls the implementation ofrun
in-process.Idea 2: Yarn's hooks are augmented to allow implementing the behavior in Idea 1. In particular, the
cli
object is provided towrapScriptExecution
or some new hook (executeScript
?) is provided that can take its place.Describe the drawbacks of your solution
In either version, there are some environment variables that would have to be juggled to make sure they are the same whether or not this in-process pathway is hit (
INIT_CWD
comes to mind).Idea 1: I don't believe there are any correctness or performance issues with the feature as described. Yarn scripts don't generally do much work before they end up shelling out to some other binary, so even if you had 10x nested scripts that hit this pathway, all you'd really be doing is collecting arguments along the way until you finally hit a non-Yarn binary or an inline shell script, which would not be eligible for inlining.
Idea 2: The hooks seem to want to be tightly scoped for a specific purpose. Providing
cli
, or even special-casing the ability to invokerun
(which seems... unlikely) would blow up the access that hooks have to Yarn considerably.Describe alternatives you've considered
I've been trying to implement a hook with this idea, but it's really gross. It reimplements a chunk of the body of
run
(since it can't call it) and does it own parsing of the command (though I learned aboutshellquote
after this particular implementation was written).I also tried writing my own stripped-down version of
npm-run-all
(this is an earlier version of it; it's messy). Doing so allows me to collapse (3) into (i) above, which is a good start. However, becauseworkspace foreach
doesn't know about it, it can't collapse (2) into (3). It also doesn't help with collapsing (i) into (ii).I think if
workspaces foreach
,run
, andrun-all
were all aware of each other (i.e., all implemented together), the example above could condense from 9 processes to 4: Yarn 1 -> Yarn 2 -> {Prettier, ESLint}.The text was updated successfully, but these errors were encountered: