fix(get-context): avoid excess purge prompts (#7639)

* fix(get-context): avoid excess purge prompts

pnpm sometimes needs to purge modules folders (node_modules) when
certain configuration changes (in other words, when it needs to start
from scratch).

This prompt, problematically, was getting triggered asynchronously for
each importer in the workspace that needed a purge, which would
sometimes lead to gargantuan prompts instead of one consolidated prompt.

The fix is to queue up which importers need a purge, then fire the
prompter all at once.

Closes #7320

* fix: reuse ImporterToPurge type

* refactor: apply suggestions from code review

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
Steven Petryk
2024-02-12 10:52:18 -08:00
committed by GitHub
parent 36dcaa0163
commit 19c4b4f973
2 changed files with 27 additions and 17 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/get-context": patch
"pnpm": patch
---
When purging multiple node_modules folders, pnpm will no longer print multiple prompts simultaneously.

View File

@@ -101,6 +101,10 @@ export interface GetContextOptions {
forcePublicHoistPattern?: boolean
global?: boolean
}
interface ImporterToPurge {
modulesDir: string
rootDir: string
}
export async function getContext (
opts: GetContextOptions
@@ -243,7 +247,9 @@ async function validateModules (
' Run "pnpm install" to recreate the modules directory.'
)
}
let purged = false
const importersToPurge: ImporterToPurge[] = []
if (opts.forceHoistPattern && (rootProject != null)) {
try {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
@@ -256,11 +262,10 @@ async function validateModules (
}
} catch (err: any) { // eslint-disable-line
if (!opts.forceNewModules) throw err
await purgeModulesDirsOfImporter(opts, rootProject)
purged = true
importersToPurge.push(rootProject)
}
}
await Promise.all(projects.map(async (project) => {
for (const project of projects) {
try {
checkCompatibility(modules, {
modulesDir: project.modulesDir,
@@ -279,16 +284,21 @@ async function validateModules (
}
} catch (err: any) { // eslint-disable-line
if (!opts.forceNewModules) throw err
await purgeModulesDirsOfImporter(opts, project)
purged = true
importersToPurge.push(project)
}
}))
if (purged && (rootProject == null)) {
await purgeModulesDirsOfImporter(opts, {
}
if (importersToPurge.length > 0 && (rootProject == null)) {
importersToPurge.push({
modulesDir: path.join(opts.lockfileDir, opts.modulesDir),
rootDir: opts.lockfileDir,
})
}
const purged = importersToPurge.length > 0
if (purged) {
await purgeModulesDirsOfImporters(opts, importersToPurge)
}
return { purged }
}
@@ -297,10 +307,7 @@ async function purgeModulesDirsOfImporter (
confirmModulesPurge?: boolean
virtualStoreDir: string
},
importer: {
modulesDir: string
rootDir: string
}
importer: ImporterToPurge
) {
return purgeModulesDirsOfImporters(opts, [importer])
}
@@ -310,10 +317,7 @@ async function purgeModulesDirsOfImporters (
confirmModulesPurge?: boolean
virtualStoreDir: string
},
importers: Array<{
modulesDir: string
rootDir: string
}>
importers: ImporterToPurge[]
) {
if (opts.confirmModulesPurge ?? true) {
const confirmed = await enquirer.prompt({