feat(pkg-manager): add new hoisting limits config#6468
Conversation
28ce1ec to
9811e6d
Compare
|
I have absolutely no clue what failed in CI... |
|
It was an issue with verdaccio. I have downgraded it. Now you can see the failed test. |
|
Seems like my bugfix introduces a breaking change to the lockfile. Before, a dependency like dependencies:
minimist:
specifier: ''
version: 1.2.8But, now, it's encoded like: dependencies:
minimist:
version: 1.2.8The problem I was papering over was that some random deps got I guess I can not do this bugfix, and try and come up with some other fix for that issue, which, of course also deserves a test, if I can figure out how to write one anyway 😅 |
|
I think in my bugfix I was mirroring how |
| manifest: Pick<ProjectManifest, DependenciesOrPeersField>, | ||
| depName: string | ||
| ) { | ||
| ): string | undefined { |
There was a problem hiding this comment.
This is technically now breaking but not sure I can do better here. I'm failing to figure out what the deal is, effectively what's happening is that a package depends on ts-node, which peer deps on @types/node, which exists in the repo and should be linked, but that peer dep appears as a dep of the user of ts-node instead.
There was a problem hiding this comment.
is it? looks like CI is passing
There was a problem hiding this comment.
Breaking API change, I mean, in that this used to return string but now returns string | undefined.
There was a problem hiding this comment.
But, I searched github and found nobody but pnpm calling this function so I don't expect it to acutally matter...
There was a problem hiding this comment.
I do think that this change is good, but, I also think I'm masking another bug regarding peer deps (but I am at least getting DT to work after this).
There was a problem hiding this comment.
I guess if I'm making the other major bumps, I may as well declare this one as major too?
There was a problem hiding this comment.
Ah, no, I already got that in the PR.
| */ | ||
| export type HoistingLimitMode = 'none' | 'workspaces' | 'dependencies' | ||
|
|
||
| export function getHoistingLimits (lockfile: Lockfile, mode: HoistingLimitMode | undefined): HoistingLimits | undefined { |
There was a problem hiding this comment.
there is no need to make this function public. Just call it from the hoist function instead of passing hoistingLimits to the hoist function.
There was a problem hiding this comment.
I guess I can shove it down the stack; the main thing I was trying to reconcile is the fact that this API takes in hoisting limits and so I need to respect them. But, I guess I can just do this somewhere else.
There was a problem hiding this comment.
There's no need to take in hoisting limits. It is not used anywhere.
There was a problem hiding this comment.
I'm not following; are you saying that #4300 can in effect be reverted? That is the API I'm referring to, and it's exposed all the way up to headlessInstall.
There was a problem hiding this comment.
yes, I needed it for Bit but then I came up with a different solution. So, it is not needed.
There was a problem hiding this comment.
I'm happy to revert that API and make this logic private, if you're confident that it's safe to do so! I'm not totally sure what API guarantees you make, so I went with the conservative option.
There was a problem hiding this comment.
It is OK. It will be a major version bump.
|
One thing I'm struggling with is producing a test for the bugfix; it's going to require adding a new package to the fake registry in In effect, I need to have these packages: I can try and find real npm packages out there that could do this, but most have a lot of other dependencies that would make pulling in the full tree awkward. |
|
The fake registry is here: https://github.com/pnpm/registry-mock You can link it locally to the pnpm repo or I can publish a new version when you add the packages. |
|
Isn't what you posted a workspace? If it is a workspace these packages shouldn't be in the registry mock. |
|
Two of them are, but if I didn't realize the mock was pulling from anything except https://github.com/pnpm/pnpm/tree/main/pkg-manager/core/test/registry-mirror; I'll go check that mock repo to see if it has something I can use! |
| "@pnpm/resolve-dependencies": major | ||
| "@pnpm/manifest-utils": major | ||
| "@pnpm/real-hoist": major | ||
| "@pnpm/headless": major | ||
| "@pnpm/core": major | ||
| "@pnpm/config": major |
There was a problem hiding this comment.
Was not sure here as the API changed, so... just said they're all major. I'm not sure if that's accurate or not.
|
Was able to get a test for the bugfix in the first commit. Will work on tests for the hoisting limits. I can also split the bugfix apart if you want that sooner than I can write tests for the second half. |
|
I am ok with whichever approach |
|
is this still needed? |
|
I unfortunately haven't had time to work on this; doing this would enable DT to stop needing to disable the shared lock file mode and therefore take way less time to install. It's just been "fine" since we switched to pnpm such that other stuff has been more pressing... |
|
I'm also interested in yarn like hoisting limits and would have time to work on it. For the terminology, it might make sense to rename |
|
I'm honetly not 100% certain what all is left at this point; the primary place to test this is on DefiniteltyTyped by enabling this option and seeing if the install is both faster and still passes tests (within reason). If you have more time than me to work on it, by all means feel free to. |
|
This will be shipped via #12041 |
Expose `hoistingLimits` as a user-facing setting for `nodeLinker: hoisted` installs, mirroring yarn's `nmHoistingLimits`. Accepts `none` (default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), or `dependencies` (hoist only up to each workspace package's direct dependencies). The setting is the user-friendly enum; `@pnpm/installing.linking.real-hoist` translates it into the `@yarnpkg/nm` hoister's per-locator border map via `getHoistingLimits`. Wires the key through config types, the config-file key registry, and the install/add/recursive command option lists. Revives the approach from #6468 (closes #6457).
Expose `hoistingLimits` as a user-facing setting for `nodeLinker: hoisted` installs, mirroring yarn's `nmHoistingLimits`. Accepts `none` (default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), or `dependencies` (hoist only up to each workspace package's direct dependencies). The setting is the user-friendly enum; `@pnpm/installing.linking.real-hoist` translates it into the `@yarnpkg/nm` hoister's per-locator border map via `getHoistingLimits`. Wires the key through config types, the config-file key registry, and the install/add/recursive command option lists. Revives the approach from #6468 (closes #6457).
Expose `hoistingLimits` as a user-facing setting for `nodeLinker: hoisted` installs, mirroring yarn's `nmHoistingLimits`. Accepts `none` (default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), or `dependencies` (hoist only up to each workspace package's direct dependencies). The setting is the user-friendly enum; `@pnpm/installing.linking.real-hoist` translates it into the `@yarnpkg/nm` hoister's per-locator border map via `getHoistingLimits`. Wires the key through config types, the config-file key registry, and the install/add/recursive command option lists. Revives the approach from #6468 (closes #6457).
…its setting (#12041) ## 1. Support `nodeLinker: hoisted` on the fresh-lockfile install path (pacquet) Closes #11871. Until now pacquet's `Install::run` hard-refused `nodeLinker: hoisted` without a checked-in lockfile (`ERR_PNPM_…UNSUPPORTED_FRESH_INSTALL_NODE_LINKER`). - Extracted a shared `run_hoisted_linker` helper from the frozen path's hoisted branch (walker → `link_hoisted_modules` → `SymlinkDirectDependencies { link_only: true }` → `pkg_root_by_key` → walker-skip folding), so both install paths run identical logic. - Fresh path now threads `node_linker` + `supported_architectures`, hands `CreateVirtualStore` the real linker (populating `cas_paths_by_pkg_id`), branches on `is_hoisted`, and returns `hoisted_locations` so `.modules.yaml` round-trips. - Removed the guard and the dead `UnsupportedFreshInstallNodeLinker` error variant. Ported upstream's `hoistedNodeLinker/install.ts` into `crates/cli/tests/hoisted_node_linker.rs` (real tests for the core layout, no-lockfile, `externalDependencies`, `autoInstallPeers`, and `hoistingLimits`; the rest stubbed as `known_failures` against `pnpm add`/update (#433) and build-phase (#11870) gaps), and ticked the boxes in `plans/TEST_PORTING.md`. ## 2. Add the `hoistingLimits` setting (pnpm CLI **and** pacquet) Revives the stale #6468 (closes #6457) and brings both stacks to parity. `hoistingLimits` mirrors yarn's `nmHoistingLimits`: `none` (default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), `dependencies` (hoist only up to each workspace package's direct deps). It was previously a programmatic-only option in pnpm (no config surface) and a pacquet-only raw-map yaml field. **pnpm CLI:** `config/reader` (`types.ts` enum + `Config.ts` + `configFileKey.ts`), `installing/linking/real-hoist`'s new `getHoistingLimits` (mode → the `@yarnpkg/nm` hoister's per-locator border map), and the install/add/recursive command option lists. Tests: `hoistedNodeLinker/install.ts` (`dependencies` mode) + `real-hoist` `getHoistingLimits` unit tests. Changeset included (minor). **pacquet:** replaced the raw-map config with the same enum; added `get_hoisting_limits` (port of `getHoistingLimits`); and **fixed `real-hoist`'s border semantics** — a name in the limits marks a *border* whose descendants stay nested beneath it, not a leaf to block. (The earlier leaf-blocking behavior was the divergence flagged while porting; its unit tests were rewritten to the corrected semantics.)
|
Revived and merged in #12041. Your Written by an agent (Claude Code, claude-opus-4-8). |
…its setting (#12041) ## 1. Support `nodeLinker: hoisted` on the fresh-lockfile install path (pacquet) Closes #11871. Until now pacquet's `Install::run` hard-refused `nodeLinker: hoisted` without a checked-in lockfile (`ERR_PNPM_…UNSUPPORTED_FRESH_INSTALL_NODE_LINKER`). - Extracted a shared `run_hoisted_linker` helper from the frozen path's hoisted branch (walker → `link_hoisted_modules` → `SymlinkDirectDependencies { link_only: true }` → `pkg_root_by_key` → walker-skip folding), so both install paths run identical logic. - Fresh path now threads `node_linker` + `supported_architectures`, hands `CreateVirtualStore` the real linker (populating `cas_paths_by_pkg_id`), branches on `is_hoisted`, and returns `hoisted_locations` so `.modules.yaml` round-trips. - Removed the guard and the dead `UnsupportedFreshInstallNodeLinker` error variant. Ported upstream's `hoistedNodeLinker/install.ts` into `crates/cli/tests/hoisted_node_linker.rs` (real tests for the core layout, no-lockfile, `externalDependencies`, `autoInstallPeers`, and `hoistingLimits`; the rest stubbed as `known_failures` against `pnpm add`/update (#433) and build-phase (#11870) gaps), and ticked the boxes in `plans/TEST_PORTING.md`. ## 2. Add the `hoistingLimits` setting (pnpm CLI **and** pacquet) Revives the stale #6468 (closes #6457) and brings both stacks to parity. `hoistingLimits` mirrors yarn's `nmHoistingLimits`: `none` (default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), `dependencies` (hoist only up to each workspace package's direct deps). It was previously a programmatic-only option in pnpm (no config surface) and a pacquet-only raw-map yaml field. **pnpm CLI:** `config/reader` (`types.ts` enum + `Config.ts` + `configFileKey.ts`), `installing/linking/real-hoist`'s new `getHoistingLimits` (mode → the `@yarnpkg/nm` hoister's per-locator border map), and the install/add/recursive command option lists. Tests: `hoistedNodeLinker/install.ts` (`dependencies` mode) + `real-hoist` `getHoistingLimits` unit tests. Changeset included (minor). **pacquet:** replaced the raw-map config with the same enum; added `get_hoisting_limits` (port of `getHoistingLimits`); and **fixed `real-hoist`'s border semantics** — a name in the limits marks a *border* whose descendants stay nested beneath it, not a leaf to block. (The earlier leaf-blocking behavior was the divergence flagged while porting; its unit tests were rewritten to the corrected semantics.)
|
🚢 11.5 |
Fixes #6457
This adds a new option which behaves the same as yarn's
nmHoistingLimitsconfig when pnpm is usingnode-linker=hoisted.I have reused the same config names, however, they may require tweaking to reflect
pnpm's terminology. I'd love some feedback on that.It also includes a bugfix needed to get things working; I can split that into another PR.
This PR needs tests, I'm pretty sure. Will work on that.