mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-10 18:18:56 -04:00
feat: add a new option to the hoister to ignore some deps (#5784)
This commit is contained in:
7
.changeset/healthy-snakes-change.md
Normal file
7
.changeset/healthy-snakes-change.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/core": minor
|
||||
"@pnpm/headless": minor
|
||||
"@pnpm/real-hoist": minor
|
||||
---
|
||||
|
||||
A new option added for avoiding hoisting some dependencies to the root of `node_modules`: `externalDependencies`. This option is a set of dependency names that were added to `node_modules` by another tool. pnpm doesn't have information about these dependencies but they shouldn't be overwritten by hoisted dependencies.
|
||||
@@ -28,6 +28,7 @@ export interface StrictInstallOptions {
|
||||
extraBinPaths: string[]
|
||||
extraEnv: Record<string, string>
|
||||
hoistingLimits?: HoistingLimits
|
||||
externalDependencies?: Set<string>
|
||||
useLockfile: boolean
|
||||
saveLockfile: boolean
|
||||
useGitBranchLockfile: boolean
|
||||
|
||||
@@ -224,3 +224,20 @@ test('hoistingLimits should prevent packages to be hoisted', async () => {
|
||||
expect(fs.existsSync('node_modules/ms')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/send/node_modules/ms')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('externalDependencies should prevent package from being hoisted to the root', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
const externalDependencies = new Set(['ms'])
|
||||
await install({
|
||||
dependencies: {
|
||||
send: '0.17.2',
|
||||
},
|
||||
}, await testDefaults({
|
||||
nodeLinker: 'hoisted',
|
||||
externalDependencies,
|
||||
}))
|
||||
|
||||
expect(fs.existsSync('node_modules/ms')).toBeFalsy()
|
||||
expect(fs.existsSync('node_modules/send/node_modules/ms')).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -109,6 +109,7 @@ export interface HeadlessOptions {
|
||||
extraNodePaths?: string[]
|
||||
preferSymlinkedExecutables?: boolean
|
||||
hoistingLimits?: HoistingLimits
|
||||
externalDependencies?: Set<string>
|
||||
ignoreDepScripts: boolean
|
||||
ignoreScripts: boolean
|
||||
ignorePackageManifest?: boolean
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface LockfileToHoistedDepGraphOptions {
|
||||
engineStrict: boolean
|
||||
force: boolean
|
||||
hoistingLimits?: HoistingLimits
|
||||
externalDependencies?: Set<string>
|
||||
importerIds: string[]
|
||||
include: IncludedDependencies
|
||||
lockfileDir: string
|
||||
@@ -64,7 +65,7 @@ async function _lockfileToHoistedDepGraph (
|
||||
lockfile: Lockfile,
|
||||
opts: LockfileToHoistedDepGraphOptions
|
||||
): Promise<Omit<LockfileToDepGraphResult, 'prevGraph'>> {
|
||||
const tree = hoist(lockfile, { hoistingLimits: opts.hoistingLimits })
|
||||
const tree = hoist(lockfile, { hoistingLimits: opts.hoistingLimits, externalDependencies: opts.externalDependencies })
|
||||
const graph: DependenciesGraph = {}
|
||||
const modulesDir = path.join(opts.lockfileDir, 'node_modules')
|
||||
const fetchDepsOpts = {
|
||||
|
||||
@@ -14,6 +14,9 @@ export function hoist (
|
||||
lockfile: Lockfile,
|
||||
opts?: {
|
||||
hoistingLimits?: HoistingLimits
|
||||
// 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<string>
|
||||
}
|
||||
): HoisterResult {
|
||||
const nodes = new Map<string, HoisterTree>()
|
||||
@@ -27,6 +30,13 @@ export function hoist (
|
||||
...lockfile.importers['.']?.dependencies,
|
||||
...lockfile.importers['.']?.devDependencies,
|
||||
...lockfile.importers['.']?.optionalDependencies,
|
||||
...(Array.from(opts?.externalDependencies ?? [])).reduce((acc, dep) => {
|
||||
// It doesn't matter what version spec is used here.
|
||||
// This dependency will be removed from the tree anyway.
|
||||
// It is only needed to prevent the hoister from hoisting deps with this name to the root of node_modules.
|
||||
acc[dep] = 'link:'
|
||||
return acc
|
||||
}, {}),
|
||||
}),
|
||||
}
|
||||
for (const [importerId, importer] of Object.entries(lockfile.importers)) {
|
||||
@@ -46,7 +56,15 @@ export function hoist (
|
||||
node.dependencies.add(importerNode)
|
||||
}
|
||||
|
||||
return _hoist(node, opts)
|
||||
const hoisterResult = _hoist(node, opts)
|
||||
if (opts?.externalDependencies) {
|
||||
for (const hoistedDep of hoisterResult.dependencies.values()) {
|
||||
if (opts.externalDependencies.has(hoistedDep.name)) {
|
||||
hoisterResult.dependencies.delete(hoistedDep)
|
||||
}
|
||||
}
|
||||
}
|
||||
return hoisterResult
|
||||
}
|
||||
|
||||
function toTree (nodes: Map<string, HoisterTree>, lockfile: Lockfile, deps: Record<string, string>): Set<HoisterTree> {
|
||||
|
||||
Reference in New Issue
Block a user