diff --git a/src/plugins.ts b/src/plugins.ts index 76ee215b..a60cc02d 100644 --- a/src/plugins.ts +++ b/src/plugins.ts @@ -1,7 +1,9 @@ import {Config, Errors, Interfaces, ux} from '@oclif/core' import makeDebug from 'debug' -import {access, mkdir, readFile, rm, writeFile} from 'node:fs/promises' +import {spawn} from 'node:child_process' +import {access, mkdir, readFile, rename, rm, writeFile} from 'node:fs/promises' import {dirname, join, resolve} from 'node:path' +import {fileURLToPath} from 'node:url' import {gt, valid, validRange} from 'semver' import {NPM} from './npm.js' @@ -334,11 +336,18 @@ export default class Plugins { // and node_modules to ensure a clean install or update. if (await fileExists(join(this.config.dataDir, 'yarn.lock'))) { this.debug('Found yarn.lock! Removing yarn.lock and node_modules...') - ux.action.status = 'Cleaning up' await Promise.all([ + rename(join(this.config.dataDir, 'node_modules'), join(this.config.dataDir, 'node_modules.old')), rm(join(this.config.dataDir, 'yarn.lock'), {force: true}), - rm(join(this.config.dataDir, 'node_modules'), {force: true, recursive: true}), ]) + + // Spawn a new process so that node_modules can be deleted asynchronously. + const rmScript = join(dirname(fileURLToPath(import.meta.url)), 'rm.js') + this.debug(`spawning ${rmScript} to remove node_modules.old`) + spawn(process.argv[0], [rmScript, join(this.config.dataDir, 'node_modules.old')], { + detached: true, + stdio: 'ignore', + }).unref() } } diff --git a/src/rm.ts b/src/rm.ts new file mode 100644 index 00000000..7f1515b6 --- /dev/null +++ b/src/rm.ts @@ -0,0 +1,5 @@ +import {rm} from 'node:fs/promises' + +const [pathToDelete] = process.argv.slice(2) + +await rm(pathToDelete, {force: true, recursive: true})