mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 01:15:58 +00:00
feat(kit)!: expose resolvePath
(#3110)
This commit is contained in:
parent
a1b2d09438
commit
03d5fdde2d
@ -112,7 +112,8 @@ console.log(getNuxtVersion())
|
|||||||
[source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/resolve.ts)
|
[source code](https://github.com/nuxt/framework/blob/main/packages/kit/src/resolve.ts)
|
||||||
|
|
||||||
- `resolvePath (path, resolveOptions?)`
|
- `resolvePath (path, resolveOptions?)`
|
||||||
- `tryResolvePath (path, resolveOptions?)`
|
- `resolveAlias (path, aliases?)`
|
||||||
|
- `findPath (paths, resolveOptions?)`
|
||||||
|
|
||||||
### Builder
|
### Builder
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ export function setupNitroBridge () {
|
|||||||
await nuxt.callHook('nitro:context', nitroDevContext)
|
await nuxt.callHook('nitro:context', nitroDevContext)
|
||||||
|
|
||||||
// Resolve middleware
|
// Resolve middleware
|
||||||
const { middleware, legacyMiddleware } = resolveMiddleware(nuxt)
|
const { middleware, legacyMiddleware } = await resolveMiddleware(nuxt)
|
||||||
if (nuxt.server) {
|
if (nuxt.server) {
|
||||||
nuxt.server.setLegacyMiddleware(legacyMiddleware)
|
nuxt.server.setLegacyMiddleware(legacyMiddleware)
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Try to resolve the path of a module, but don't emit an error if it can't be found. */
|
/** Try to resolve the path of a module, but don't emit an error if it can't be found. */
|
||||||
export function tryResolveModule (path: string, opts: ResolveModuleOptions = {}) {
|
export function tryResolveModule (path: string, opts: ResolveModuleOptions = {}): string | null {
|
||||||
try {
|
try {
|
||||||
return resolveModule(path, opts)
|
return resolveModule(path, opts)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -105,6 +105,7 @@ export function tryResolveModule (path: string, opts: ResolveModuleOptions = {})
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Require a module and return it. */
|
/** Require a module and return it. */
|
||||||
|
@ -18,7 +18,7 @@ export async function installModule (nuxtModule: string | NuxtModule, inlineOpti
|
|||||||
|
|
||||||
// Import if input is string
|
// Import if input is string
|
||||||
if (typeof nuxtModule === 'string') {
|
if (typeof nuxtModule === 'string') {
|
||||||
const _src = resolveModule(resolveAlias(nuxtModule, nuxt.options.alias), { paths: nuxt.options.modulesDir })
|
const _src = resolveModule(resolveAlias(nuxtModule), { paths: nuxt.options.modulesDir })
|
||||||
// TODO: also check with type: 'module' in closest `package.json`
|
// TODO: also check with type: 'module' in closest `package.json`
|
||||||
const isESM = _src.endsWith('.mjs')
|
const isESM = _src.endsWith('.mjs')
|
||||||
nuxtModule = isESM ? await importModule(_src) : requireModule(_src)
|
nuxtModule = isESM ? await importModule(_src) : requireModule(_src)
|
||||||
|
@ -1,89 +1,101 @@
|
|||||||
import { existsSync, lstatSync, readdirSync } from 'fs'
|
import { promises as fsp, existsSync } from 'fs'
|
||||||
import { basename, dirname, resolve, join } from 'pathe'
|
import { basename, dirname, resolve, join, normalize, isAbsolute } from 'pathe'
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
|
import { useNuxt } from './context'
|
||||||
|
import { tryResolveModule } from '.'
|
||||||
|
|
||||||
export interface ResolveOptions {
|
export interface ResolvePathOptions {
|
||||||
/**
|
/** Base for resolving paths from. Default is Nuxt rootDir. */
|
||||||
* The base path against which to resolve the path
|
cwd?: string
|
||||||
*
|
|
||||||
* @default .
|
/** An object of aliases. Default is Nuxt configured aliases. */
|
||||||
*/
|
|
||||||
base?: string
|
|
||||||
/**
|
|
||||||
* An object of aliases (alias, path) to take into account, for example
|
|
||||||
* `{ 'example/alias': '/full/path/to/alias' }`
|
|
||||||
*/
|
|
||||||
alias?: Record<string, string>
|
alias?: Record<string, string>
|
||||||
/** The file extensions to try (for example, ['js', 'ts']) */
|
|
||||||
|
/** The file extensions to try. Default is Nuxt configured extensions. */
|
||||||
extensions?: string[]
|
extensions?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePath (path: string, opts: ResolveOptions = {}) {
|
/**
|
||||||
|
* Resolve full path to a file or directory respecting Nuxt alias and extensions options
|
||||||
|
*
|
||||||
|
* If path could not be resolved, normalized input path will be returned
|
||||||
|
*/
|
||||||
|
export async function resolvePath (path: string, opts: ResolvePathOptions = {}): Promise<string> {
|
||||||
|
// Always normalize input
|
||||||
|
path = normalize(path)
|
||||||
|
|
||||||
// Fast return if the path exists
|
// Fast return if the path exists
|
||||||
if (existsSyncSensitive(path)) {
|
if (existsSync(path)) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolvedPath: string
|
// Use current nuxt options
|
||||||
|
const nuxt = useNuxt()
|
||||||
|
const cwd = opts.cwd || nuxt.options.rootDir
|
||||||
|
const extensions = opts.extensions || nuxt.options.extensions
|
||||||
|
const modulesDir = nuxt.options.modulesDir
|
||||||
|
|
||||||
// Resolve alias
|
// Resolve aliases
|
||||||
if (opts.alias) {
|
path = resolveAlias(path)
|
||||||
resolvedPath = resolveAlias(path, opts.alias)
|
|
||||||
|
// Resolve relative to cwd
|
||||||
|
if (!isAbsolute(path)) {
|
||||||
|
path = resolve(cwd, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve relative to base or cwd
|
|
||||||
resolvedPath = resolve(opts.base || '.', resolvedPath)
|
|
||||||
|
|
||||||
const resolvedPathFiles = readdirSync(dirname(resolvedPath))
|
|
||||||
|
|
||||||
// Check if resolvedPath is a file
|
// Check if resolvedPath is a file
|
||||||
let isDirectory = false
|
let isDirectory = false
|
||||||
if (existsSyncSensitive(resolvedPath, resolvedPathFiles)) {
|
if (existsSync(path)) {
|
||||||
isDirectory = lstatSync(resolvedPath).isDirectory()
|
isDirectory = (await fsp.lstat(path)).isDirectory()
|
||||||
if (!isDirectory) {
|
if (!isDirectory) {
|
||||||
return resolvedPath
|
return path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check possible extensions
|
// Check possible extensions
|
||||||
for (const ext of opts.extensions) {
|
for (const ext of extensions) {
|
||||||
// resolvedPath.[ext]
|
// path.[ext]
|
||||||
const resolvedPathwithExt = resolvedPath + ext
|
const pathWithExt = path + ext
|
||||||
if (!isDirectory && existsSyncSensitive(resolvedPathwithExt, resolvedPathFiles)) {
|
if (!isDirectory && existsSync(pathWithExt)) {
|
||||||
return resolvedPathwithExt
|
return pathWithExt
|
||||||
}
|
}
|
||||||
// resolvedPath/index.[ext]
|
// path/index.[ext]
|
||||||
const resolvedPathwithIndex = join(resolvedPath, 'index' + ext)
|
const pathWithIndex = join(path, 'index' + ext)
|
||||||
if (isDirectory && existsSyncSensitive(resolvedPathwithIndex)) {
|
if (isDirectory && existsSync(pathWithIndex)) {
|
||||||
return resolvedPathwithIndex
|
return pathWithIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If extension check fails and resolvedPath is a valid directory, return it
|
// Try to resolve as module id
|
||||||
if (isDirectory) {
|
const resolveModulePath = tryResolveModule(path, { paths: modulesDir })
|
||||||
return resolvedPath
|
if (resolveModulePath) {
|
||||||
|
return resolveModulePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give up if it is neither a directory
|
// Return normalized input
|
||||||
throw new Error(`Cannot resolve "${path}" from "${resolvedPath}"`)
|
return path
|
||||||
}
|
|
||||||
|
|
||||||
function existsSyncSensitive (path: string, files?: string[]) {
|
|
||||||
if (!existsSync(path)) { return false }
|
|
||||||
const _files = files || readdirSync(dirname(path))
|
|
||||||
return _files.includes(basename(path))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a path with any relevant aliases resolved.
|
* Try to resolve first existing file in paths
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```js
|
|
||||||
* const aliases = { 'test': '/here/there' }
|
|
||||||
* resolveAlias('test/everywhere', aliases)
|
|
||||||
* // '/here/there/everywhere'
|
|
||||||
*/
|
*/
|
||||||
export function resolveAlias (path: string, alias: ResolveOptions['alias']) {
|
export async function findPath (paths: string[], opts?: ResolvePathOptions): Promise<string|null> {
|
||||||
|
for (const path of paths) {
|
||||||
|
const rPath = await resolvePath(path, opts)
|
||||||
|
if (await existsSensitive(rPath)) {
|
||||||
|
return rPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve path aliases respecting Nuxt alias options
|
||||||
|
*/
|
||||||
|
export function resolveAlias (path: string, alias?: Record<string, string>): string {
|
||||||
|
if (!alias) {
|
||||||
|
alias = useNuxt().options.alias
|
||||||
|
}
|
||||||
for (const key in alias) {
|
for (const key in alias) {
|
||||||
if (key === '@' && !path.startsWith('@/')) { continue } // Don't resolve @foo/bar
|
if (key === '@' && !path.startsWith('@/')) { continue } // Don't resolve @foo/bar
|
||||||
if (path.startsWith(key)) {
|
if (path.startsWith(key)) {
|
||||||
@ -93,21 +105,15 @@ export function resolveAlias (path: string, alias: ResolveOptions['alias']) {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// --- Internal ---
|
||||||
* Resolve the path of a file but don't emit an error,
|
|
||||||
* even if the module can't be resolved.
|
async function existsSensitive (path: string) {
|
||||||
*/
|
if (!existsSync(path)) { return false }
|
||||||
export function tryResolvePath (path: string, opts: ResolveOptions = {}) {
|
const dirFiles = await fsp.readdir(dirname(path))
|
||||||
try {
|
return dirFiles.includes(basename(path))
|
||||||
return resolvePath(path, opts)
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveFiles (path: string, pattern: string | string[]) {
|
export async function resolveFiles (path: string, pattern: string | string[]) {
|
||||||
const files = await globby(pattern, {
|
const files = await globby(pattern, { cwd: path, followSymbolicLinks: true })
|
||||||
cwd: path,
|
|
||||||
followSymbolicLinks: true
|
|
||||||
})
|
|
||||||
return files.map(p => resolve(path, p))
|
return files.map(p => resolve(path, p))
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { resolve, join, extname } from 'pathe'
|
|||||||
import { joinURL } from 'ufo'
|
import { joinURL } from 'ufo'
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
import { watch } from 'chokidar'
|
import { watch } from 'chokidar'
|
||||||
import { tryResolveModule, tryResolvePath } from '@nuxt/kit'
|
import { resolvePath } from '@nuxt/kit'
|
||||||
import type { Nuxt } from '@nuxt/schema'
|
import type { Nuxt } from '@nuxt/schema'
|
||||||
import type { Middleware } from 'h3'
|
import type { Middleware } from 'h3'
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ export function scanMiddleware (serverDir: string, onChange?: (results: ServerMi
|
|||||||
return scan()
|
return scan()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMiddleware (nuxt: Nuxt) {
|
export async function resolveMiddleware (nuxt: Nuxt) {
|
||||||
const middleware: ServerMiddleware[] = []
|
const middleware: ServerMiddleware[] = []
|
||||||
const legacyMiddleware: ServerMiddleware[] = []
|
const legacyMiddleware: ServerMiddleware[] = []
|
||||||
|
|
||||||
@ -83,11 +83,7 @@ export function resolveMiddleware (nuxt: Nuxt) {
|
|||||||
delete m.path
|
delete m.path
|
||||||
middleware.push({
|
middleware.push({
|
||||||
...m,
|
...m,
|
||||||
handle: tryResolvePath(handle, {
|
handle: await resolvePath(handle),
|
||||||
extensions: ['.ts', '.mjs', '.js', '.cjs'],
|
|
||||||
alias: nuxt.options.alias,
|
|
||||||
base: nuxt.options.srcDir
|
|
||||||
}) || tryResolveModule(handle, { paths: nuxt.options.modulesDir }),
|
|
||||||
route
|
route
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ function generateDts (ctx: AutoImportContext) {
|
|||||||
const resolved = {}
|
const resolved = {}
|
||||||
const r = (id: string) => {
|
const r = (id: string) => {
|
||||||
if (resolved[id]) { return resolved[id] }
|
if (resolved[id]) { return resolved[id] }
|
||||||
let path = resolveAlias(id, nuxt.options.alias)
|
let path = resolveAlias(id)
|
||||||
if (isAbsolute(path)) {
|
if (isAbsolute(path)) {
|
||||||
path = relative(join(nuxt.options.buildDir, 'types'), path)
|
path = relative(join(nuxt.options.buildDir, 'types'), path)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
|
|
||||||
componentDirs = allDirs.filter(isPureObjectOrString).map((dir) => {
|
componentDirs = allDirs.filter(isPureObjectOrString).map((dir) => {
|
||||||
const dirOptions: ComponentsDir = typeof dir === 'object' ? dir : { path: dir }
|
const dirOptions: ComponentsDir = typeof dir === 'object' ? dir : { path: dir }
|
||||||
const dirPath = resolveAlias(dirOptions.path, nuxt.options.alias)
|
const dirPath = resolveAlias(dirOptions.path)
|
||||||
const transpile = typeof dirOptions.transpile === 'boolean' ? dirOptions.transpile : 'auto'
|
const transpile = typeof dirOptions.transpile === 'boolean' ? dirOptions.transpile : 'auto'
|
||||||
const extensions = (dirOptions.extensions || nuxt.options.extensions).map(e => e.replace(/^\./g, ''))
|
const extensions = (dirOptions.extensions || nuxt.options.extensions).map(e => e.replace(/^\./g, ''))
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { promises as fsp } from 'fs'
|
|||||||
import { dirname, resolve } from 'pathe'
|
import { dirname, resolve } from 'pathe'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import type { Nuxt, NuxtApp } from '@nuxt/schema'
|
import type { Nuxt, NuxtApp } from '@nuxt/schema'
|
||||||
import { tryResolvePath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils } from '@nuxt/kit'
|
import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils } from '@nuxt/kit'
|
||||||
|
|
||||||
import * as defaultTemplates from './templates'
|
import * as defaultTemplates from './templates'
|
||||||
|
|
||||||
@ -54,15 +54,9 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
||||||
const resolveOptions = {
|
|
||||||
base: nuxt.options.srcDir,
|
|
||||||
alias: nuxt.options.alias,
|
|
||||||
extensions: nuxt.options.extensions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve main (app.vue)
|
// Resolve main (app.vue)
|
||||||
if (!app.mainComponent) {
|
if (!app.mainComponent) {
|
||||||
app.mainComponent = tryResolvePath('~/App', resolveOptions) || tryResolvePath('~/app', resolveOptions)
|
app.mainComponent = await findPath(['~/App', '~/app'])
|
||||||
}
|
}
|
||||||
if (!app.mainComponent) {
|
if (!app.mainComponent) {
|
||||||
app.mainComponent = resolve(nuxt.options.appDir, 'components/nuxt-welcome.vue')
|
app.mainComponent = resolve(nuxt.options.appDir, 'components/nuxt-welcome.vue')
|
||||||
|
@ -59,7 +59,7 @@ export function initNitro (nuxt: Nuxt) {
|
|||||||
await nuxt.callHook('nitro:context', nitroDevContext)
|
await nuxt.callHook('nitro:context', nitroDevContext)
|
||||||
|
|
||||||
// Resolve middleware
|
// Resolve middleware
|
||||||
const { middleware, legacyMiddleware } = resolveMiddleware(nuxt)
|
const { middleware, legacyMiddleware } = await resolveMiddleware(nuxt)
|
||||||
nuxt.server.setLegacyMiddleware(legacyMiddleware)
|
nuxt.server.setLegacyMiddleware(legacyMiddleware)
|
||||||
nitroContext.middleware.push(...middleware)
|
nitroContext.middleware.push(...middleware)
|
||||||
nitroDevContext.middleware.push(...middleware)
|
nitroDevContext.middleware.push(...middleware)
|
||||||
|
Loading…
Reference in New Issue
Block a user