Skip to content

Installs with the Rust pnpm engine always re-resolve: state-dependent generated manifests and missing dedupePeers option #10542

Description

@zkochan

Findings from profiling bd install in the bit2 workspace (331 components, ~8.5k packages) with the Rust pnpm engine (@pnpm/napi). Every install was taking ~4 minutes even with an up-to-date lockfile, and rm -rf node_modules && bd install appeared to hang at Progress: resolved 0, reused N. The engine-side causes are being fixed in pnpm (see references at the bottom); this issue tracks the two findings that need fixes in Bit, because they force the engine into a full re-resolution on every install regardless of how fast the engine is.

1. Generated component manifests differ depending on whether node_modules exists

Bit's dependency detection produces different manifests for the same workspace state depending on the presence of node_modules:

  • with node_modules present, the generated manifests for ui/api-diff-view, ui/hooks/use-bulk-paged-query, and ui/inline-config-compare include @apollo/client@^3.12.0;
  • with node_modules absent, the same components' manifests do not include it — even though all three genuinely import/require @apollo/client in their source.

The engine's lockfile freshness check therefore flaps forever. Captured from the engine's staleness log (TRACE=pacquet::install=info):

  • install with node_modules present, lockfile from a no-node_modules install: specifiers in the lockfile don't match specifiers in package.json: * 1 dependency was added: @apollo/client@^3.12.0
  • install after rm -rf node_modules, lockfile from a with-node_modules install: ... * 1 dependency was removed: @apollo/client@^3.12.0

Because no lockfile can satisfy both states, every install after removing node_modules (and the next one after it is restored) runs a full re-resolution (~3–4 minutes through the engine today) instead of the frozen path. With the flap fixed, the measured frozen path is ~1s of engine time on a warm workspace and ~5.5s of engine materialization after rm -rf node_modules — the "hang" at resolved 0, reused N was the full re-resolution, not the store/link pipeline.

Expected fix: dependency detection / version attribution must be independent of installed state — a component that imports @apollo/client should get the same manifest entry whether or not node_modules exists.

2. lynx.js does not pass dedupePeers: true to the engine

Bit's existing lockfiles record settings.dedupePeers: true (generated by the previous engine integration). The current installOptions built in scopes/dependencies/pnpm/lynx.ts does not pass dedupePeers, so the engine resolves it to its default (false) and its freshness gate reports:

`dedupePeers` in the lockfile (true) doesn't match the current config (false)

→ every install of an existing Bit repo is treated as outdated, full-resolves, and rewrites the entire lockfile's peer suffixes (a ~50k-line diff), which then keeps churning.

Until now this was not fixable from Bit's side because the @pnpm/napi install options did not expose dedupePeers at all; that binding gap is fixed in pnpm/pnpm#13492. Once the @pnpm/napi release containing it ships, lynx.ts should pass dedupePeers: true alongside dedupePeerDependents: true.

Engine-side context (fixed or in progress on the pnpm side)

For completeness — these were found in the same investigation and are not Bit bugs, but they explain the remaining numbers:

With both Bit-side fixes in place, bd install only pays resolution when dependencies actually change; warm repeat installs take ~1s of engine time and rm -rf node_modules && bd install ~5.5s.


Written by an agent (Claude Code, claude-fable-5), investigating together with Zoltan Kochan.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions