Skip to content
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

fix: resolve peer of peer from the deps of direct dependent package #7606

Merged
merged 43 commits into from
Feb 8, 2024

Conversation

zkochan
Copy link
Member

@zkochan zkochan commented Feb 2, 2024

close #7444

Peer dependencies of peer dependencies are now resolved correctly. When peer dependencies have peer dependencies of their own, the peer dependencies are grouped with their own peer dependencies before being linked to their dependents.

For instance, if card has react in peer dependencies and react has typescript in its peer dependencies, then the same version of react may be linked from different places if there are multiple versions of typescript. For instance:

project1/package.json
{
  "dependencies": {
    "card": "1.0.0",
    "react": "16.8.0",
    "typescript": "7.0.0"
  }
}
project2/package.json
{
  "dependencies": {
    "card": "1.0.0",
    "react": "16.8.0",
    "typescript": "8.0.0"
  }
}
node_modules
  .pnpm
    card@1.0.0(react@16.8.0(typescript@7.0.0))
      node_modules
        card
        react --> ../../react@16.8.0(typescript@7.0.0)/node_modules/react
    react@16.8.0(typescript@7.0.0)
      node_modules
        react
        typescript --> ../../typescript@7.0.0/node_modules/typescript
    typescript@7.0.0
      node_modules
        typescript
    card@1.0.0(react@16.8.0(typescript@8.0.0))
      node_modules
        card
        react --> ../../react@16.8.0(typescript@8.0.0)/node_modules/react
    react@16.8.0(typescript@8.0.0)
      node_modules
        react
        typescript --> ../../typescript@8.0.0/node_modules/typescript
    typescript@8.0.0
      node_modules
        typescript

In the above example, both projects have card in dependencies but the projects use different versions of typescript. Hence, even though the same version of card is used, card in project1 will reference react from a directory where it is placed with typescript@7.0.0 (because it resolves typescript from the dependencies of project1), while card in project2 will reference react with typescript@8.0.0.

@zkochan zkochan added this to the v9.0 milestone Feb 5, 2024
@@ -143,7 +143,7 @@ test('don\'t install the same missing peer dependency twice', async () => {
const lockfile = await project.readLockfile()
expect(Object.keys(lockfile.packages).sort()).toStrictEqual([
'/@pnpm/y@1.0.0',
`/@pnpm.e2e/has-has-y-peer-peer@1.0.0${createPeersFolderSuffix([{ name: '@pnpm/y', version: '1.0.0' }, { name: '@pnpm.e2e/has-y-peer', version: '1.0.0' }])}`,
'/@pnpm.e2e/has-has-y-peer-peer@1.0.0(@pnpm.e2e/has-y-peer@1.0.0(@pnpm/y@1.0.0))(@pnpm/y@1.0.0)',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the nested syntax here is pretty interesting—that's new, right? is it representing a small subtree of peer dep resolutions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if a peer dependency has peer dependencies of its own, they will be nested. The nesting may be deep if there is a long chain of peer dependency peer dependencies.

Comment on lines -136 to +137
'@pnpm.e2e/has-say-hi-peer': '1.0.0(hi@1.0.0)',
'@pnpm.e2e/has-say-hi-peer': '1.0.0(github.com/zkochan/hi/4cdebec76b7b9d1f6e219e06c42d92a6b8ea60cd)',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh awesome, this seems like it would fix #7393 wouldn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure. It was a byproduct of my changes. I'll be happy if it fixes more issues.

@stevenpetryk
Copy link
Contributor

This might be annoying to mention if this PR is still quite early on, but when I try out this branch locally on Discord I get the following error (enabled sourcemaps with pd install):

Stacktrace
ERROR  graph.get is not a function or its return value is not iterable

pnpm: graph.get is not a function or its return value is not iterable
    at findCycle (/Users/steven/src/pnpm/deps/graph-sequencer/src/index.ts:103:30)
    at graphSequencer (/Users/steven/src/pnpm/deps/graph-sequencer/src/index.ts:66:23)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:605:22)
    at resolvePeers (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:97:27)
    at resolveDependencies2 (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/index.ts:181:7)
    at _installInContext (/Users/steven/src/pnpm/pkg-manager/core/src/install/index.ts:1001:7)
    at installInContext (/Users/steven/src/pnpm/pkg-manager/core/src/install/index.ts:1399:12)
    at _install (/Users/steven/src/pnpm/pkg-manager/core/src/install/index.ts:679:20)
    at mutateModules (/Users/steven/src/pnpm/pkg-manager/core/src/install/index.ts:274:18)
    at recursive (/Users/steven/src/pnpm/pkg-manager/plugin-commands-installation/src/recursive.ts:273:46)
Progress: resolved 5629, reused 5510, downloaded 0, added 0
TypeError: Cannot read properties of undefined (reading 'promise')
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:463:58)
    at Array.map (<anonymous>)
    at calculateDepPaths (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:448:10)
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:53)
    at Array.map (<anonymous>)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:26)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
