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

Lack of more granular hoisting (former "nohoist") prevents me from upgrading from Yarn 1.x to 3.x #3273

Closed
Rush opened this issue Aug 12, 2021 · 3 comments

Comments

@Rush
Copy link

Rush commented Aug 12, 2021

The approximation of my monorepo setup:

{
  "name": "monorepo",
  "workspaces": {
    "packages": [
      "package1",
      "package2"
    ]
  },

monorepo/package1 depends on:

  • @angular/core
  • mongoose

what's special about package1 is that it can either be used standalone, or as a dependency for package2

monorepo/package2 depends on:

  • @angular/core
  • mongoose

With yarn 1.x I use:

  "workspaces": {
    "nohoist": [
      "@angular/**",
    ]

But if I undestand Yarn 3.x, I can either have my direct dependencies hoisted by default or not hoisted at all (hoistingLimits set to "workspaces")

The problem is with the same repo, I need the behavior of:

  • mongoose never being hoisted. Unfortunately mongoose is a stateful package where mongoose.model registers information in package's local state. package1 and package2 need separate state stored in mongoose.
  • @angular/** always being hoisted. There cannot be two versions of angular as it relies on strict equality between DI tokens. One cannot inject a token from one angular tree and expect a dependency resolved from the injector created in another tree.

Unfortunately I had to revert to yarn v1.x but I hope more granular hoisting can be made possible with future yarn versions. I realize it's possibly an edge case, but for me it's a real one.

@larixer
Copy link
Member

larixer commented Aug 12, 2021

@Rush I assume, you are using nodeLinker: node-modules

If you want to disable hoisting for only a few packages, you can just make the name busy on the higher level, for instance by using an alias, or link: protocol.
For example, if you don't want to hoist mongoose, you can have in root package.json:

{
  "name": "monorepo",
  "workspaces": {
    "packages": [
      "package1",
      "package2"
    ]
  },
  "devDependencies": {
    "mongoose": "npm:is-number"
  }

or

{
  "name": "monorepo",
  "workspaces": {
    "packages": [
      "package1",
      "package2"
    ]
  },
  "devDependencies": {
    "mongoose": "link:./packages"
  }

This way the nm linker will have no chance to hoist mongoose from inside packages to the top level.

@larixer larixer closed this as completed Aug 12, 2021
@elado
Copy link
Contributor

elado commented Dec 24, 2021

This is so useful!
Especially with TypeScript types conflicts.

I have a project with 2 workspaces and dependencies:

- packages
  - foo
    - react-router-dom@^6
  - bar
    - react-router-dom@^5
    - @types/react-router-dom@^5

Yarn ends up installing it like:

- node_modules
  - react-router-dom@^6
  - @types/react-router-dom@^5

- packages
  - foo    
  - bar
    - react-router-dom@^5

React Router v6 includes the types in it, while v5 had a @types package. TypeScript is trying to read types from both places in the foo package, and gets conflicts.

With the solution above, I added at the root:

  "devDependencies": {
    "@types/react-router-dom": "portal:./packages/noop"
  },

and a simple packages/noop with only a package.json with name/version, and now the tree is

- node_modules
  - react-router-dom@^6
  - @types/react-router-dom --> packages/noop

- packages
  - foo
  - bar
    - react-router-dom@^5
    - @types/react-router-dom@^5

The v5 types don't leak out!

@taylorkline
Copy link

If you use the link: protocol, the file does not have to even exist, so I've got "link:./null"

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

No branches or pull requests

4 participants