-
Notifications
You must be signed in to change notification settings - Fork 3k
npm install
should deduplicate its tree as part of the install process
#6912
Comments
One interesting consequence of this is that now you'll be able to do {
"dependencies": { "A": "1" }
} but then var a = require("A");
var b = require("B");
var c = require("C"); If this is undesired, you could probably sidestep it while still gaining many of the benefits by creating the structure
However, this is a bit of a slippery slope. If we say that preventing require-of-indirect-dependencies is a priority, that places a hard cap on the possible deduplication, e.g. in the scenario
you would be unable to deduplicate B. So, probably not worth it. |
Yeah, this is all true, but even the existing |
@domenic Do you have a concrete scenario in mind where this could become an issue? As @iarna indicates, this is already an issue with dedupe, and it hasn't been an issue to date. We're planning on tracking why a hoisted package is there (i.e. its dependents), and also planning on operating on and displaying the logical tree rather than what's on disk (so |
No concrete scenario based on experience. I'm just imagining someone e.g. installing facebook's jest, then starting to do Or, people explicitly creating packages like "my-favorite-libs" that depend on a bunch of libs, then saying in the readme "after you do It'll indeed help that |
To prevent this, "Si quieres viajar alrededor del mundo y ser invitado a hablar en un |
Any changes to the Node module resolution algorithm are completely out of scope for npm, especially because that API is marked "locked" within Node itself. |
Something to keep in mind though when designing the ES6 module loader for Node (in the so-far-hypothetical future where V8 ships ES6 modules). |
The behaviour and API would still be the same, it only change the "Si quieres viajar alrededor del mundo y ser invitado a hablar en un |
@domenic Isn't this the same problem I mentioned back in September? |
@stuartpb Your issue and its various ramifications are real, but some of the things that @iarna is doing with her pass at deduplication in the multi-stage install work are designed to address some of the edge cases you raise. On the one hand, people will now be able to inadvertently require things from the top level that they probably shouldn't be able to, and there's a risk they'll come to depend on things that aren't actually part of the install. On the other, npm will keep track of what's a direct dependency and what's a transitive dependency, and should be able to not lose its bananas when a dependency switches from one category to the other. I don't think there's a solution to this problem that always prevents anyone from ever being surprised, but deduplication by default is otherwise such a win that I think the tradeoff is acceptable. |
Wholly +1 on this. Note that this is going to break a lot more package.json scripts incorrectly relying on executables being installed in
We could adapt some existing require-detecting tooling to pick this up pretty easily. |
That's really smart. We should just strip |
We actually already do strip npm/read-package-json@56c7f5de I'm going to be moving this over to |
Closing this as fixed in npm/npm#multi-stage |
Great! :-D Could you stimate when/in what version this could be integrated in master? Maybe npm 3? |
@iarna is there any plan to do automatic deduping as part of {
"name" : "A",
"dependencies": {
"B": "^1.2.3",
"C": "^4.5.6",
} Pinned {
"name" : "B",
"dependencies": {
"C": "4.5.6"
} It's desirable for |
This was a huge mistake I should say. Basic example: I have a |
Well, I guess we should not allow a required dependency to be uninstalled without the use of something like |
Or remove the other ones recursively, too. |
@piranna Yep, but some new option should be introduced to do that like |
👍 |
Please explain how do you see "correct" uninstall from the user point of view. I shouldn't remember all deps of all deps, right? So the problem here is caused exactly by NPM deduplication, not any of my actions which were pretty basic. By adding new options you'll just get more tricky cases on the next levels of relations. |
It solves some cases where computer wants to be smarter than a human. Sometimes I want a computer to do something he thinks dangerous or impossible. For example, rollback migrations on production machine. Such actions must be confirmed with
Dependency is something, that is required by any module in your system. Not just by the package you requested to be installed. This way it works with every other package manager: yum, apt-get, php-composer etc. I don't see why node should be an exception. You cannot allow user remove a module for which is known that it is used by other modules. The fact, that user never installed it himself doesn't matter. You must present a user with a clear error message about this fact. But still, there are some cases when this operation (module installation) MUST be performed disregarding consequences (we are programmers after all, not some silly children). For inspecting aftereffects, for example. Or may be we are going to replace all broken dependency links by a module with the same interface, but didn't edit npm registry. Or may be, module we are removing is used only by another modules, that are going to be pruned by my next command. Or... well, there could be some cases, believe me. Of course user must understand, that the use of
Here I agree. But I do not consider npm complicated when you compare it to similiar package managers. |
Ok, i'm trying to remove I can accept flag if it prevents you from doing something that may be done better. What NPM should do instead is to provide a dialog:
This is helpful and doesn't leave anything in broken state in cases |
Yes, this is another option. But it is just the same thing - But sometimes actions must be done from scripts without user interaction. |
Yes. Then just give us one flag |
Well, |
(Just my take on how I would expect things to work.) |
When you do |
Thank you for this example @FractalizeR. It's sad to see that yum also behaves very unfriendly. The simplest correct solution is what @parshap says. Just reinstall this damned |
How will deduplication handle different versions of the same dependency?
In this scenario, would we end up with a directory structure like the current
|
Yes. The install / deduplication algorithm will only flatten the dependency tree as much as it can without introducing semver conflicts or other forms of dependency hell. If there is a conflict, then each dependency will get its own version of the conflicting dependency. |
Will there be a flag on package.json to notify we don't allow conflicts on a package to make sure that there's only one version of it and throw an error if not, similar to the sanity-check done by peerDependencies? |
No. There is discussion of a new |
My question was not regarded to browser, but instead about the fact that having duplicated libraries I've found several errors when doing instanceof because the same class was being fetch from two diferent copies of the same package and Node.js understood them as two diferent classes. |
That's not an error, and that's why |
This is intended to solve a few larger project goals:
As such, @othiym23 and I have decided this should be a maximally flat deduplication, which means if you have a dep tree of:
Then if you install A, you'll get B and C next to it in your node modules. That is, it'll be installed as:
But we'll hold onto metadata to know why B and C were installed such that removing A will remove B and C as it would now.
As for devDependencies, they shouldn't have their dependencies folded in as above. Instead each of them should essentially act as its own root. So if A above were a dev dependency then it would be installed as:
The following work remains to be done:
npm outdated
to give similar output to npm@2 #7273npm outdated
needs to structure its output in a way that makes sense with a flat node_modules folder.npm ls
command that's aware of new structure #7272npm ls
needs to structure its output in a way that makes sense with a flat node_modules folder.See also: #4761, #4037, #5465
The text was updated successfully, but these errors were encountered: