-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Workspaces - Is it possible to exclude some node_modules from beeing hoisted to the root node_modules folder? #3882
Comments
@thomaschaaf is this a feature request? :) (since you haven't mentioned that in the first question) |
//cc @bestander |
@BYK If its not yet possible (maybe it is not documented?) than it is a feature request. |
Would a symlink to the hoisted location work? |
lerna installs it directly when using |
Another use-case for disabling hoisting is that it helps prevent devs from creating accidentally-malformed packages. I worked on a Lerna repo that had hoisting enabled. A number of the packages were erroneously using hoisted dependencies they had not specified because the code compiled/ran fine due to the way in which Node searches for modules -- namely, by traversing up the file hierarchy until it finds something in any ancestor's For our use-case, hoisting bought us nothing while introducing more pitfalls, so I would love a way to disable hoisting on any given monorepo -- indeed, I would actually argue that no-hoist should be the default for the reasons stated above and by the principle of least surprise. |
All good points here. The hoisting logic is isolated in https://github.com/yarnpkg/yarn/blob/master/src/package-hoister.js and you know whether the dependency is a workspaces if it's name is |
we bump into this issue with react-native so working on this PR. Question regarding the preference of where to put the nohoist configuration. A few options to consider:
Let me know if you see other better options, right now we are leaning toward option 2, suggestion something like this:
thoughts? |
At AAA, we have some packages that still depend on Grunt and Having package.json/workspaces:array "workspaces": [
"packages/*"
] package.json/workspaces:object "workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"grunt*",
"jasmine*"
]
} |
@andrewmcwatters , I like it |
[discussion]
1. shallow nohoist
2. deep nohoist
3. hybrid (weak inheritance)
What do you guys think? |
@bestander which option is more aligned with the yarn philosophy? @andrewmcwatters, any of the options above will not work for your use case? |
We run also into this with Our use case:
The structure can be:
Suggestions:
I think it would be nice to combine the solution and provide both. I am interested in your opinions and user/edge cases! |
@DannyvanderJagt thanks for the feedback, yes the nohoist will be available in any package.json, not just the root. It is pretty clear how to make react-native itself nohoist, the question is more about how we should handle react-native's dependency. Use your scenario as an example, let's assume your react-native-project uses jest and so does the react-native:
(I updated the earlier comment to make it more clear. ) |
the more I think about it, the more I think maybe the deep-nohoist is the safest way to go. It is definitely not space-efficient, but since nohoist is mainly a workaround for packages that are not using the normal package management facility, a trade-off in space-efficiency is probably acceptable. Ideally, react-native and others should be updated to use the package manager and not walking the file tree itself. Until then, we use nohoist as a workaround... please let me know if you disagree with this approach. (I will be travelling this week, but should have some time next week to finish it) |
Maybe we could do better... 😏 just thought about something that might make shallow-hoist a better option: By default, every nohoist package is "shallow", if some package is looking to also nohoist a deep dependency, for example, jest under react-native, it could just add "jest" into the react-native-project's package.json:
in this case, every "jest" package under react-native-project will also not be hoisted. The benefit is that yarn doesn't have to make assumption and developers can add as much or little nohoist packages as they need while maximizing the benefit of hoist. Since the configuration will be position-aware, other projects used jest could still hoist jest, i.e. the "nohoist" will only apply to the dependency tree downward from where it is specified. let me know if you see any logic flaw or missed use cases... |
@connectdotz Thanks for the explanation! The last one looks solid. Just quickly tested this for a react-native project by simulating a no hoist for only the |
perfect! thx @DannyvanderJagt |
Is there a possible ETA on when we could hope to merge this functionality in? |
@connectdotz, I enjoy seeing so much enthusiasm around solving this issue! I think the nohoist feature can be very useful, similar to selective version resolutions. As for your question #3882 (comment), I think shallow hoist (1) looks more consistent with what Yarn currently does. |
@seansfkelley, the eslint-plugin-import no-extraneous-dependencies rule can help prevent this fwiw. |
Unfortunately this won't catch extraneous dependencies which are required implicitly, for example TypeScript typings (e.g. |
Just ran into the same issue with react-native, do you guys have an ETA on this feature? |
sorry for the late reply, I was off-grid in the last few days (traveling until mid next week) @bestander yes I will submit an RFC, probably should have started this discussion as an RFC... oh well... For those who wondered about the progress of nohoist, I will be back to the state next week and plan to submit the RFC in the 1st week of Nov. Not sure how long the RFC process itself will take, but at least we shall see some concrete progress then... if you have the time and idea, I am sure you will be welcome to start the RFC process sooner... |
In case anyone is stuck with this and until the different issues are fixed, I made a little guide on how to use yarn workspaces with Create React App and Create React Native App (Expo) to share common code across. Hope you find it handy! |
@dariocravero great writeup and thanks for investing your time in it! |
Related issues: #4743 & #4503. Another reason that hoisting seems problematic is that it could lead a library author to erroneously believe their package has the correct dependencies defined, when in fact they are just being resolved from hoisted dependencies of a sibling package. Wouldn't find out until after publishing that there was a problem. |
A hack to avoid specific dependency being hoisted seems to be to install a conflicting version of the dependency in the root directory, but this still doesn't address the issue mentioned above of not realizing that you're relying on hoisted modules. |
Wondering if symlink'ing to the hoisted location, as suggested by @bestander in #3882 (comment), would just work by default for most of the use cases that are broken by the current implementation. Additionally this would allow that hoisted location (top-level 'node_modules') to be renamed to something like 'hoisted_modules', which would fix the issue of inadvertently picking up dependencies that are not defined by your package, as described above by @Zerim. |
@bradfordlemley There is another tool for npm monorepos called Rush that uses an approach similar to what you're describing -- installing shared dependencies in a folder not seen as a node_modules folder, then using symlinks to connect projects to their dependencies. (Their approach goes a bit further to allow multiple versions of a given module to be shared, further reducing the disk space and copying needed. In my testing, this also resulted in a faster webpack build for our application that used less memory.) I'd be very happy if yarn workspaces offered a dependency layout on disk similar to the one used by Rush. It would fix all the hoisting-related issues I'm aware of. |
Great to see that there's an RFC. Really hope this will come to fruition in the near future, I'm also using react-native and am blocked from using yarn workspaces because of this issue at the moment. |
The base implementation of nohoist is already in a PR and mostly done, so I think we'll get a resolution for this soon enough. |
@connectdotz Is there a way to temporarily disable yarn (and lerna) hoisting in the case you want to do some final integration tests against published packages? |
not quite sure what you mean by "temporary"... here is how you can turn on/off nohoist at any time you wish:
|
I think he was thinking of a command such as |
there is no command line option for nohoist currently. However, for CI/CD, you can have different |
I apologize for the unspecific question. I actually meant can I disable all the hoisting AND LINKING, in order to do final integration tests against published packages. As such, it probably belongs in its own issue and not here because I don't think it relates to the Admittedly, all this really tests is that in the process of publishing I did not accidentally Perhaps I should phrase my question as a way to disable I'm not sure how to yarn install the actual packages off the registry unless I mutate the Thoughts? |
It seems like with nohoist this issue can be closed now, right? |
The problem with absolute path requirements in certain dependencies is that they can lead to issues with package resolution and portability. When a dependency specifies an absolute path to require other dependencies, it assumes a specific file system structure and location. This can cause problems when the package is used in different environments or by different developers who have different file system structures. For example, let's say a package has a dependency that is required using an absolute path like In general, it is considered best practice to use relative paths or module resolution mechanisms (such as |
Do you want to request a feature or report a bug?
Feature
What is the current behavior?
We are currently using
hoist
feature from lerna. I tried to move to yarn workspaces and it works way faster! Awesome, thank you!If the current behavior is a bug, please provide the steps to reproduce.
What is the expected behavior?
But i also need the ability (sadly) to exclude some node_modules from not beeing hoisted to the root node_modules folder but be physically installed in the package i configured it as dependency. (The same way the
--no-hoist
arguments are working for lerna. )The reason is, sadly, that some dependencies we use, are trying to require some dependencies with an absolute path from
packages/<package>/node_modules
directly. So i have to exclude some.Is there a way to configure some sort of exclude glob for workspaces?
Please mention your node.js, yarn and operating system version.
yarn --version: 0.27.5
node -v: v6.11.0
macOS: 10.12.5
The text was updated successfully, but these errors were encountered: