Skip to content

[Feature] PnP depency tree plumbing and deduplication #6051

Open
@yuriy-yarosh

Description

@yuriy-yarosh
  • I'd be willing to implement this feature (contributing guide)
  • This feature is important to have in this repository; a contrib plugin wouldn't do

Describe the user story

As a developer, I do like the idea of explicit dependency tries and Hoisting only at explicit Dependency Level, but I don't like bloated package.json's.

Given: that I prefer separating my monorepo reusable shared configs from the packages.

{
  "workspaces": [
    "config/*",
    "packages/*"
  ]
}

So, for instance, I have @org/config-eslint and @org/config-typescript, with dependencies

@org/config-eslint

{
  "dependencies": {
      "@typescript-eslint/eslint-plugin": "^6.14.0"
      "@typescript-eslint/parser": "^6.14.0"
      "eslint": "8.55.0"
      "eslint-config-turbo": "^1.11.2"
  }
}

@org/config-typescript

{
  "dependencies": {
    "@types/node": "^20.10.6",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
  }
}

When: I'm making an explicit dependency, in devDependencies due to the hoisting limits nmHoistingLimits: dependencies.
Then: I'm forced to add propagate all the deps explicitly. PnP disregards Hoisting entirely, and it's a must, e.g.

org

{
  "devDependencies": {
    "@org/config-eslint": "*"
    "eslint": "8.55.0"
    "eslint-config-turbo": "^1.11.2"
    ...
    "@org/config-typescript": "*"
    "@types/node": "^20.10.6",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
    ...
  }
}

Which bloats package.json's everywhere.

Describe the solution you'd like

Target config dependencies could be expressed as a set of peerDependencies.

  "peerDependencies": {
    "@typescript-eslint/eslint-plugin": "*",
    "@typescript-eslint/parser": "*",
    "eslint": "*",
    "eslint-config-turbo": "*"
  }

and installed in .yarnrc as package extensions, with specific versions

packageExtensions:
  "@orgconfig-eslint@*":
    dependencies:
      "@typescript-eslint/eslint-plugin": "^6.14.0"
      "@typescript-eslint/parser": "^6.14.0"
      "eslint": "8.55.0"
  1. js-yaml is missing anchor merging. I'd like to add proper anchor merging support there, and enable it by default for .yarnrc's. This would allow us to merge and reuse deps, because you can't just "inherit" and install all the peerDependencies from a dependency, implicitly. And I'm looking for a way to do that explicitly, without much configuration bloat.

So, with anchor merging, it would be possible to use some advanced yaml syntax, like

packageExtensions:
  "@org/config-eslint@*":
    dependencies: &config-eslint
      "@typescript-eslint/eslint-plugin": "^6.14.0"
      "@typescript-eslint/parser": "^6.14.0"
      "eslint": "8.55.0"
      
  "@org/config-typescript@*":
    dependencies: &config-typescript
      "@types/node": "^20.10.6"
      "ts-node": "^10.9.2"
      "typescript": "^5.3.3"
      
  "org":
    dependencies:
      << : [ *config-eslint, *config-typescript]  
   
  "@org/package-with-shared-configs":
    dependencies:
      << : [ *config-eslint, *config-typescript]  
  1. I'd like to be able to extend devDependencies with packageExtensions, as well
packageExtensions:
  "@org/config-eslint@*":
    devDependencies:
      "eslint": "8.55.0"
  1. I'd like to be able to extend the dependency tree by inheriting the dependencies of leaf monorepo packages in packageExtensions
packageExtensions:
  "@org/config-eslint@*":
    dependenciesFrom:
      - peer: "@org/config-typescript" # adds dependencies with peerDependencies of `config-typescript`
      - dev: "@org/config-eslint"       # adds dependencies with devDependencies of `config-eslint`
    devDependenciesFrom:
      - peer: "@org/config-typescript" # adds devDependencies with peerDependencies of `config-typescript`
      - dev: "@org/config-eslint"       # adds devDependencies with devDependencies of `config-eslint`
  1. It should be also possible to override some versions explicitly, because "*" install should result in latest stable version
packageExtensions:
  "@org@*":
    dependenciesFrom:
      - dev: "@org/config-eslint"       # adds dependencies with devDependencies of `config-eslint`
    dependencies:
      "eslint": "8.55.0"

Anchor merging should take into account such overrides and adding dependenciesFrom elsewhere, to keep this feature consistent.

  1. I'd like to add some .yarnrc dependency upgrades capabilties for the yarn upgrade-interactive

Describe the drawbacks of your solution

It would require custom packageExtensions implementation, and advanced yaml syntax support, that would divert from the original npm spec to a certain degree.

Describe alternatives you've considered

There's not much.
I'm forced to copy-paste all the peerDependencies across multiple packages, and bloat package.json's.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions