From 67743a3c4c50705288c8ee1cc320d87f0c1c4661 Mon Sep 17 00:00:00 2001 From: Matt Nathan Date: Sun, 22 May 2022 14:15:08 +0100 Subject: [PATCH] fix: EPERM error on Windows when processing dependencies (#8235) Co-authored-by: patak-dev --- packages/vite/src/node/optimizer/index.ts | 3 +- packages/vite/src/node/utils.ts | 35 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index de09f978cd505c..b31cd7a1b595bf 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -15,6 +15,7 @@ import { lookupFile, normalizeId, normalizePath, + removeDir, removeDirSync, renameDir, writeFile @@ -534,7 +535,7 @@ export async function runOptimizeDeps( async function commitProcessingDepsCacheSync() { // Processing is done, we can now replace the depsCacheDir with processingCacheDir // Rewire the file paths from the temporal processing dir to the final deps cache dir - removeDirSync(depsCacheDir) + await removeDir(depsCacheDir) await renameDir(processingCacheDir, depsCacheDir) } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index dc0d979d664450..a3573d2a6dc1de 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -539,6 +539,9 @@ export function removeDirSync(dir: string) { } } +export const removeDir = isWindows + ? promisify(gracefulRemoveDir) + : removeDirSync export const renameDir = isWindows ? promisify(gracefulRename) : fs.renameSync export function ensureWatchedFile( @@ -834,6 +837,38 @@ function gracefulRename( }) } +const GRACEFUL_REMOVE_DIR_TIMEOUT = 5000 +function gracefulRemoveDir( + dir: string, + cb: (error: NodeJS.ErrnoException | null) => void +) { + const rmdir = fs.rm ?? fs.rmdir // TODO: Remove after support for Node 12 is dropped + const start = Date.now() + let backoff = 0 + rmdir(dir, { recursive: true }, function CB(er) { + if (er) { + if ( + (er.code === 'ENOTEMPTY' || + er.code === 'EACCES' || + er.code === 'EPERM') && + Date.now() - start < GRACEFUL_REMOVE_DIR_TIMEOUT + ) { + setTimeout(function () { + rmdir(dir, { recursive: true }, CB) + }, backoff) + if (backoff < 100) backoff += 10 + return + } + + if (er.code === 'ENOENT') { + er = null + } + } + + if (cb) cb(er) + }) +} + export function emptyCssComments(raw: string) { return raw.replace(multilineCommentsRE, (s) => ' '.repeat(s.length)) }