refactor: prune lockfile importers when running pnpm deploy to prepare for allProjectsGraph refactor (#9258)

* feat: support `pruneLockfileImporters` as argument to install

* fix: remove unnecessary importers from filtered lockfile during deploy
This commit is contained in:
Brandon Cheng
2025-03-10 21:52:32 -04:00
committed by GitHub
parent 221fe80b94
commit cda1c43dad
6 changed files with 39 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/plugin-commands-installation": minor
---
The `install` function now accepts a `pruneLockfileImporters` option. This is used internally by pnpm to create a more accurate filtered lockfile.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/plugin-commands-deploy": patch
---
An internal refactor was made to the `deploy` command to better handle a change in `plugin-commands-installation` when `node-linker=hoisted`. There are no behavior changes expected with this refactor.

View File

@@ -323,6 +323,7 @@ export type InstallCommandOptions = Pick<Config,
frozenLockfileIfExists?: boolean
useBetaCli?: boolean
pruneDirectDependencies?: boolean
pruneLockfileImporters?: boolean
pruneStore?: boolean
recursive?: boolean
resolutionOnly?: boolean

View File

@@ -135,6 +135,7 @@ export type InstallDepsOptions = Pick<Config,
includeOnlyPackageFiles?: boolean
prepareExecutionEnv: PrepareExecutionEnv
fetchFullMetadata?: boolean
pruneLockfileImporters?: boolean
} & Partial<Pick<Config, 'pnpmHomeDir' | 'strictDepBuilds'>>
export async function installDeps (

View File

@@ -92,6 +92,7 @@ export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
selectedProjectsGraph: ProjectsGraph
preferredVersions?: PreferredVersions
pruneDirectDependencies?: boolean
pruneLockfileImporters?: boolean
storeControllerAndDir?: {
ctrl: StoreController
dir: string
@@ -139,8 +140,9 @@ export async function recursive (
linkWorkspacePackagesDepth: opts.linkWorkspacePackages === 'deep' ? Infinity : opts.linkWorkspacePackages ? 0 : -1,
ownLifecycleHooksStdio: 'pipe',
peer: opts.savePeer,
pruneLockfileImporters: ((opts.ignoredPackages == null) || opts.ignoredPackages.size === 0) &&
pkgs.length === allProjects.length,
pruneLockfileImporters: opts.pruneLockfileImporters ??
(((opts.ignoredPackages == null) || opts.ignoredPackages.size === 0) &&
pkgs.length === allProjects.length),
storeController: store.ctrl,
storeDir: store.dir,
targetDependenciesField,

View File

@@ -142,6 +142,29 @@ export async function handler (opts: DeployOptions, params: string[]): Promise<v
// dedupe-injected-deps to always inject workspace packages since copying is
// desirable.
dedupeInjectedDeps: false,
// Compute the wanted lockfile correctly by setting pruneLockfileImporters.
// Since pnpm deploy only installs dependencies for a single selected
// project, other projects in the "importers" lockfile section will be
// empty when node-linker=hoisted.
//
// For example, when deploying project-1, project-2 may not be populated,
// even if it has dependencies.
//
// importers:
// project-1:
// dependencies:
// foo:
// specifier: ^1.0.0
// version: ^1.0.0
// project-2: {}
//
// Avoid including these empty importers in the in-memory wanted lockfile.
// This is important when node-linker=hoisted to prevent project-2 from
// being included in the hoisted install. If project-2 is errantly hoisted
// to the root node_modules dir, downstream logic will fail to inject it to
// the deploy directory. It's also just weird to include empty importers
// that don't matter to the filtered lockfile generated for pnpm deploy.
pruneLockfileImporters: true,
depth: Infinity,
hooks: {
...opts.hooks,