TypeError: Cannot read properties of undefined (reading 'promise')
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:463:58)
    at Array.map (<anonymous>)
    at calculateDepPaths (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:448:10)
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:53)
    at Array.map (<anonymous>)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:26)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
TypeError: Cannot read properties of undefined (reading 'promise')
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:463:58)
    at Array.map (<anonymous>)
    at calculateDepPaths (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:448:10)
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:53)
    at Array.map (<anonymous>)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:26)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
    at resolvePeers (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:97:27)
    at resolveDependencies2 (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/index.ts:181:7)
TypeError: Cannot read properties of undefined (reading 'promise')
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:463:58)
    at Array.map (<anonymous>)
    at calculateDepPaths (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:448:10)
    at <anonymous> (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:53)
    at Array.map (<anonymous>)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:608:26)
    at resolvePeersOfNode (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:376:7)
    at resolvePeersOfChildren (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:590:9)
    at resolvePeers (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/resolvePeers.ts:97:27)
    at resolveDependencies2 (/Users/steven/src/pnpm/pkg-manager/resolve-dependencies/src/index.ts:181:7)

@zkochan
Copy link
Member Author

zkochan commented Feb 7, 2024

Actually the PR is ready. I only need to add changesets and a description. So, it is not good that it failed for you. But I think I know how to fix the issue.

@zkochan
Copy link
Member Author

zkochan commented Feb 7, 2024

This is a breaking change but it is a very important fix, so I will probably add this change to v8 as well (as an opt-in).

@zkochan
Copy link
Member Author

zkochan commented Feb 8, 2024

Steven has found a scenario in which these changes make pnpm hang:

{
  "devDependencies": {
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.0.0"
  }
}

I'll try to fix this.

@zkochan
Copy link
Member Author

zkochan commented Feb 8, 2024

@stevenpetryk you can try it again. I have fixed the issue.

@stevenpetryk
Copy link
Contributor

Seems fixed on our end!

@jakebailey
Copy link
Member

I'm currently running a test locally with this PR for DT, just to see. It's caused a few failures so far, so I need to try and narrow this down to understand what differed. Mainly, it looks like certain packages used to have access to @types/node, but now don't. (And other related errors.)

@zkochan
Copy link
Member Author

zkochan commented Feb 8, 2024

Before these changes, the resolution algorithm was somewhat undeterministic. There was a possibility that, before the change, a peer dependency would have access to @types/node simply because it was accessible in a different workspace project. Conversely, there were instances where it might not have had access to @types/node, even though it should have.

That might be the cause of the issue.

@zkochan
Copy link
Member Author

zkochan commented Feb 8, 2024

@jakebailey let me know what you find out and whether we should wait with merging this.

@jakebailey
Copy link
Member

I haven't had time to analyze it yet, but https://gist.github.com/jakebailey/d4ac5d357dcf84dd6ef8fd265264be00 contains the raw output of running tsc on every DT project when installed using this branch. I suspect that a lot of these are "okay" in that they represent more packages that need a @types/node dep to pull them into the tree (anything that says cannot find type defintion file for node), but the cases where there are now new duplicated identifiers are more concerning.

@zkochan
Copy link
Member Author

zkochan commented Feb 8, 2024

This will only be released in v9. We will fix any issues that you find before the first stable version.

@zkochan zkochan merged commit 98a1266 into main Feb 8, 2024
14 checks passed
@zkochan zkochan deleted the fix-peers-resolution branch February 8, 2024 23:50
@jakebailey
Copy link
Member

Thankfully, most of the errors were my mistake (running the wrong typescript version on typesVersions dirs).

The rest are all places where we could add deps on node/react to fix the problem, which is something we had to do originally when switching to pnpm and can be done here to make tests pass. So, I don't think there are any issues for us.

@jakebailey
Copy link
Member

jakebailey commented Feb 9, 2024

I did notice that one of the paths mentioned has an unmatched closing paren:

types/react-native-safari-view/node_modules/.pnpm/react-native@0.73.4_@babel+core@7.23.9_@babel+preset-env@7.23.9_@babel+core@7.23.9)_react@18.2.0/node_modules/react-native/Libraries/Animated/Animated.d.ts

image

Which may be a bug in this PR.

@zkochan
Copy link
Member Author

zkochan commented Feb 9, 2024

I see, I already started the release of v9.0.0-alpha.2. We can create an issue about this issue that you have found.

@zkochan
Copy link
Member Author

zkochan commented Feb 13, 2024

It probably makes sense to bump the lockfile version to v7 with this change. As it appears that pnpm v8 fails with the new nested brackets syntax. I have backported a fix but I don't think it will be enough to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Inconsistent lockfile changes on repeat installs
3 participants