Skip to content

[release/v11] fix: prefer existing tree nodes for peerOptional deps (#9249)#9301

Merged
owlstronaut merged 1 commit intorelease/v11from
backport/v11/9283
May 4, 2026
Merged

[release/v11] fix: prefer existing tree nodes for peerOptional deps (#9249)#9301
owlstronaut merged 1 commit intorelease/v11from
backport/v11/9283

Conversation

@owlstronaut
Copy link
Copy Markdown
Contributor

@owlstronaut owlstronaut commented May 4, 2026

Manual backport of #9283 to release/v11.

Cherry-picked commit: 0629fbf

Refs #9249.

When a peerOptional edge conflicts, search descendants for a satisfying
node before fetching from the registry. This prevents extraneous
packages from blocking hoisting of required deps.

This fixes 1/2 or 1/3 of #9249. Before this change a clean install would
resolve `nm/jest-util@30` when resolving the conflict at nm/jest-util
between ts-jest's jest-util@^29||^30, and expect's ^28, which had been
placed at root. `#nodeFromEdge` would create a brand new node, matching
greatest ^30. A subequent install would mark nm/jest-util@30 as
extraneous and prune it.
This tree is valid, but ts-jest's peerOptional jest-util is unsatisfied,
while compatible jest-util are installed and duplicated.

This change reduces duplication and can prevent peerOptionals from
actively installing.

1. Now during initial installs npm will prefer hoisting a dependency to
de-dupe a peerOptional conflict over creating a new extraneous edge.
2. It doesn't solve the problem if there's no compatible version in the
sub-tree. npm will still use `#nodeFromEdge` and install an extraneous
edge.
3. It doesn't fix installs from lockfiles generated before this fix. I
think this is okay, because the trees are techincally valid, just not
optimal.

 I think a better solution to all three issues would be:
* During problemEdge conflict resolution, npm would hoist
nm/jest-util@28 under expect, without replacing it with anything.
ts-jest's peerOptional jest-util would be unsatisfied. This creates the
same tree as npm's second installs that prune extraneous.
* Check for any dependencies that can be hosited. This can run during
the initial install on problemEdge conflict resoultion, and in
pruneIdealTree on any nodes that are removed.

I think this solves all three issues. I didn't implement it because I
couldn't find a way to resolve the conflict by leaving a hole in the
tree..

(cherry picked from commit 0629fbf)
@owlstronaut owlstronaut requested a review from a team as a code owner May 4, 2026 16:21
@owlstronaut owlstronaut merged commit e19b349 into release/v11 May 4, 2026
17 checks passed
@owlstronaut owlstronaut deleted the backport/v11/9283 branch May 4, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants