diff --git a/.changeset/quiet-moons-sparkle.md b/.changeset/quiet-moons-sparkle.md new file mode 100644 index 0000000000..11aefdf7e0 --- /dev/null +++ b/.changeset/quiet-moons-sparkle.md @@ -0,0 +1,7 @@ +--- +"@pnpm/real-hoist": patch +"@pnpm/headless": patch +"pnpm": patch +--- + +Peer dependencies of subdependencies should be installed, when `node-linker` is set to `hoisted` [#6680](https://github.com/pnpm/pnpm/pull/6680). diff --git a/pkg-manager/core/test/hoistedNodeLinker/install.ts b/pkg-manager/core/test/hoistedNodeLinker/install.ts index b32f222c08..6cebca34a6 100644 --- a/pkg-manager/core/test/hoistedNodeLinker/install.ts +++ b/pkg-manager/core/test/hoistedNodeLinker/install.ts @@ -316,3 +316,17 @@ test('linking bins of local projects when node-linker is set to hoisted', async expect(fs.existsSync('project-1/node_modules/.bin/project-2')).toBeTruthy() }) + +test('peerDependencies should be installed when autoInstallPeers is set to true and nodeLinker is set to hoisted', async () => { + prepareEmpty() + await install({ + dependencies: { + 'react-dom': '18.2.0', + }, + }, await testDefaults({ + nodeLinker: 'hoisted', + autoInstallPeers: true, + })) + + expect(fs.existsSync('node_modules/react')).toBeTruthy() +}) diff --git a/pkg-manager/headless/src/lockfileToDepGraph.ts b/pkg-manager/headless/src/lockfileToDepGraph.ts index 49a9466b21..fff008ec7d 100644 --- a/pkg-manager/headless/src/lockfileToDepGraph.ts +++ b/pkg-manager/headless/src/lockfileToDepGraph.ts @@ -53,6 +53,7 @@ export interface DependenciesGraph { } export interface LockfileToDepGraphOptions { + autoInstallPeers: boolean engineStrict: boolean force: boolean importerIds: string[] diff --git a/pkg-manager/headless/src/lockfileToHoistedDepGraph.ts b/pkg-manager/headless/src/lockfileToHoistedDepGraph.ts index 7fe3e067bc..54523ebbfc 100644 --- a/pkg-manager/headless/src/lockfileToHoistedDepGraph.ts +++ b/pkg-manager/headless/src/lockfileToHoistedDepGraph.ts @@ -27,6 +27,7 @@ import { } from './lockfileToDepGraph' export interface LockfileToHoistedDepGraphOptions { + autoInstallPeers: boolean engineStrict: boolean force: boolean hoistingLimits?: HoistingLimits @@ -68,7 +69,11 @@ async function _lockfileToHoistedDepGraph ( lockfile: Lockfile, opts: LockfileToHoistedDepGraphOptions ): Promise> { - const tree = hoist(lockfile, { hoistingLimits: opts.hoistingLimits, externalDependencies: opts.externalDependencies }) + const tree = hoist(lockfile, { + hoistingLimits: opts.hoistingLimits, + externalDependencies: opts.externalDependencies, + autoInstallPeers: opts.autoInstallPeers, + }) const graph: DependenciesGraph = {} const modulesDir = path.join(opts.lockfileDir, 'node_modules') const fetchDepsOpts = { diff --git a/pkg-manager/real-hoist/src/index.ts b/pkg-manager/real-hoist/src/index.ts index 919fd180f3..8554dc46ce 100644 --- a/pkg-manager/real-hoist/src/index.ts +++ b/pkg-manager/real-hoist/src/index.ts @@ -17,6 +17,7 @@ export function hoist ( // This option was added for Bit CLI in order to prevent pnpm from overwriting dependencies linked by Bit. // However, in the future it might be useful to use it in pnpm for skipping any dependencies added by external tools. externalDependencies?: Set + autoInstallPeers?: boolean } ): HoisterResult { const nodes = new Map() @@ -37,7 +38,7 @@ export function hoist ( acc[dep] = 'link:' return acc }, {} as Record), - }), + }, opts?.autoInstallPeers), } for (const [importerId, importer] of Object.entries(lockfile.importers)) { if (importerId === '.') continue @@ -51,7 +52,7 @@ export function hoist ( ...importer.dependencies, ...importer.devDependencies, ...importer.optionalDependencies, - }), + }, opts?.autoInstallPeers), } node.dependencies.add(importerNode) } @@ -67,7 +68,12 @@ export function hoist ( return hoisterResult } -function toTree (nodes: Map, lockfile: Lockfile, deps: Record): Set { +function toTree ( + nodes: Map, + lockfile: Lockfile, + deps: Record, + autoInstallPeers?: boolean +): Set { return new Set(Object.entries(deps).map(([alias, ref]) => { const depPath = dp.refToRelative(ref, alias)! if (!depPath) { @@ -100,10 +106,12 @@ function toTree (nodes: Map, lockfile: Lockfile, deps: Reco reference: depPath, dependencyKind: HoisterDependencyKind.REGULAR, dependencies: new Set(), - peerNames: new Set([ - ...Object.keys(pkgSnapshot.peerDependencies ?? {}), - ...(pkgSnapshot.transitivePeerDependencies ?? []), - ]), + peerNames: new Set(autoInstallPeers + ? [] + : [ + ...Object.keys(pkgSnapshot.peerDependencies ?? {}), + ...(pkgSnapshot.transitivePeerDependencies ?? []), + ]), } nodes.set(key, node) node.dependencies = toTree(nodes, lockfile, { ...pkgSnapshot.dependencies, ...pkgSnapshot.optionalDependencies })