Skip to content

Commit

Permalink
fix: optimized processing folder renaming in win (fix #7939) (#8019)
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev committed May 4, 2022
1 parent 9974094 commit e5fe1c6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 18 deletions.
23 changes: 9 additions & 14 deletions packages/vite/src/node/optimizer/index.ts
Expand Up @@ -13,7 +13,9 @@ import {
normalizePath,
writeFile,
flattenId,
normalizeId
normalizeId,
removeDirSync,
renameDir
} from '../utils'
import { esbuildDepPlugin } from './esbuildDepPlugin'
import { init, parse } from 'es-module-lexer'
Expand Down Expand Up @@ -116,7 +118,7 @@ export interface DepOptimizationResult {
* the page reload will be delayed until the next rerun so we need
* to be able to discard the result
*/
commit: () => void
commit: () => Promise<void>
cancel: () => void
}

Expand Down Expand Up @@ -194,7 +196,7 @@ export async function optimizeDeps(

const result = await runOptimizeDeps(config, depsInfo)

result.commit()
await result.commit()

return result.metadata
}
Expand Down Expand Up @@ -376,7 +378,7 @@ export async function runOptimizeDeps(
metadata,
commit() {
// Write metadata file, delete `deps` folder and rename the `processing` folder to `deps`
commitProcessingDepsCacheSync()
return commitProcessingDepsCacheSync()
},
cancel
}
Expand Down Expand Up @@ -529,30 +531,23 @@ export async function runOptimizeDeps(
metadata,
commit() {
// Write metadata file, delete `deps` folder and rename the new `processing` folder to `deps` in sync
commitProcessingDepsCacheSync()
return commitProcessingDepsCacheSync()
},
cancel
}

function commitProcessingDepsCacheSync() {
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)
fs.renameSync(processingCacheDir, depsCacheDir)
await renameDir(processingCacheDir, depsCacheDir)
}

function cancel() {
removeDirSync(processingCacheDir)
}
}

function removeDirSync(dir: string) {
if (fs.existsSync(dir)) {
const rmSync = fs.rmSync ?? fs.rmdirSync // TODO: Remove after support for Node 12 is dropped
rmSync(dir, { recursive: true })
}
}

export async function findKnownImports(
config: ResolvedConfig
): Promise<string[]> {
Expand Down
8 changes: 4 additions & 4 deletions packages/vite/src/node/optimizer/registerMissing.ts
Expand Up @@ -189,8 +189,8 @@ export function createOptimizedDeps(server: ViteDevServer): OptimizedDeps {
)
})

const commitProcessing = () => {
processingResult.commit()
const commitProcessing = async () => {
await processingResult.commit()

// While optimizeDeps is running, new missing deps may be discovered,
// in which case they will keep being added to metadata.discovered
Expand Down Expand Up @@ -240,7 +240,7 @@ export function createOptimizedDeps(server: ViteDevServer): OptimizedDeps {
}

if (!needsReload) {
commitProcessing()
await commitProcessing()

if (!isDebugEnabled) {
if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
Expand Down Expand Up @@ -270,7 +270,7 @@ export function createOptimizedDeps(server: ViteDevServer): OptimizedDeps {
}
)
} else {
commitProcessing()
await commitProcessing()

if (!isDebugEnabled) {
if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
Expand Down
48 changes: 48 additions & 0 deletions packages/vite/src/node/utils.ts
Expand Up @@ -3,6 +3,7 @@ import colors from 'picocolors'
import fs from 'fs'
import os from 'os'
import path from 'path'
import { promisify } from 'util'
import { pathToFileURL, URL } from 'url'
import {
FS_PREFIX,
Expand Down Expand Up @@ -522,6 +523,15 @@ export function copyDir(srcDir: string, destDir: string): void {
}
}

export function removeDirSync(dir: string) {
if (fs.existsSync(dir)) {
const rmSync = fs.rmSync ?? fs.rmdirSync // TODO: Remove after support for Node 12 is dropped
rmSync(dir, { recursive: true })
}
}

export const renameDir = isWindows ? promisify(gracefulRename) : fs.renameSync

export function ensureWatchedFile(
watcher: FSWatcher,
file: string | null,
Expand Down Expand Up @@ -737,3 +747,41 @@ export function parseRequest(id: string): Record<string, string> | null {
}

export const blankReplacer = (match: string) => ' '.repeat(match.length)

// Based on node-graceful-fs

// The ISC License
// Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
// https://github.com/isaacs/node-graceful-fs/blob/main/LICENSE

// On Windows, A/V software can lock the directory, causing this
// to fail with an EACCES or EPERM if the directory contains newly
// created files. The original tried for up to 60 seconds, we only
// wait for 5 seconds, as a longer time would be seen as an error

const GRACEFUL_RENAME_TIMEOUT = 5000
function gracefulRename(
from: string,
to: string,
cb: (error: NodeJS.ErrnoException | null) => void
) {
const start = Date.now()
let backoff = 0
fs.rename(from, to, function CB(er) {
if (
er &&
(er.code === 'EACCES' || er.code === 'EPERM') &&
Date.now() - start < GRACEFUL_RENAME_TIMEOUT
) {
setTimeout(function () {
fs.stat(to, function (stater, st) {
if (stater && stater.code === 'ENOENT') gracefulRename(from, to, CB)
else cb(er)
})
}, backoff)
if (backoff < 100) backoff += 10
return
}
if (cb) cb(er)
})
}

0 comments on commit e5fe1c6

Please sign in to comment.