diff --git a/common/changes/@microsoft/rush/tune-prepare-async_2025-08-20-01-11.json b/common/changes/@microsoft/rush/tune-prepare-async_2025-08-20-01-11.json new file mode 100644 index 00000000000..1c81c3b8f20 --- /dev/null +++ b/common/changes/@microsoft/rush/tune-prepare-async_2025-08-20-01-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Fix poor performance scaling during `rush install` when identifying projects in the lockfile that no longer exist.", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index 6f03421a064..e6ba5b3a8d0 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -42,6 +42,7 @@ import type { ResolvedDependencies } from '@pnpm/lockfile.types'; import { convertLockfileV9ToLockfileObject } from './PnpmShrinkWrapFileConverters'; +import type { IReadonlyLookupByPath } from '@rushstack/lookup-by-path'; const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); @@ -812,12 +813,15 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return super.findOrphanedProjects(rushConfiguration, subspace); } + const subspaceTempFolder: string = subspace.getSubspaceTempFolderPath(); + const lookup: IReadonlyLookupByPath = + rushConfiguration.getProjectLookupForRoot(subspaceTempFolder); + const orphanedProjectPaths: string[] = []; for (const importerKey of this.getImporterKeys()) { - // PNPM importer keys are relative paths from the workspace root, which is the common temp folder - const rushProjectPath: string = path.resolve(subspace.getSubspaceTempFolderPath(), importerKey); - if (!rushConfiguration.tryGetProjectForPath(rushProjectPath)) { - orphanedProjectPaths.push(rushProjectPath); + if (!lookup.findChildPath(importerKey)) { + // PNPM importer keys are relative paths from the workspace root, which is the common temp folder + orphanedProjectPaths.push(path.resolve(subspaceTempFolder, importerKey)); } } return orphanedProjectPaths;