mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-22 11:22:43 +00:00
perf(kit): reduce duplication between findPath
and resolvePath
(#30682)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
893ac0f8bc
commit
e8789b900c
@ -1,4 +1,4 @@
|
|||||||
import { existsSync, promises as fsp } from 'node:fs'
|
import { promises as fsp } from 'node:fs'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { basename, dirname, isAbsolute, join, normalize, resolve } from 'pathe'
|
import { basename, dirname, isAbsolute, join, normalize, resolve } from 'pathe'
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
@ -38,97 +38,30 @@ export interface ResolvePathOptions {
|
|||||||
* If path could not be resolved, normalized input path will be returned
|
* If path could not be resolved, normalized input path will be returned
|
||||||
*/
|
*/
|
||||||
export async function resolvePath (path: string, opts: ResolvePathOptions = {}): Promise<string> {
|
export async function resolvePath (path: string, opts: ResolvePathOptions = {}): Promise<string> {
|
||||||
// Always normalize input
|
const res = await _resolvePathGranularly(path, opts)
|
||||||
const _path = path
|
|
||||||
path = normalize(path)
|
|
||||||
|
|
||||||
// Fast return if the path exists
|
if (res.type === 'file') {
|
||||||
if (isAbsolute(path)) {
|
return res.path
|
||||||
if (opts?.virtual && existsInVFS(path)) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
if (existsSync(path) && !(await isDirectory(path))) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use current nuxt options
|
|
||||||
const nuxt = tryUseNuxt()
|
|
||||||
const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd())
|
|
||||||
const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : ['.ts', '.mjs', '.cjs', '.json'])
|
|
||||||
const modulesDir = nuxt ? nuxt.options.modulesDir : []
|
|
||||||
|
|
||||||
// Resolve aliases
|
|
||||||
path = resolveAlias(path)
|
|
||||||
|
|
||||||
// Resolve relative to cwd
|
|
||||||
if (!isAbsolute(path)) {
|
|
||||||
path = resolve(cwd, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if resolvedPath is a file
|
|
||||||
if (opts?.virtual && existsInVFS(path, nuxt)) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
let _isDir = false
|
|
||||||
if (existsSync(path)) {
|
|
||||||
_isDir = await isDirectory(path)
|
|
||||||
if (!_isDir) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check possible extensions
|
|
||||||
for (const ext of extensions) {
|
|
||||||
// path.[ext]
|
|
||||||
const pathWithExt = path + ext
|
|
||||||
if (opts?.virtual && existsInVFS(pathWithExt, nuxt)) {
|
|
||||||
return pathWithExt
|
|
||||||
}
|
|
||||||
if (existsSync(pathWithExt)) {
|
|
||||||
return pathWithExt
|
|
||||||
}
|
|
||||||
// path/index.[ext]
|
|
||||||
const pathWithIndex = join(path, 'index' + ext)
|
|
||||||
if (opts?.virtual && existsInVFS(pathWithIndex, nuxt)) {
|
|
||||||
return pathWithIndex
|
|
||||||
}
|
|
||||||
if (_isDir && existsSync(pathWithIndex)) {
|
|
||||||
return pathWithIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to resolve as module id
|
|
||||||
const resolveModulePath = await _resolvePath(_path, { url: [cwd, ...modulesDir] }).catch(() => null)
|
|
||||||
if (resolveModulePath) {
|
|
||||||
return resolveModulePath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return normalized input
|
// Return normalized input
|
||||||
return opts.fallbackToOriginal ? _path : path
|
return opts.fallbackToOriginal ? path : res.path
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to resolve first existing file in paths
|
* Try to resolve first existing file in paths
|
||||||
*/
|
*/
|
||||||
export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> {
|
export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> {
|
||||||
const nuxt = opts?.virtual ? tryUseNuxt() : undefined
|
|
||||||
|
|
||||||
for (const path of toArray(paths)) {
|
for (const path of toArray(paths)) {
|
||||||
const rPath = await resolvePath(path, opts)
|
const res = await _resolvePathGranularly(path, opts)
|
||||||
|
|
||||||
// Check VFS
|
if (!res.type || (pathType && res.type !== pathType)) {
|
||||||
if (opts?.virtual && existsInVFS(rPath, nuxt)) {
|
continue
|
||||||
return rPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check file system
|
// Check file system
|
||||||
if (await existsSensitive(rPath)) {
|
if (res.virtual || await existsSensitive(res.path)) {
|
||||||
const _isDir = await isDirectory(rPath)
|
return res.path
|
||||||
if (!pathType || (pathType === 'file' && !_isDir) || (pathType === 'dir' && _isDir)) {
|
|
||||||
return rPath
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -186,15 +119,106 @@ export async function resolveNuxtModule (base: string, paths: string[]): Promise
|
|||||||
|
|
||||||
// --- Internal ---
|
// --- Internal ---
|
||||||
|
|
||||||
async function existsSensitive (path: string) {
|
interface PathResolution {
|
||||||
if (!existsSync(path)) { return false }
|
path: string
|
||||||
const dirFiles = await fsp.readdir(dirname(path))
|
type?: 'file' | 'dir'
|
||||||
return dirFiles.includes(basename(path))
|
virtual?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage note: We assume path existence is already ensured
|
async function _resolvePathType (path: string, opts: ResolvePathOptions = {}, skipFs = false): Promise<PathResolution | undefined> {
|
||||||
async function isDirectory (path: string) {
|
if (opts?.virtual && existsInVFS(path)) {
|
||||||
return (await fsp.lstat(path)).isDirectory()
|
return {
|
||||||
|
path,
|
||||||
|
type: 'file',
|
||||||
|
virtual: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipFs) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const fd = await fsp.open(path, 'r').catch(() => null)
|
||||||
|
try {
|
||||||
|
const stats = await fd?.stat()
|
||||||
|
if (stats) {
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
type: stats.isFile() ? 'file' : 'dir',
|
||||||
|
virtual: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
fd?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _resolvePathGranularly (path: string, opts: ResolvePathOptions = {}): Promise<PathResolution> {
|
||||||
|
// Always normalize input
|
||||||
|
const _path = path
|
||||||
|
path = normalize(path)
|
||||||
|
|
||||||
|
// Fast return if the path exists
|
||||||
|
if (isAbsolute(path)) {
|
||||||
|
const res = await _resolvePathType(path, opts)
|
||||||
|
if (res && res.type === 'file') {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use current nuxt options
|
||||||
|
const nuxt = tryUseNuxt()
|
||||||
|
const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd())
|
||||||
|
const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : ['.ts', '.mjs', '.cjs', '.json'])
|
||||||
|
const modulesDir = nuxt ? nuxt.options.modulesDir : []
|
||||||
|
|
||||||
|
// Resolve aliases
|
||||||
|
path = resolveAlias(path)
|
||||||
|
|
||||||
|
// Resolve relative to cwd
|
||||||
|
if (!isAbsolute(path)) {
|
||||||
|
path = resolve(cwd, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await _resolvePathType(path, opts)
|
||||||
|
if (res && res.type === 'file') {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check possible extensions
|
||||||
|
for (const ext of extensions) {
|
||||||
|
// path.[ext]
|
||||||
|
const extPath = await _resolvePathType(path + ext, opts)
|
||||||
|
if (extPath && extPath.type === 'file') {
|
||||||
|
return extPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// path/index.[ext]
|
||||||
|
const indexPath = await _resolvePathType(join(path, 'index' + ext), opts, res?.type !== 'dir' /* skip checking if parent is not a directory */)
|
||||||
|
if (indexPath && indexPath.type === 'file') {
|
||||||
|
return indexPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to resolve as module id
|
||||||
|
const resolvedModulePath = await _resolvePath(_path, { url: [cwd, ...modulesDir] }).catch(() => null)
|
||||||
|
if (resolvedModulePath) {
|
||||||
|
return {
|
||||||
|
path: resolvedModulePath,
|
||||||
|
type: 'file',
|
||||||
|
virtual: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return normalized input
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function existsSensitive (path: string) {
|
||||||
|
const dirFiles = await fsp.readdir(dirname(path)).catch(() => null)
|
||||||
|
return dirFiles && dirFiles.includes(basename(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
function existsInVFS (path: string, nuxt = tryUseNuxt()) {
|
function existsInVFS (path: string, nuxt = tryUseNuxt()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user