refactor!: remove fs.cachedChecks option (#18493)

This commit is contained in:
patak 2024-10-31 05:13:20 +01:00 committed by GitHub
parent 5d6dc491b6
commit 94b0857353
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 69 additions and 505 deletions

View File

@ -329,14 +329,6 @@ export default defineConfig({
Blocklist for sensitive files being restricted to be served by Vite dev server. This will have higher priority than [`server.fs.allow`](#server-fs-allow). [picomatch patterns](https://github.com/micromatch/picomatch#globbing-features) are supported.
## server.fs.cachedChecks
- **Type:** `boolean`
- **Default:** `false`
- **Experimental**
Caches filenames of accessed directories to avoid repeated filesystem operations. Particularly in Windows, this could result in a performance boost. It is disabled by default due to edge cases when writing a file in a cached folder and immediately importing it.
## server.origin
- **Type:** `string`

View File

@ -66,6 +66,8 @@ There are other breaking changes which only affect few users.
- [`commonjsOptions.strictRequires`](https://github.com/rollup/plugins/blob/master/packages/commonjs/README.md#strictrequires) is now `true` by default (was `'auto'` before).
- [[#18243] chore(deps)!: migrate `fast-glob` to `tinyglobby`](https://github.com/vitejs/vite/pull/18243)
- Range braces (`{01..03}` ⇒ `['01', '02', '03']`) and incremental braces (`{2..8..2}` ⇒ `['2', '4', '6', '8']`) are no longer supported in globs.
- [[#18493] refactor!: remove fs.cachedChecks option](https://github.com/vitejs/vite/pull/18493)
- This opt-in optimization was removed due to edge cases when writing a file in a cached folder and immediately importing it.
## Migration from v4

View File

@ -1,433 +0,0 @@
import fs from 'node:fs'
import path from 'node:path'
import type { FSWatcher } from 'dep-types/chokidar'
import type { ResolvedConfig } from './config'
import {
isInNodeModules,
normalizePath,
safeRealpathSync,
tryStatSync,
} from './utils'
export interface FsUtils {
existsSync: (path: string) => boolean
isDirectory: (path: string) => boolean
tryResolveRealFile: (
path: string,
preserveSymlinks?: boolean,
) => string | undefined
tryResolveRealFileWithExtensions: (
path: string,
extensions: string[],
preserveSymlinks?: boolean,
) => string | undefined
tryResolveRealFileOrType: (
path: string,
preserveSymlinks?: boolean,
) => { path?: string; type: 'directory' | 'file' } | undefined
initWatcher?: (watcher: FSWatcher) => void
}
// An implementation of fsUtils without caching
export const commonFsUtils: FsUtils = {
existsSync: fs.existsSync,
isDirectory,
tryResolveRealFile,
tryResolveRealFileWithExtensions,
tryResolveRealFileOrType,
}
const cachedFsUtilsMap = new WeakMap<ResolvedConfig, FsUtils>()
export function getFsUtils(config: ResolvedConfig): FsUtils {
let fsUtils = cachedFsUtilsMap.get(config)
if (!fsUtils) {
if (
config.command !== 'serve' ||
config.server.fs.cachedChecks !== true ||
config.server.watch?.ignored ||
process.versions.pnp
) {
// cached fsUtils is only used in the dev server for now
// it is disabled by default due to potential edge cases when writing a file
// and reading it immediately
// It is also disabled when there aren't custom watcher ignored patterns configured
// and if yarn pnp isn't used
fsUtils = commonFsUtils
} else if (
!config.resolve.preserveSymlinks &&
config.root !== getRealPath(config.root)
) {
fsUtils = commonFsUtils
} else {
fsUtils = createCachedFsUtils(config)
}
cachedFsUtilsMap.set(config, fsUtils)
}
return fsUtils
}
type DirentsMap = Map<string, DirentCache>
type DirentCacheType =
| 'directory'
| 'file'
| 'symlink'
| 'error'
| 'directory_maybe_symlink'
| 'file_maybe_symlink'
interface DirentCache {
dirents?: DirentsMap
type: DirentCacheType
}
function readDirCacheSync(file: string): undefined | DirentsMap {
let dirents: fs.Dirent[]
try {
dirents = fs.readdirSync(file, { withFileTypes: true })
} catch {
return
}
return direntsToDirentMap(dirents)
}
function direntsToDirentMap(fsDirents: fs.Dirent[]): DirentsMap {
const dirents: DirentsMap = new Map()
for (const dirent of fsDirents) {
// We ignore non directory, file, and symlink entries
const type = dirent.isDirectory()
? 'directory'
: dirent.isSymbolicLink()
? 'symlink'
: dirent.isFile()
? 'file'
: undefined
if (type) {
dirents.set(dirent.name, { type })
}
}
return dirents
}
function ensureFileMaybeSymlinkIsResolved(
direntCache: DirentCache,
filePath: string,
) {
if (direntCache.type !== 'file_maybe_symlink') return
const isSymlink = fs
.lstatSync(filePath, { throwIfNoEntry: false })
?.isSymbolicLink()
direntCache.type =
isSymlink === undefined ? 'error' : isSymlink ? 'symlink' : 'file'
}
function pathUntilPart(root: string, parts: string[], i: number): string {
let p = root
for (let k = 0; k < i; k++) p += '/' + parts[k]
return p
}
export function createCachedFsUtils(config: ResolvedConfig): FsUtils {
const root = config.root // root is resolved and normalized, so it doesn't have a trailing slash
const rootDirPath = `${root}/`
const rootCache: DirentCache = { type: 'directory' } // dirents will be computed lazily
const getDirentCacheSync = (parts: string[]): DirentCache | undefined => {
let direntCache: DirentCache = rootCache
for (let i = 0; i < parts.length; i++) {
if (direntCache.type === 'directory') {
let dirPath
if (!direntCache.dirents) {
dirPath = pathUntilPart(root, parts, i)
const dirents = readDirCacheSync(dirPath)
if (!dirents) {
direntCache.type = 'error'
return
}
direntCache.dirents = dirents
}
const nextDirentCache = direntCache.dirents!.get(parts[i])
if (!nextDirentCache) {
return
}
if (nextDirentCache.type === 'directory_maybe_symlink') {
dirPath ??= pathUntilPart(root, parts, i + 1)
const isSymlink = fs
.lstatSync(dirPath, { throwIfNoEntry: false })
?.isSymbolicLink()
nextDirentCache.type = isSymlink ? 'symlink' : 'directory'
}
direntCache = nextDirentCache
} else if (direntCache.type === 'symlink') {
// early return if we encounter a symlink
return direntCache
} else if (direntCache.type === 'error') {
return direntCache
} else {
if (i !== parts.length - 1) {
return
}
if (direntCache.type === 'file_maybe_symlink') {
ensureFileMaybeSymlinkIsResolved(
direntCache,
pathUntilPart(root, parts, i),
)
return direntCache
} else if (direntCache.type === 'file') {
return direntCache
} else {
return
}
}
}
return direntCache
}
function getDirentCacheFromPath(
normalizedFile: string,
): DirentCache | false | undefined {
// path.posix.normalize may return a path either with / or without /
if (normalizedFile[normalizedFile.length - 1] === '/') {
normalizedFile = normalizedFile.slice(0, -1)
}
if (normalizedFile === root) {
return rootCache
}
if (!normalizedFile.startsWith(rootDirPath)) {
return undefined
}
const pathFromRoot = normalizedFile.slice(rootDirPath.length)
const parts = pathFromRoot.split('/')
const direntCache = getDirentCacheSync(parts)
if (!direntCache || direntCache.type === 'error') {
return false
}
return direntCache
}
function onPathAdd(
file: string,
type: 'directory_maybe_symlink' | 'file_maybe_symlink',
) {
const direntCache = getDirentCacheFromPath(
normalizePath(path.dirname(file)),
)
if (
direntCache &&
direntCache.type === 'directory' &&
direntCache.dirents
) {
direntCache.dirents.set(path.basename(file), { type })
}
}
function onPathUnlink(file: string) {
const direntCache = getDirentCacheFromPath(
normalizePath(path.dirname(file)),
)
if (
direntCache &&
direntCache.type === 'directory' &&
direntCache.dirents
) {
direntCache.dirents.delete(path.basename(file))
}
}
return {
existsSync(file: string) {
if (isInNodeModules(file)) {
return fs.existsSync(file)
}
const normalizedFile = normalizePath(file)
const direntCache = getDirentCacheFromPath(normalizedFile)
if (
direntCache === undefined ||
(direntCache && direntCache.type === 'symlink')
) {
// fallback to built-in fs for out-of-root and symlinked files
return fs.existsSync(file)
}
return !!direntCache
},
tryResolveRealFile(
file: string,
preserveSymlinks?: boolean,
): string | undefined {
if (isInNodeModules(file)) {
return tryResolveRealFile(file, preserveSymlinks)
}
const normalizedFile = normalizePath(file)
const direntCache = getDirentCacheFromPath(normalizedFile)
if (
direntCache === undefined ||
(direntCache && direntCache.type === 'symlink')
) {
// fallback to built-in fs for out-of-root and symlinked files
return tryResolveRealFile(file, preserveSymlinks)
}
if (!direntCache || direntCache.type === 'directory') {
return
}
// We can avoid getRealPath even if preserveSymlinks is false because we know it's
// a file without symlinks in its path
return normalizedFile
},
tryResolveRealFileWithExtensions(
file: string,
extensions: string[],
preserveSymlinks?: boolean,
): string | undefined {
if (isInNodeModules(file)) {
return tryResolveRealFileWithExtensions(
file,
extensions,
preserveSymlinks,
)
}
const normalizedFile = normalizePath(file)
const dirPath = path.posix.dirname(normalizedFile)
const direntCache = getDirentCacheFromPath(dirPath)
if (
direntCache === undefined ||
(direntCache && direntCache.type === 'symlink')
) {
// fallback to built-in fs for out-of-root and symlinked files
return tryResolveRealFileWithExtensions(
file,
extensions,
preserveSymlinks,
)
}
if (!direntCache || direntCache.type !== 'directory') {
return
}
if (!direntCache.dirents) {
const dirents = readDirCacheSync(dirPath)
if (!dirents) {
direntCache.type = 'error'
return
}
direntCache.dirents = dirents
}
const base = path.posix.basename(normalizedFile)
for (const ext of extensions) {
const fileName = base + ext
const fileDirentCache = direntCache.dirents.get(fileName)
if (fileDirentCache) {
const filePath = dirPath + '/' + fileName
ensureFileMaybeSymlinkIsResolved(fileDirentCache, filePath)
if (fileDirentCache.type === 'symlink') {
// fallback to built-in fs for symlinked files
return tryResolveRealFile(filePath, preserveSymlinks)
}
if (fileDirentCache.type === 'file') {
return filePath
}
}
}
},
tryResolveRealFileOrType(
file: string,
preserveSymlinks?: boolean,
): { path?: string; type: 'directory' | 'file' } | undefined {
if (isInNodeModules(file)) {
return tryResolveRealFileOrType(file, preserveSymlinks)
}
const normalizedFile = normalizePath(file)
const direntCache = getDirentCacheFromPath(normalizedFile)
if (
direntCache === undefined ||
(direntCache && direntCache.type === 'symlink')
) {
// fallback to built-in fs for out-of-root and symlinked files
return tryResolveRealFileOrType(file, preserveSymlinks)
}
if (!direntCache) {
return
}
if (direntCache.type === 'directory') {
return { type: 'directory' }
}
// We can avoid getRealPath even if preserveSymlinks is false because we know it's
// a file without symlinks in its path
return { path: normalizedFile, type: 'file' }
},
isDirectory(dirPath: string) {
if (isInNodeModules(dirPath)) {
return isDirectory(dirPath)
}
const direntCache = getDirentCacheFromPath(normalizePath(dirPath))
if (
direntCache === undefined ||
(direntCache && direntCache.type === 'symlink')
) {
// fallback to built-in fs for out-of-root and symlinked files
return isDirectory(dirPath)
}
return direntCache && direntCache.type === 'directory'
},
initWatcher(watcher: FSWatcher) {
watcher.on('add', (file) => {
onPathAdd(file, 'file_maybe_symlink')
})
watcher.on('addDir', (dir) => {
onPathAdd(dir, 'directory_maybe_symlink')
})
watcher.on('unlink', onPathUnlink)
watcher.on('unlinkDir', onPathUnlink)
},
}
}
function tryResolveRealFile(
file: string,
preserveSymlinks?: boolean,
): string | undefined {
const stat = tryStatSync(file)
if (stat?.isFile()) return getRealPath(file, preserveSymlinks)
}
function tryResolveRealFileWithExtensions(
filePath: string,
extensions: string[],
preserveSymlinks?: boolean,
): string | undefined {
for (const ext of extensions) {
const res = tryResolveRealFile(filePath + ext, preserveSymlinks)
if (res) return res
}
}
function tryResolveRealFileOrType(
file: string,
preserveSymlinks?: boolean,
): { path?: string; type: 'directory' | 'file' } | undefined {
const fileStat = tryStatSync(file)
if (fileStat?.isFile()) {
return { path: getRealPath(file, preserveSymlinks), type: 'file' }
}
if (fileStat?.isDirectory()) {
return { type: 'directory' }
}
return
}
function getRealPath(resolved: string, preserveSymlinks?: boolean): string {
if (!preserveSymlinks) {
resolved = safeRealpathSync(resolved)
}
return normalizePath(resolved)
}
function isDirectory(path: string): boolean {
const stat = tryStatSync(path)
return stat?.isDirectory() ?? false
}

View File

@ -5,7 +5,6 @@ import type { EnvironmentPluginContainer } from './server/pluginContainer'
import { createEnvironmentPluginContainer } from './server/pluginContainer'
import { resolvePlugin } from './plugins/resolve'
import type { InternalResolveOptions } from './plugins/resolve'
import { getFsUtils } from './fsUtils'
import type { Environment } from './environment'
import type { PartialEnvironment } from './baseEnvironment'
@ -69,7 +68,6 @@ export function createIdResolver(
preferRelative: false,
tryIndex: true,
...options,
fsUtils: getFsUtils(config),
// Ignore sideEffects and other computations as we only need the id
idOnly: true,
}),

View File

@ -1,4 +1,5 @@
import path from 'node:path'
import fs from 'node:fs'
import { performance } from 'node:perf_hooks'
import colors from 'picocolors'
import MagicString from 'magic-string'
@ -52,7 +53,6 @@ import {
transformStableResult,
urlRE,
} from '../utils'
import { getFsUtils } from '../fsUtils'
import { checkPublicFile } from '../publicDir'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
@ -107,7 +107,6 @@ export function normalizeResolvedIdToUrl(
): string {
const root = environment.config.root
const depsOptimizer = environment.depsOptimizer
const fsUtils = getFsUtils(environment.getTopLevelConfig())
// normalize all imports into resolved URLs
// e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
@ -121,7 +120,7 @@ export function normalizeResolvedIdToUrl(
// We'll remove this as soon we're able to fix the react plugins.
(resolved.id !== '/@react-refresh' &&
path.isAbsolute(resolved.id) &&
fsUtils.existsSync(cleanUrl(resolved.id)))
fs.existsSync(cleanUrl(resolved.id)))
) {
// an optimized deps may not yet exists in the filesystem, or
// a regular file exists but is out of root: rewrite to absolute /@fs/ paths

View File

@ -4,7 +4,6 @@ import type { PluginHookUtils, ResolvedConfig } from '../config'
import { isDepOptimizationDisabled } from '../optimizer'
import type { HookHandler, Plugin, PluginWithRequiredHook } from '../plugin'
import { watchPackageDataPlugin } from '../packages'
import { getFsUtils } from '../fsUtils'
import { jsonPlugin } from './json'
import { resolvePlugin } from './resolve'
import { optimizedDepsPlugin } from './optimizedDeps'
@ -65,7 +64,6 @@ export async function resolvePlugins(
isBuild,
packageCache: config.packageCache,
asSrc: true,
fsUtils: getFsUtils(config),
optimizeDeps: true,
externalize: true,
},

View File

@ -1,4 +1,5 @@
import path from 'node:path'
import fs from 'node:fs'
import type {
Alias,
AliasOptions,
@ -13,7 +14,6 @@ import {
isOptimizable,
moduleListContains,
} from '../utils'
import { getFsUtils } from '../fsUtils'
import { cleanUrl, withTrailingSlash } from '../../shared/utils'
import { tryOptimizedResolve } from './resolve'
@ -23,7 +23,6 @@ import { tryOptimizedResolve } from './resolve'
export function preAliasPlugin(config: ResolvedConfig): Plugin {
const findPatterns = getAliasPatterns(config.resolve.alias)
const isBuild = config.command === 'build'
const fsUtils = getFsUtils(config)
return {
name: 'vite:pre-alias',
async resolveId(id, importer, options) {
@ -60,7 +59,7 @@ export function preAliasPlugin(config: ResolvedConfig): Plugin {
const isVirtual = resolvedId === id || resolvedId.includes('\0')
if (
!isVirtual &&
fsUtils.existsSync(resolvedId) &&
fs.existsSync(resolvedId) &&
!moduleListContains(optimizeDeps.exclude, id) &&
path.isAbsolute(resolvedId) &&
(isInNodeModules(resolvedId) ||

View File

@ -38,8 +38,6 @@ import { optimizedDepInfoFromFile, optimizedDepInfoFromId } from '../optimizer'
import type { DepsOptimizer } from '../optimizer'
import type { DepOptimizationOptions, SSROptions } from '..'
import type { PackageCache, PackageData } from '../packages'
import type { FsUtils } from '../fsUtils'
import { commonFsUtils } from '../fsUtils'
import { shouldExternalize } from '../external'
import {
findNearestMainPackageData,
@ -113,7 +111,6 @@ interface ResolvePluginOptions {
isBuild: boolean
isProduction: boolean
packageCache?: PackageCache
fsUtils?: FsUtils
/**
* src code mode also attempts the following:
* - resolving /xxx as URLs
@ -629,13 +626,8 @@ function tryCleanFsResolve(
): string | undefined {
const { tryPrefix, extensions, preserveSymlinks } = options
const fsUtils = options.fsUtils ?? commonFsUtils
// Optimization to get the real type or file type (directory, file, other)
const fileResult = fsUtils.tryResolveRealFileOrType(
file,
options.preserveSymlinks,
)
const fileResult = tryResolveRealFileOrType(file, options.preserveSymlinks)
if (fileResult?.path) return fileResult.path
@ -645,13 +637,13 @@ function tryCleanFsResolve(
const possibleJsToTs = options.isFromTsImporter && isPossibleTsOutput(file)
if (possibleJsToTs || options.extensions.length || tryPrefix) {
const dirPath = path.dirname(file)
if (fsUtils.isDirectory(dirPath)) {
if (isDirectory(dirPath)) {
if (possibleJsToTs) {
// try resolve .js, .mjs, .cjs or .jsx import to typescript file
const fileExt = path.extname(file)
const fileName = file.slice(0, -fileExt.length)
if (
(res = fsUtils.tryResolveRealFile(
(res = tryResolveRealFile(
fileName + fileExt.replace('js', 'ts'),
preserveSymlinks,
))
@ -660,16 +652,13 @@ function tryCleanFsResolve(
// for .js, also try .tsx
if (
fileExt === '.js' &&
(res = fsUtils.tryResolveRealFile(
fileName + '.tsx',
preserveSymlinks,
))
(res = tryResolveRealFile(fileName + '.tsx', preserveSymlinks))
)
return res
}
if (
(res = fsUtils.tryResolveRealFileWithExtensions(
(res = tryResolveRealFileWithExtensions(
file,
extensions,
preserveSymlinks,
@ -680,11 +669,10 @@ function tryCleanFsResolve(
if (tryPrefix) {
const prefixed = `${dirPath}/${options.tryPrefix}${path.basename(file)}`
if ((res = fsUtils.tryResolveRealFile(prefixed, preserveSymlinks)))
return res
if ((res = tryResolveRealFile(prefixed, preserveSymlinks))) return res
if (
(res = fsUtils.tryResolveRealFileWithExtensions(
(res = tryResolveRealFileWithExtensions(
prefixed,
extensions,
preserveSymlinks,
@ -702,7 +690,7 @@ function tryCleanFsResolve(
if (!skipPackageJson) {
let pkgPath = `${dirPath}/package.json`
try {
if (fsUtils.existsSync(pkgPath)) {
if (fs.existsSync(pkgPath)) {
if (!options.preserveSymlinks) {
pkgPath = safeRealpathSync(pkgPath)
}
@ -718,7 +706,7 @@ function tryCleanFsResolve(
}
if (
(res = fsUtils.tryResolveRealFileWithExtensions(
(res = tryResolveRealFileWithExtensions(
`${dirPath}/index`,
extensions,
preserveSymlinks,
@ -728,7 +716,7 @@ function tryCleanFsResolve(
if (tryPrefix) {
if (
(res = fsUtils.tryResolveRealFileWithExtensions(
(res = tryResolveRealFileWithExtensions(
`${dirPath}/${options.tryPrefix}index`,
extensions,
preserveSymlinks,
@ -1322,3 +1310,48 @@ function mapWithBrowserField(
function equalWithoutSuffix(path: string, key: string, suffix: string) {
return key.endsWith(suffix) && key.slice(0, -suffix.length) === path
}
function tryResolveRealFile(
file: string,
preserveSymlinks?: boolean,
): string | undefined {
const stat = tryStatSync(file)
if (stat?.isFile()) return getRealPath(file, preserveSymlinks)
}
function tryResolveRealFileWithExtensions(
filePath: string,
extensions: string[],
preserveSymlinks?: boolean,
): string | undefined {
for (const ext of extensions) {
const res = tryResolveRealFile(filePath + ext, preserveSymlinks)
if (res) return res
}
}
function tryResolveRealFileOrType(
file: string,
preserveSymlinks?: boolean,
): { path?: string; type: 'directory' | 'file' } | undefined {
const fileStat = tryStatSync(file)
if (fileStat?.isFile()) {
return { path: getRealPath(file, preserveSymlinks), type: 'file' }
}
if (fileStat?.isDirectory()) {
return { type: 'directory' }
}
return
}
function getRealPath(resolved: string, preserveSymlinks?: boolean): string {
if (!preserveSymlinks) {
resolved = safeRealpathSync(resolved)
}
return normalizePath(resolved)
}
function isDirectory(path: string): boolean {
const stat = tryStatSync(path)
return stat?.isDirectory() ?? false
}

View File

@ -36,7 +36,6 @@ import {
setupSIGTERMListener,
teardownSIGTERMListener,
} from '../utils'
import { getFsUtils } from '../fsUtils'
import { ssrLoadModule } from '../ssr/ssrModuleLoader'
import { ssrFixStacktrace, ssrRewriteStacktrace } from '../ssr/ssrStacktrace'
import { ssrTransform } from '../ssr/ssrTransform'
@ -218,14 +217,6 @@ export interface FileSystemServeOptions {
* @default ['.env', '.env.*', '*.{crt,pem}', '**\/.git/**']
*/
deny?: string[]
/**
* Enable caching of fs calls. It is enabled by default if no custom watch ignored patterns are provided.
*
* @experimental
* @default undefined
*/
cachedChecks?: boolean
}
export type ServerHook = (
@ -810,8 +801,6 @@ export async function _createServer(
await onHMRUpdate('update', file)
})
getFsUtils(config).initWatcher?.(watcher)
watcher.on('add', (file) => {
onFileAddUnlink(file, false)
})
@ -889,13 +878,7 @@ export async function _createServer(
// html fallback
if (config.appType === 'spa' || config.appType === 'mpa') {
middlewares.use(
htmlFallbackMiddleware(
root,
config.appType === 'spa',
getFsUtils(config),
),
)
middlewares.use(htmlFallbackMiddleware(root, config.appType === 'spa'))
}
// run post config hooks
@ -1095,7 +1078,6 @@ export function resolveServerOptions(
strict: server.fs?.strict ?? true,
allow: allowDirs,
deny,
cachedChecks: server.fs?.cachedChecks,
}
if (server.origin?.endsWith('/')) {

View File

@ -1,8 +1,7 @@
import path from 'node:path'
import fs from 'node:fs'
import type { Connect } from 'dep-types/connect'
import { createDebugger } from '../../utils'
import type { FsUtils } from '../../fsUtils'
import { commonFsUtils } from '../../fsUtils'
import { cleanUrl } from '../../../shared/utils'
const debug = createDebugger('vite:html-fallback')
@ -10,7 +9,6 @@ const debug = createDebugger('vite:html-fallback')
export function htmlFallbackMiddleware(
root: string,
spaFallback: boolean,
fsUtils: FsUtils = commonFsUtils,
): Connect.NextHandleFunction {
// Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
return function viteHtmlFallbackMiddleware(req, _res, next) {
@ -37,7 +35,7 @@ export function htmlFallbackMiddleware(
// so we need to check if the file exists
if (pathname.endsWith('.html')) {
const filePath = path.join(root, pathname)
if (fsUtils.existsSync(filePath)) {
if (fs.existsSync(filePath)) {
debug?.(`Rewriting ${req.method} ${req.url} to ${url}`)
req.url = url
return next()
@ -46,7 +44,7 @@ export function htmlFallbackMiddleware(
// trailing slash should check for fallback index.html
else if (pathname[pathname.length - 1] === '/') {
const filePath = path.join(root, pathname, 'index.html')
if (fsUtils.existsSync(filePath)) {
if (fs.existsSync(filePath)) {
const newUrl = url + 'index.html'
debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`)
req.url = newUrl
@ -56,7 +54,7 @@ export function htmlFallbackMiddleware(
// non-trailing slash should check for fallback .html
else {
const filePath = path.join(root, pathname + '.html')
if (fsUtils.existsSync(filePath)) {
if (fs.existsSync(filePath)) {
const newUrl = url + '.html'
debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`)
req.url = newUrl

View File

@ -1,3 +1,4 @@
import fs from 'node:fs'
import fsp from 'node:fs/promises'
import path from 'node:path'
import MagicString from 'magic-string'
@ -40,7 +41,6 @@ import {
processSrcSetSync,
stripBase,
} from '../../utils'
import { getFsUtils } from '../../fsUtils'
import { checkPublicFile } from '../../publicDir'
import { isCSSRequest } from '../../plugins/css'
import { getCodeWithSourcemap, injectSourcesContent } from '../sourcemap'
@ -195,7 +195,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
let proxyModuleUrl: string
const trailingSlash = htmlPath.endsWith('/')
if (!trailingSlash && getFsUtils(config).existsSync(filename)) {
if (!trailingSlash && fs.existsSync(filename)) {
proxyModulePath = htmlPath
proxyModuleUrl = proxyModulePath
} else {
@ -441,7 +441,6 @@ export function indexHtmlMiddleware(
server: ViteDevServer | PreviewServer,
): Connect.NextHandleFunction {
const isDev = isDevServer(server)
const fsUtils = getFsUtils(server.config)
// Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
return async function viteIndexHtmlMiddleware(req, res, next) {
@ -459,7 +458,7 @@ export function indexHtmlMiddleware(
filePath = path.join(root, decodeURIComponent(url))
}
if (fsUtils.existsSync(filePath)) {
if (fs.existsSync(filePath)) {
const headers = isDev
? server.config.server.headers
: server.config.preview.headers

View File

@ -44,9 +44,6 @@ export default defineConfig({
},
server: {
fs: {
cachedChecks: false,
},
warmup: {
clientFiles: ['./warmup/*'],
},