perf(nuxt): migrate to use exsolve for module resolution (#31124)

This commit is contained in:
Daniel Roe 2025-02-26 17:02:04 +00:00
parent a99c59fbd4
commit fb9ee0a4ea
No known key found for this signature in database
GPG Key ID: CBC814C393D93268
20 changed files with 250 additions and 203 deletions

View File

@ -31,6 +31,7 @@
"consola": "^3.4.0", "consola": "^3.4.0",
"defu": "^6.1.4", "defu": "^6.1.4",
"destr": "^2.0.3", "destr": "^2.0.3",
"exsolve": "^1.0.1",
"globby": "^14.1.0", "globby": "^14.1.0",
"ignore": "^7.0.3", "ignore": "^7.0.3",
"jiti": "^2.4.2", "jiti": "^2.4.2",

View File

@ -1,5 +1,6 @@
import { pathToFileURL } from 'node:url' import { pathToFileURL } from 'node:url'
import { interopDefault, resolvePath, resolvePathSync } from 'mlly' import { interopDefault } from 'mlly'
import { resolveModulePath } from 'exsolve'
import { createJiti } from 'jiti' import { createJiti } from 'jiti'
export interface ResolveModuleOptions { export interface ResolveModuleOptions {
@ -20,17 +21,19 @@ export function directoryToURL (dir: string): URL {
*/ */
export async function tryResolveModule (id: string, url: URL | URL[]): Promise<string | undefined> export async function tryResolveModule (id: string, url: URL | URL[]): Promise<string | undefined>
/** @deprecated pass URLs pointing at files */ /** @deprecated pass URLs pointing at files */
export async function tryResolveModule (id: string, url: string | string[]): Promise<string | undefined> export function tryResolveModule (id: string, url: string | string[]): Promise<string | undefined>
export async function tryResolveModule (id: string, url: string | string[] | URL | URL[] = import.meta.url) { export function tryResolveModule (id: string, url: string | string[] | URL | URL[] = import.meta.url) {
try { return Promise.resolve(resolveModulePath(id, {
return await resolvePath(id, { url }) from: url,
} catch { suffixes: ['', 'index'],
// intentionally empty as this is a `try-` function try: true,
} }))
} }
export function resolveModule (id: string, options?: ResolveModuleOptions) { export function resolveModule (id: string, options?: ResolveModuleOptions) {
return resolvePathSync(id, { url: options?.url ?? options?.paths ?? [import.meta.url] }) return resolveModulePath(id, {
from: options?.url ?? options?.paths ?? [import.meta.url],
})
} }
export interface ImportModuleOptions extends ResolveModuleOptions { export interface ImportModuleOptions extends ResolveModuleOptions {

View File

@ -8,8 +8,9 @@ import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
import { globby } from 'globby' import { globby } from 'globby'
import defu from 'defu' import defu from 'defu'
import { basename, join, relative } from 'pathe' import { basename, join, relative } from 'pathe'
import { isWindows } from 'std-env' import { resolveModuleURL } from 'exsolve'
import { directoryToURL, tryResolveModule } from '../internal/esm'
import { directoryToURL } from '../internal/esm'
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> { export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
@ -110,10 +111,10 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
async function loadNuxtSchema (cwd: string) { async function loadNuxtSchema (cwd: string) {
const url = directoryToURL(cwd) const url = directoryToURL(cwd)
const urls = [url] const urls = [url]
const nuxtPath = await tryResolveModule('nuxt', url) ?? await tryResolveModule('nuxt-nightly', url) const nuxtPath = resolveModuleURL('nuxt', { try: true, from: url }) ?? resolveModuleURL('nuxt-nightly', { try: true, from: url })
if (nuxtPath) { if (nuxtPath) {
urls.unshift(pathToFileURL(nuxtPath)) urls.unshift(pathToFileURL(nuxtPath))
} }
const schemaPath = await tryResolveModule('@nuxt/schema', urls) ?? '@nuxt/schema' const schemaPath = resolveModuleURL('@nuxt/schema', { try: true, from: urls }) ?? '@nuxt/schema'
return await import(isWindows ? pathToFileURL(schemaPath).href : schemaPath).then(r => r.NuxtConfigSchema) return await import(schemaPath).then(r => r.NuxtConfigSchema)
} }

View File

@ -1,16 +1,16 @@
import { existsSync, promises as fsp, lstatSync } from 'node:fs' import { existsSync, promises as fsp, lstatSync } from 'node:fs'
import { fileURLToPath, pathToFileURL } from 'node:url' import { fileURLToPath } from 'node:url'
import type { ModuleMeta, Nuxt, NuxtConfig, NuxtModule } from '@nuxt/schema' import type { ModuleMeta, Nuxt, NuxtConfig, NuxtModule } from '@nuxt/schema'
import { dirname, isAbsolute, join, resolve } from 'pathe' import { dirname, isAbsolute, resolve } from 'pathe'
import { defu } from 'defu' import { defu } from 'defu'
import { createJiti } from 'jiti' import { createJiti } from 'jiti'
import { parseNodeModulePath, resolve as resolveModule } from 'mlly' import { parseNodeModulePath } from 'mlly'
import { resolveModuleURL } from 'exsolve'
import { isRelative } from 'ufo' import { isRelative } from 'ufo'
import { isNuxt2 } from '../compatibility' import { isNuxt2 } from '../compatibility'
import { directoryToURL } from '../internal/esm' import { directoryToURL } from '../internal/esm'
import { useNuxt } from '../context' import { useNuxt } from '../context'
import { resolveAlias, resolvePath } from '../resolve' import { resolveAlias } from '../resolve'
import { logger } from '../logger'
const NODE_MODULES_RE = /[/\\]node_modules[/\\]/ const NODE_MODULES_RE = /[/\\]node_modules[/\\]/
@ -87,84 +87,63 @@ export const normalizeModuleTranspilePath = (p: string) => {
const MissingModuleMatcher = /Cannot find module\s+['"]?([^'")\s]+)['"]?/i const MissingModuleMatcher = /Cannot find module\s+['"]?([^'")\s]+)['"]?/i
export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, nuxt: Nuxt = useNuxt()) { export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, nuxt: Nuxt = useNuxt()): Promise<{ nuxtModule: NuxtModule<any>, buildTimeModuleMeta: ModuleMeta, resolvedModulePath?: string }> {
let buildTimeModuleMeta: ModuleMeta = {} let buildTimeModuleMeta: ModuleMeta = {}
let resolvedModulePath: string | undefined
if (typeof nuxtModule === 'function') {
return {
nuxtModule,
buildTimeModuleMeta,
}
}
if (typeof nuxtModule !== 'string') {
throw new TypeError(`Nuxt module should be a function or a string to import. Received: ${nuxtModule}.`)
}
const jiti = createJiti(nuxt.options.rootDir, { alias: nuxt.options.alias }) const jiti = createJiti(nuxt.options.rootDir, { alias: nuxt.options.alias })
let resolvedNuxtModule: NuxtModule<any> | undefined
let hadNonFunctionPath = false
// Import if input is string // Import if input is string
if (typeof nuxtModule === 'string') { nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias)
const paths = new Set<string>()
nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias)
if (isRelative(nuxtModule)) { if (isRelative(nuxtModule)) {
nuxtModule = resolve(nuxt.options.rootDir, nuxtModule) nuxtModule = resolve(nuxt.options.rootDir, nuxtModule)
}
paths.add(nuxtModule)
paths.add(join(nuxtModule, 'module'))
paths.add(join(nuxtModule, 'nuxt'))
for (const path of paths) {
try {
const src = isAbsolute(path)
? pathToFileURL(await resolvePath(path, { fallbackToOriginal: false, extensions: nuxt.options.extensions })).href
: await resolveModule(path, {
url: nuxt.options.modulesDir.map(m => directoryToURL(m.replace(/\/node_modules\/?$/, '/'))),
extensions: nuxt.options.extensions,
})
resolvedModulePath = fileURLToPath(new URL(src))
if (!existsSync(resolvedModulePath)) {
continue
}
const instance = await jiti.import(src, { default: true }) as NuxtModule
// ignore possible barrel exports
if (typeof instance !== 'function') {
hadNonFunctionPath = true
continue
}
resolvedNuxtModule = instance
// nuxt-module-builder generates a module.json with metadata including the version
const moduleMetadataPath = new URL('module.json', src)
if (existsSync(moduleMetadataPath)) {
buildTimeModuleMeta = JSON.parse(await fsp.readFile(moduleMetadataPath, 'utf-8'))
}
break
} catch (error: unknown) {
const code = (error as Error & { code?: string }).code
if (code === 'ERR_PACKAGE_PATH_NOT_EXPORTED' || code === 'ERR_UNSUPPORTED_DIR_IMPORT' || code === 'ENOTDIR') {
continue
}
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
const module = MissingModuleMatcher.exec((error as Error).message)?.[1]
// verify that it's missing the nuxt module otherwise it may be a sub dependency of the module itself
// i.e module is importing a module that is missing
if (!module || module.includes(nuxtModule as string)) {
continue
}
}
logger.error(`Error while importing module \`${nuxtModule}\`: ${error}`)
throw error
}
}
} else {
resolvedNuxtModule = nuxtModule
} }
if (!resolvedNuxtModule) { try {
// Module was resolvable but returned a non-function const src = resolveModuleURL(nuxtModule, {
if (hadNonFunctionPath) { from: nuxt.options.modulesDir.map(m => directoryToURL(m.replace(/\/node_modules\/?$/, '/'))),
suffixes: ['nuxt', 'nuxt/index', 'module', 'module/index', '', 'index'],
extensions: ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'],
})
const resolvedModulePath = fileURLToPath(src)
const resolvedNuxtModule = await jiti.import<NuxtModule<any>>(src, { default: true })
if (typeof resolvedNuxtModule !== 'function') {
throw new TypeError(`Nuxt module should be a function: ${nuxtModule}.`) throw new TypeError(`Nuxt module should be a function: ${nuxtModule}.`)
} }
// Throw error if module could not be found
if (typeof nuxtModule === 'string') { // nuxt-module-builder generates a module.json with metadata including the version
const moduleMetadataPath = new URL('module.json', src)
if (existsSync(moduleMetadataPath)) {
buildTimeModuleMeta = JSON.parse(await fsp.readFile(moduleMetadataPath, 'utf-8'))
}
return { nuxtModule: resolvedNuxtModule, buildTimeModuleMeta, resolvedModulePath }
} catch (error: unknown) {
const code = (error as Error & { code?: string }).code
if (code === 'ERR_PACKAGE_PATH_NOT_EXPORTED' || code === 'ERR_UNSUPPORTED_DIR_IMPORT' || code === 'ENOTDIR') {
throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`) throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`)
} }
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
const module = MissingModuleMatcher.exec((error as Error).message)?.[1]
// verify that it's missing the nuxt module otherwise it may be a sub dependency of the module itself
// i.e module is importing a module that is missing
if (module && !module.includes(nuxtModule as string)) {
throw new TypeError(`Error while importing module \`${nuxtModule}\`: ${error}`)
}
}
} }
return { nuxtModule: resolvedNuxtModule, buildTimeModuleMeta, resolvedModulePath } as { nuxtModule: NuxtModule<any>, buildTimeModuleMeta: ModuleMeta, resolvedModulePath?: string } throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`)
} }

View File

@ -1,10 +1,8 @@
import { existsSync } from 'node:fs' import { existsSync } from 'node:fs'
import { isAbsolute } from 'node:path' import { isAbsolute } from 'node:path'
import { pathToFileURL } from 'node:url'
import { normalize } from 'pathe' import { normalize } from 'pathe'
import type { NuxtPlugin, NuxtPluginTemplate } from '@nuxt/schema' import type { NuxtPlugin, NuxtPluginTemplate } from '@nuxt/schema'
import { resolvePathSync } from 'mlly' import { resolveModulePath } from 'exsolve'
import { isWindows } from 'std-env'
import { MODE_RE, filterInPlace } from './utils' import { MODE_RE, filterInPlace } from './utils'
import { tryUseNuxt, useNuxt } from './context' import { tryUseNuxt, useNuxt } from './context'
import { addTemplate } from './template' import { addTemplate } from './template'
@ -35,7 +33,9 @@ export function normalizePlugin (plugin: NuxtPlugin | string): NuxtPlugin {
if (!existsSync(plugin.src) && isAbsolute(plugin.src)) { if (!existsSync(plugin.src) && isAbsolute(plugin.src)) {
try { try {
plugin.src = resolvePathSync(isWindows ? pathToFileURL(plugin.src).href : plugin.src, { extensions: tryUseNuxt()?.options.extensions }) plugin.src = resolveModulePath(plugin.src, {
extensions: tryUseNuxt()?.options.extensions ?? ['.js', '.mjs', '.cjs', '.ts', '.tsx', '.mts', '.cts'],
})
} catch { } catch {
// ignore errors as the file may be in the nuxt vfs // ignore errors as the file may be in the nuxt vfs
} }

View File

@ -2,7 +2,7 @@ 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'
import { resolvePath as _resolvePath } from 'mlly' import { resolveModulePath } from 'exsolve'
import { resolveAlias as _resolveAlias } from 'pathe/utils' import { resolveAlias as _resolveAlias } from 'pathe/utils'
import { directoryToURL } from './internal/esm' import { directoryToURL } from './internal/esm'
import { tryUseNuxt } from './context' import { tryUseNuxt } from './context'
@ -172,7 +172,7 @@ async function _resolvePathGranularly (path: string, opts: ResolvePathOptions =
const modulesDir = nuxt ? nuxt.options.modulesDir : [] const modulesDir = nuxt ? nuxt.options.modulesDir : []
// Resolve aliases // Resolve aliases
path = resolveAlias(path) path = _resolveAlias(path, opts.alias ?? nuxt?.options.alias ?? {})
// Resolve relative to cwd // Resolve relative to cwd
if (!isAbsolute(path)) { if (!isAbsolute(path)) {
@ -200,7 +200,11 @@ async function _resolvePathGranularly (path: string, opts: ResolvePathOptions =
} }
// Try to resolve as module id // Try to resolve as module id
const resolvedModulePath = await _resolvePath(_path, { url: [cwd, ...modulesDir].map(d => directoryToURL(d)) }).catch(() => null) const resolvedModulePath = resolveModulePath(_path, {
try: true,
suffixes: ['', 'index'],
from: [cwd, ...modulesDir].map(d => directoryToURL(d)),
})
if (resolvedModulePath) { if (resolvedModulePath) {
return { return {
path: resolvedModulePath, path: resolvedModulePath,

View File

@ -7,9 +7,10 @@ import { defu } from 'defu'
import type { TSConfig } from 'pkg-types' import type { TSConfig } from 'pkg-types'
import { gte } from 'semver' import { gte } from 'semver'
import { readPackageJSON } from 'pkg-types' import { readPackageJSON } from 'pkg-types'
import { resolveModulePath } from 'exsolve'
import { filterInPlace } from './utils' import { filterInPlace } from './utils'
import { directoryToURL, tryResolveModule } from './internal/esm' import { directoryToURL } from './internal/esm'
import { getDirectory } from './module/install' import { getDirectory } from './module/install'
import { tryUseNuxt, useNuxt } from './context' import { tryUseNuxt, useNuxt } from './context'
import { resolveNuxtModule } from './resolve' import { resolveNuxtModule } from './resolve'
@ -250,7 +251,7 @@ export async function _generateTypes (nuxt: Nuxt) {
let absolutePath = resolve(basePath, aliases[alias]!) let absolutePath = resolve(basePath, aliases[alias]!)
let stats = await fsp.stat(absolutePath).catch(() => null /* file does not exist */) let stats = await fsp.stat(absolutePath).catch(() => null /* file does not exist */)
if (!stats) { if (!stats) {
const resolvedModule = await tryResolveModule(aliases[alias]!, importPaths) const resolvedModule = resolveModulePath(aliases[alias]!, { try: true, from: importPaths })
if (resolvedModule) { if (resolvedModule) {
absolutePath = resolvedModule absolutePath = resolvedModule
stats = await fsp.stat(resolvedModule).catch(() => null) stats = await fsp.stat(resolvedModule).catch(() => null)

View File

@ -94,6 +94,7 @@
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"exsolve": "^1.0.1",
"globby": "^14.1.0", "globby": "^14.1.0",
"h3": "^1.15.1", "h3": "^1.15.1",
"hookable": "^5.5.3", "hookable": "^5.5.3",

View File

@ -1,8 +1,9 @@
import { existsSync, statSync, writeFileSync } from 'node:fs' import { existsSync, statSync, writeFileSync } from 'node:fs'
import { isAbsolute, join, normalize, relative, resolve } from 'pathe' import { isAbsolute, join, normalize, relative, resolve } from 'pathe'
import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, defineNuxtModule, findPath, resolveAlias, resolvePath } from '@nuxt/kit' import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, defineNuxtModule, findPath, resolveAlias } from '@nuxt/kit'
import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema' import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { resolveModulePath } from 'exsolve'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { logger } from '../utils' import { logger } from '../utils'
import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates' import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates'
@ -175,7 +176,7 @@ export default defineNuxtModule<ComponentsOptions>({
for (const component of newComponents) { for (const component of newComponents) {
if (!(component as any /* untyped internal property */)._scanned && !(component.filePath in nuxt.vfs) && isAbsolute(component.filePath) && !existsSync(component.filePath)) { if (!(component as any /* untyped internal property */)._scanned && !(component.filePath in nuxt.vfs) && isAbsolute(component.filePath) && !existsSync(component.filePath)) {
// attempt to resolve component path // attempt to resolve component path
component.filePath = await resolvePath(component.filePath, { fallbackToOriginal: true }) component.filePath = resolveModulePath(resolveAlias(component.filePath), { try: true, extensions: nuxt.options.extensions }) ?? component.filePath
} }
if (component.mode === 'client' && !newComponents.some(c => c.pascalName === component.pascalName && c.mode === 'server')) { if (component.mode === 'client' && !newComponents.some(c => c.pascalName === component.pascalName && c.mode === 'server')) {
newComponents.push({ newComponents.push({

View File

@ -1,7 +1,7 @@
import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs' import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs'
import { dirname, join, relative, resolve } from 'pathe' import { dirname, join, relative, resolve } from 'pathe'
import { defu } from 'defu' import { defu } from 'defu'
import { compileTemplate as _compileTemplate, findPath, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils } from '@nuxt/kit' import { compileTemplate as _compileTemplate, findPath, normalizePlugin, normalizeTemplate, resolveFiles, resolvePath, templateUtils } from '@nuxt/kit'
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema' import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema'
import type { PluginMeta } from 'nuxt/app' import type { PluginMeta } from 'nuxt/app'
@ -217,8 +217,8 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
} }
// Normalize and de-duplicate plugins and middleware // Normalize and de-duplicate plugins and middleware
app.middleware = uniqueBy(await resolvePaths([...app.middleware].reverse(), 'path'), 'name').reverse() app.middleware = uniqueBy(await resolvePaths(nuxt, [...app.middleware].reverse(), 'path'), 'name').reverse()
app.plugins = uniqueBy(await resolvePaths(app.plugins, 'src'), 'src') app.plugins = uniqueBy(await resolvePaths(nuxt, app.plugins, 'src'), 'src')
// Resolve app.config // Resolve app.config
app.configs = [] app.configs = []
@ -233,16 +233,21 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
await nuxt.callHook('app:resolve', app) await nuxt.callHook('app:resolve', app)
// Normalize and de-duplicate plugins and middleware // Normalize and de-duplicate plugins and middleware
app.middleware = uniqueBy(await resolvePaths(app.middleware, 'path'), 'name') app.middleware = uniqueBy(await resolvePaths(nuxt, app.middleware, 'path'), 'name')
app.plugins = uniqueBy(await resolvePaths(app.plugins, 'src'), 'src') app.plugins = uniqueBy(await resolvePaths(nuxt, app.plugins, 'src'), 'src')
} }
function resolvePaths<Item extends Record<string, any>> (items: Item[], key: { [K in keyof Item]: Item[K] extends string ? K : never }[keyof Item]) { function resolvePaths<Item extends Record<string, any>> (nuxt: Nuxt, items: Item[], key: { [K in keyof Item]: Item[K] extends string ? K : never }[keyof Item]) {
return Promise.all(items.map(async (item) => { return Promise.all(items.map(async (item) => {
if (!item[key]) { return item } if (!item[key]) { return item }
return { return {
...item, ...item,
[key]: await resolvePath(resolveAlias(item[key])), [key]: await resolvePath(item[key], {
alias: nuxt.options.alias,
extensions: nuxt.options.extensions,
fallbackToOriginal: true,
virtual: true,
}),
} }
})) }))
} }

View File

@ -1,7 +1,7 @@
import type { EventType } from '@parcel/watcher' import type { EventType } from '@parcel/watcher'
import type { FSWatcher } from 'chokidar' import type { FSWatcher } from 'chokidar'
import { watch as chokidarWatch } from 'chokidar' import { watch as chokidarWatch } from 'chokidar'
import { createIsIgnored, directoryToURL, importModule, isIgnored, tryResolveModule, useNuxt } from '@nuxt/kit' import { createIsIgnored, directoryToURL, importModule, isIgnored, useNuxt } from '@nuxt/kit'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { normalize, relative, resolve } from 'pathe' import { normalize, relative, resolve } from 'pathe'
import type { Nuxt, NuxtBuilder } from 'nuxt/schema' import type { Nuxt, NuxtBuilder } from 'nuxt/schema'
@ -196,37 +196,36 @@ async function createParcelWatcher () {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.time('[nuxt] builder:parcel:watch') console.time('[nuxt] builder:parcel:watch')
} }
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(d => directoryToURL(d))) try {
if (!watcherPath) { const { subscribe } = await importModule<typeof import('@parcel/watcher')>('@parcel/watcher', { url: [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(d => directoryToURL(d)) })
for (const layer of nuxt.options._layers) {
if (!layer.config.srcDir) { continue }
const watcher = subscribe(layer.config.srcDir, (err, events) => {
if (err) { return }
for (const event of events) {
if (isIgnored(event.path)) { continue }
// TODO: consider moving to emit absolute path in 3.8 or 4.0
nuxt.callHook('builder:watch', watchEvents[event.type], nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, event.path)) : normalize(event.path))
}
}, {
ignore: [
...nuxt.options.ignore,
'node_modules',
],
})
watcher.then((subscription) => {
if (nuxt.options.debug && nuxt.options.debug.watchers) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:parcel:watch')
}
nuxt.hook('close', () => subscription.unsubscribe())
})
}
return true
} catch {
logger.warn('Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.') logger.warn('Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.')
return false return false
} }
const { subscribe } = await importModule<typeof import('@parcel/watcher')>(watcherPath)
for (const layer of nuxt.options._layers) {
if (!layer.config.srcDir) { continue }
const watcher = subscribe(layer.config.srcDir, (err, events) => {
if (err) { return }
for (const event of events) {
if (isIgnored(event.path)) { continue }
// TODO: consider moving to emit absolute path in 3.8 or 4.0
nuxt.callHook('builder:watch', watchEvents[event.type], nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, event.path)) : normalize(event.path))
}
}, {
ignore: [
...nuxt.options.ignore,
'node_modules',
],
})
watcher.then((subscription) => {
if (nuxt.options.debug && nuxt.options.debug.watchers) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:parcel:watch')
}
nuxt.hook('close', () => subscription.unsubscribe())
})
}
return true
} }
async function bundle (nuxt: Nuxt) { async function bundle (nuxt: Nuxt) {
@ -248,10 +247,9 @@ async function bundle (nuxt: Nuxt) {
} }
async function loadBuilder (nuxt: Nuxt, builder: string): Promise<NuxtBuilder> { async function loadBuilder (nuxt: Nuxt, builder: string): Promise<NuxtBuilder> {
const builderPath = await tryResolveModule(builder, [directoryToURL(nuxt.options.rootDir), new URL(import.meta.url)]) try {
return await importModule(builder, { url: [directoryToURL(nuxt.options.rootDir), new URL(import.meta.url)] })
if (!builderPath) { } catch {
throw new Error(`Loading \`${builder}\` builder failed. You can read more about the nuxt \`builder\` option at: \`https://nuxt.com/docs/api/nuxt-config#builder\``) throw new Error(`Loading \`${builder}\` builder failed. You can read more about the nuxt \`builder\` option at: \`https://nuxt.com/docs/api/nuxt-config#builder\``)
} }
return importModule(builderPath)
} }

View File

@ -6,7 +6,7 @@ import { join, normalize, relative, resolve } from 'pathe'
import { createDebugger, createHooks } from 'hookable' import { createDebugger, createHooks } from 'hookable'
import ignore from 'ignore' import ignore from 'ignore'
import type { LoadNuxtOptions } from '@nuxt/kit' import type { LoadNuxtOptions } from '@nuxt/kit'
import { addBuildPlugin, addComponent, addPlugin, addPluginTemplate, addRouteMiddleware, addServerPlugin, addTypeTemplate, addVitePlugin, addWebpackPlugin, directoryToURL, installModule, loadNuxtConfig, nuxtCtx, resolveAlias, resolveFiles, resolveIgnorePatterns, resolvePath, runWithNuxtContext, tryResolveModule, useNitro } from '@nuxt/kit' import { addBuildPlugin, addComponent, addPlugin, addPluginTemplate, addRouteMiddleware, addServerPlugin, addTypeTemplate, addVitePlugin, addWebpackPlugin, directoryToURL, installModule, loadNuxtConfig, nuxtCtx, resolveAlias, resolveFiles, resolveIgnorePatterns, runWithNuxtContext, useNitro } from '@nuxt/kit'
import type { Nuxt, NuxtHooks, NuxtModule, NuxtOptions } from 'nuxt/schema' import type { Nuxt, NuxtHooks, NuxtModule, NuxtOptions } from 'nuxt/schema'
import type { PackageJson } from 'pkg-types' import type { PackageJson } from 'pkg-types'
import { readPackageJSON } from 'pkg-types' import { readPackageJSON } from 'pkg-types'
@ -24,6 +24,7 @@ import defu from 'defu'
import { gt, satisfies } from 'semver' import { gt, satisfies } from 'semver'
import { hasTTY, isCI } from 'std-env' import { hasTTY, isCI } from 'std-env'
import { genImport } from 'knitwork' import { genImport } from 'knitwork'
import { resolveModulePath, resolveModuleURL } from 'exsolve'
import pagesModule from '../pages/module' import pagesModule from '../pages/module'
import metaModule from '../head/module' import metaModule from '../head/module'
@ -389,14 +390,14 @@ async function initNuxt (nuxt: Nuxt) {
})) }))
} }
nuxt.hook('modules:done', async () => { nuxt.hook('modules:done', () => {
const importPaths = nuxt.options.modulesDir.map(dir => directoryToURL((dir))) const importPaths = nuxt.options.modulesDir.map(dir => directoryToURL((dir)))
// Add unctx transform // Add unctx transform
addBuildPlugin(UnctxTransformPlugin({ addBuildPlugin(UnctxTransformPlugin({
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
transformerOptions: { transformerOptions: {
...nuxt.options.optimization.asyncTransforms, ...nuxt.options.optimization.asyncTransforms,
helperModule: await tryResolveModule('unctx', importPaths) ?? 'unctx', helperModule: resolveModuleURL('unctx', { try: true, from: importPaths }) ?? 'unctx',
}, },
})) }))
@ -481,8 +482,14 @@ async function initNuxt (nuxt: Nuxt) {
for (const _mod of nuxt.options.modules) { for (const _mod of nuxt.options.modules) {
const mod = Array.isArray(_mod) ? _mod[0] : _mod const mod = Array.isArray(_mod) ? _mod[0] : _mod
if (typeof mod !== 'string') { continue } if (typeof mod !== 'string') { continue }
const modPath = await resolvePath(resolveAlias(mod), { fallbackToOriginal: true }) const modAlias = resolveAlias(mod)
specifiedModules.add(modPath) const modPath = resolveModulePath(modAlias, {
try: true,
from: nuxt.options.modulesDir.map(m => directoryToURL(m.replace(/\/node_modules\/?$/, '/'))),
suffixes: ['nuxt', 'nuxt/index', 'module', 'module/index', '', 'index'],
extensions: ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'],
})
specifiedModules.add(modPath || modAlias)
} }
// Automatically register user modules // Automatically register user modules
@ -919,9 +926,9 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
} }
export async function checkDependencyVersion (name: string, nuxtVersion: string): Promise<void> { export async function checkDependencyVersion (name: string, nuxtVersion: string): Promise<void> {
const path = await resolvePath(name, { fallbackToOriginal: true }).catch(() => null) const path = resolveModulePath(name, { try: true })
if (!path || path === name) { return } if (!path) { return }
const { version } = await readPackageJSON(path) const { version } = await readPackageJSON(path)
if (version && gt(nuxtVersion, version)) { if (version && gt(nuxtVersion, version)) {

View File

@ -1,4 +1,5 @@
import { parseNodeModulePath, resolvePath } from 'mlly' import { parseNodeModulePath } from 'mlly'
import { resolveModulePath } from 'exsolve'
import { isAbsolute, normalize } from 'pathe' import { isAbsolute, normalize } from 'pathe'
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import { directoryToURL, resolveAlias } from '@nuxt/kit' import { directoryToURL, resolveAlias } from '@nuxt/kit'
@ -36,13 +37,24 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
const normalisedImporter = importer.replace(/^\0?virtual:(?:nuxt:)?/, '') const normalisedImporter = importer.replace(/^\0?virtual:(?:nuxt:)?/, '')
const dir = parseNodeModulePath(normalisedImporter).dir || pkgDir const dir = parseNodeModulePath(normalisedImporter).dir || pkgDir
return await this.resolve?.(normalisedId, dir, { skipSelf: true }) ?? await resolvePath(id, { const res = await this.resolve?.(normalisedId, dir, { skipSelf: true })
url: [dir, ...nuxt.options.modulesDir].map(d => directoryToURL(d)), if (res !== undefined && res !== null) {
return res
}
const path = resolveModulePath(id, {
from: [dir, ...nuxt.options.modulesDir].map(d => directoryToURL(d)),
suffixes: ['', 'index'],
conditions, conditions,
}).catch(() => { try: true,
})
if (!path) {
logger.debug('Could not resolve id', id, importer) logger.debug('Could not resolve id', id, importer)
return null return null
}) }
return normalize(path)
}, },
} }
} }

View File

@ -5,7 +5,7 @@ import { resolve } from 'pathe'
import { watch } from 'chokidar' import { watch } from 'chokidar'
import { defu } from 'defu' import { defu } from 'defu'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { createIsIgnored, createResolver, defineNuxtModule, directoryToURL, importModule, tryResolveModule } from '@nuxt/kit' import { createIsIgnored, createResolver, defineNuxtModule, directoryToURL, importModule } from '@nuxt/kit'
import { generateTypes, resolveSchema as resolveUntypedSchema } from 'untyped' import { generateTypes, resolveSchema as resolveUntypedSchema } from 'untyped'
import type { Schema, SchemaDefinition } from 'untyped' import type { Schema, SchemaDefinition } from 'untyped'
import untypedPlugin from 'untyped/babel-plugin' import untypedPlugin from 'untyped/babel-plugin'
@ -57,9 +57,10 @@ export default defineNuxtModule({
}) })
if (nuxt.options.experimental.watcher === 'parcel') { if (nuxt.options.experimental.watcher === 'parcel') {
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(dir => directoryToURL(dir))) try {
if (watcherPath) { const { subscribe } = await importModule<typeof import('@parcel/watcher')>('@parcel/watcher', {
const { subscribe } = await importModule<typeof import('@parcel/watcher')>(watcherPath) url: [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(dir => directoryToURL(dir)),
})
for (const layer of nuxt.options._layers) { for (const layer of nuxt.options._layers) {
const subscription = await subscribe(layer.config.rootDir, onChange, { const subscription = await subscribe(layer.config.rootDir, onChange, {
ignore: ['!nuxt.schema.*'], ignore: ['!nuxt.schema.*'],
@ -67,8 +68,9 @@ export default defineNuxtModule({
nuxt.hook('close', () => subscription.unsubscribe()) nuxt.hook('close', () => subscription.unsubscribe())
} }
return return
} catch {
logger.warn('Falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project.')
} }
logger.warn('Falling back to `chokidar` as `@parcel/watcher` cannot be resolved in your project.')
} }
const isIgnored = createIsIgnored(nuxt) const isIgnored = createIsIgnored(nuxt)

View File

@ -1,11 +1,14 @@
import { resolvePackageJSON } from 'pkg-types' import { resolvePackageJSON } from 'pkg-types'
import { resolvePath as _resolvePath } from 'mlly' import { resolveModulePath } from 'exsolve'
import { dirname } from 'pathe' import { dirname } from 'pathe'
import { directoryToURL, tryUseNuxt } from '@nuxt/kit' import { directoryToURL, tryUseNuxt } from '@nuxt/kit'
export async function resolveTypePath (path: string, subpath: string, searchPaths = tryUseNuxt()?.options.modulesDir) { export async function resolveTypePath (path: string, subpath: string, searchPaths = tryUseNuxt()?.options.modulesDir) {
try { try {
const r = await _resolvePath(path, { url: searchPaths?.map(d => directoryToURL(d)), conditions: ['types', 'import', 'require'] }) const r = resolveModulePath(path, {
from: searchPaths?.map(d => directoryToURL(d)),
conditions: ['types', 'import', 'require'],
})
if (subpath) { if (subpath) {
return r.replace(/(?:\.d)?\.[mc]?[jt]s$/, '') return r.replace(/(?:\.d)?\.[mc]?[jt]s$/, '')
} }

View File

@ -1,6 +1,7 @@
import { resolve } from 'pathe' import { resolve } from 'pathe'
import { addComponent, addImportsSources, addPlugin, addTemplate, defineNuxtModule, directoryToURL, tryResolveModule } from '@nuxt/kit' import { addComponent, addImportsSources, addPlugin, addTemplate, defineNuxtModule, directoryToURL } from '@nuxt/kit'
import type { NuxtOptions } from '@nuxt/schema' import type { NuxtOptions } from '@nuxt/schema'
import { resolveModulePath } from 'exsolve'
import { distDir } from '../dirs' import { distDir } from '../dirs'
const components = ['NoScript', 'Link', 'Base', 'Title', 'Meta', 'Style', 'Head', 'Html', 'Body'] const components = ['NoScript', 'Link', 'Base', 'Title', 'Meta', 'Style', 'Head', 'Html', 'Body']
@ -10,7 +11,7 @@ export default defineNuxtModule<NuxtOptions['unhead']>({
name: 'nuxt:meta', name: 'nuxt:meta',
configKey: 'unhead', configKey: 'unhead',
}, },
async setup (options, nuxt) { setup (options, nuxt) {
const runtimeDir = resolve(distDir, 'head/runtime') const runtimeDir = resolve(distDir, 'head/runtime')
// Transpile @unhead/vue // Transpile @unhead/vue
@ -53,7 +54,7 @@ export default defineNuxtModule<NuxtOptions['unhead']>({
// Opt-out feature allowing dependencies using @vueuse/head to work // Opt-out feature allowing dependencies using @vueuse/head to work
const importPaths = nuxt.options.modulesDir.map(d => directoryToURL(d)) const importPaths = nuxt.options.modulesDir.map(d => directoryToURL(d))
const unheadVue = await tryResolveModule('@unhead/vue', importPaths) || '@unhead/vue' const unheadVue = resolveModulePath('@unhead/vue', { try: true, from: importPaths }) || '@unhead/vue'
if (nuxt.options.experimental.polyfillVueUseHead) { if (nuxt.options.experimental.polyfillVueUseHead) {
// backwards compatibility // backwards compatibility
nuxt.options.alias['@vueuse/head'] = unheadVue nuxt.options.alias['@vueuse/head'] = unheadVue

View File

@ -241,6 +241,9 @@ importers:
destr: destr:
specifier: ^2.0.3 specifier: ^2.0.3
version: 2.0.3 version: 2.0.3
exsolve:
specifier: ^1.0.1
version: 1.0.1
globby: globby:
specifier: ^14.1.0 specifier: ^14.1.0
version: 14.1.0 version: 14.1.0
@ -310,7 +313,7 @@ importers:
version: 2.10.4(typescript@5.7.3) version: 2.10.4(typescript@5.7.3)
unbuild: unbuild:
specifier: latest specifier: latest
version: 3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) version: 3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
vite: vite:
specifier: 6.2.0 specifier: 6.2.0
version: 6.2.0(@types/node@22.13.5)(jiti@2.4.2)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.2)(yaml@2.7.0) version: 6.2.0(@types/node@22.13.5)(jiti@2.4.2)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.2)(yaml@2.7.0)
@ -401,6 +404,9 @@ importers:
estree-walker: estree-walker:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.3 version: 3.0.3
exsolve:
specifier: ^1.0.1
version: 1.0.1
globby: globby:
specifier: ^14.1.0 specifier: ^14.1.0
version: 14.1.0 version: 14.1.0
@ -539,7 +545,7 @@ importers:
version: 3.5.13 version: 3.5.13
unbuild: unbuild:
specifier: latest specifier: latest
version: 3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) version: 3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
vite: vite:
specifier: 6.2.0 specifier: 6.2.0
version: 6.2.0(@types/node@22.13.5)(jiti@2.4.2)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.2)(yaml@2.7.0) version: 6.2.0(@types/node@22.13.5)(jiti@2.4.2)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.2)(yaml@2.7.0)
@ -684,7 +690,7 @@ importers:
version: 4.34.8 version: 4.34.8
unbuild: unbuild:
specifier: latest specifier: latest
version: 3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) version: 3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
vue: vue:
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13(typescript@5.7.3) version: 3.5.13(typescript@5.7.3)
@ -974,7 +980,7 @@ importers:
version: 4.34.8 version: 4.34.8
unbuild: unbuild:
specifier: latest specifier: latest
version: 3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) version: 3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
vue: vue:
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13(typescript@5.7.3) version: 3.5.13(typescript@5.7.3)
@ -1113,7 +1119,7 @@ importers:
version: 2.25.9 version: 2.25.9
unbuild: unbuild:
specifier: latest specifier: latest
version: 3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) version: 3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
vue: vue:
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13(typescript@5.7.3) version: 3.5.13(typescript@5.7.3)
@ -2378,8 +2384,8 @@ packages:
'@redocly/config@0.21.0': '@redocly/config@0.21.0':
resolution: {integrity: sha512-JBtrrjBIURTnzb7KUIWOF46vSgpfC3rO6Mm8LjtRjtTNCLTyB+mOuU7HrTkVcvUCEBuSuzkivlTHMWT4JETz9A==} resolution: {integrity: sha512-JBtrrjBIURTnzb7KUIWOF46vSgpfC3rO6Mm8LjtRjtTNCLTyB+mOuU7HrTkVcvUCEBuSuzkivlTHMWT4JETz9A==}
'@redocly/openapi-core@1.31.3': '@redocly/openapi-core@1.31.2':
resolution: {integrity: sha512-SyE/1TwM33tgldc3k367sg2i1kqnILOJZo6J96Y/Tt1PHhJp+na637CzCuTgdyY86GTPvNw42834Ks0Lkfk3Hg==} resolution: {integrity: sha512-HScpiSuluLic9+QpsI2JWaegeDuRn3hximPBpiUpy4WdXf74Ev094kpUgjhiD3xDuP/KpVdchooAkLnzQ0X+vg==}
engines: {node: '>=18.17.0', npm: '>=9.5.0'} engines: {node: '>=18.17.0', npm: '>=9.5.0'}
'@rollup/plugin-alias@5.1.1': '@rollup/plugin-alias@5.1.1':
@ -2631,8 +2637,8 @@ packages:
'@shikijs/core@1.23.1': '@shikijs/core@1.23.1':
resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==} resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==}
'@shikijs/core@3.1.0': '@shikijs/core@3.0.0':
resolution: {integrity: sha512-1ppAOyg3F18N8Ge9DmJjGqRVswihN33rOgPovR6gUHW17Hw1L4RlRhnmVQcsacSHh0A8IO1FIgNbtTxUFwodmg==} resolution: {integrity: sha512-gSm3JQf2J2psiUn5bWokmZwnu5N0jfBtRps4CQ1B+qrFvmZCRAkMVoaxgl9qZgAFK5KisLAS3//XaMFVytYHKw==}
'@shikijs/engine-javascript@1.22.2': '@shikijs/engine-javascript@1.22.2':
resolution: {integrity: sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==} resolution: {integrity: sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==}
@ -2649,10 +2655,8 @@ packages:
'@shikijs/transformers@1.22.2': '@shikijs/transformers@1.22.2':
resolution: {integrity: sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==} resolution: {integrity: sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==}
'@shikijs/twoslash@3.1.0': '@shikijs/twoslash@3.0.0':
resolution: {integrity: sha512-cEaS6Nw1IhcJRc0RxJWIaZLXq0A5d9aJ9LoRfO4+y1L1wqC/+YCqrMEZqxkdjep3usCbZRae13fcXMd4pz8fHQ==} resolution: {integrity: sha512-Il7XsIzbBLGV67i4yCoBDFvlMOuky1DpMyHgBjNjBu7gEw/DcmpoEEs1MwVH6Lk6fX4wXDhMQ+pDL2EwqzWqdQ==}
peerDependencies:
typescript: 5.7.3
'@shikijs/types@1.22.2': '@shikijs/types@1.22.2':
resolution: {integrity: sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==} resolution: {integrity: sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==}
@ -2660,8 +2664,8 @@ packages:
'@shikijs/types@1.23.1': '@shikijs/types@1.23.1':
resolution: {integrity: sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==} resolution: {integrity: sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==}
'@shikijs/types@3.1.0': '@shikijs/types@3.0.0':
resolution: {integrity: sha512-F8e7Fy4ihtcNpJG572BZZC1ErYrBrzJ5Cbc9Zi3REgWry43gIvjJ9lFAoUnuy7Bvy4IFz7grUSxL5edfrrjFEA==} resolution: {integrity: sha512-kh/xgZHxI6m9trVvPw+C47jyVHx190r0F5gkF+VO5vYB54UtcoPJe66dzZmK7GbJbzmtGEGbOwct/jsoPjjUqg==}
'@shikijs/vitepress-twoslash@1.23.1': '@shikijs/vitepress-twoslash@1.23.1':
resolution: {integrity: sha512-L67HkzDkbECjYdWxQA9BuKAIB0c7eaa+7sD6dZUQ6/cdJGiWvaPLYMRwMWZQ4ToRsz1X6MQmOKQp6Xb6FEc3Bg==} resolution: {integrity: sha512-L67HkzDkbECjYdWxQA9BuKAIB0c7eaa+7sD6dZUQ6/cdJGiWvaPLYMRwMWZQ4ToRsz1X6MQmOKQp6Xb6FEc3Bg==}
@ -7180,9 +7184,6 @@ packages:
twoslash-protocol@0.2.12: twoslash-protocol@0.2.12:
resolution: {integrity: sha512-5qZLXVYfZ9ABdjqbvPc4RWMr7PrpPaaDSeaYY55vl/w1j6H6kzsWK/urAEIXlzYlyrFmyz1UbwIt+AA0ck+wbg==} resolution: {integrity: sha512-5qZLXVYfZ9ABdjqbvPc4RWMr7PrpPaaDSeaYY55vl/w1j6H6kzsWK/urAEIXlzYlyrFmyz1UbwIt+AA0ck+wbg==}
twoslash-protocol@0.3.1:
resolution: {integrity: sha512-BMePTL9OkuNISSyyMclBBhV2s9++DiOCyhhCoV5Kaht6eaWLwVjCCUJHY33eZJPsyKeZYS8Wzz0h+XI01VohVw==}
twoslash-vue@0.2.12: twoslash-vue@0.2.12:
resolution: {integrity: sha512-kxH60DLn2QBcN2wjqxgMDkyRgmPXsytv7fJIlsyFMDPSkm1/lMrI/UMrNAshNaRHcI+hv8x3h/WBgcvlb2RNAQ==} resolution: {integrity: sha512-kxH60DLn2QBcN2wjqxgMDkyRgmPXsytv7fJIlsyFMDPSkm1/lMrI/UMrNAshNaRHcI+hv8x3h/WBgcvlb2RNAQ==}
peerDependencies: peerDependencies:
@ -7193,11 +7194,6 @@ packages:
peerDependencies: peerDependencies:
typescript: 5.7.3 typescript: 5.7.3
twoslash@0.3.1:
resolution: {integrity: sha512-OGqMTGvqXTcb92YQdwGfEdK0nZJA64Aj/ChLOelbl3TfYch2IoBST0Yx4C0LQ7Lzyqm9RpgcpgDxeXQIz4p2Kg==}
peerDependencies:
typescript: 5.7.3
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@ -7228,6 +7224,15 @@ packages:
ultrahtml@1.5.3: ultrahtml@1.5.3:
resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==}
unbuild@3.3.1:
resolution: {integrity: sha512-/5OeeHmW1JlWEyQw3SPkB9BV16lzr6C5i8D+O17NLx6ETgvCZ3ZlyXfWkVVfG2YCsv8xAVQCqJNJtbEAGwHg7A==}
hasBin: true
peerDependencies:
typescript: 5.7.3
peerDependenciesMeta:
typescript:
optional: true
unbuild@3.5.0: unbuild@3.5.0:
resolution: {integrity: sha512-DPFttsiADnHRb/K+yJ9r9jdn6JyXlsmdT0S12VFC14DFSJD+cxBnHq+v0INmqqPVPxOoUjvJFYUVIb02rWnVeA==} resolution: {integrity: sha512-DPFttsiADnHRb/K+yJ9r9jdn6JyXlsmdT0S12VFC14DFSJD+cxBnHq+v0INmqqPVPxOoUjvJFYUVIb02rWnVeA==}
hasBin: true hasBin: true
@ -9132,7 +9137,7 @@ snapshots:
'@redocly/config@0.21.0': {} '@redocly/config@0.21.0': {}
'@redocly/openapi-core@1.31.3(supports-color@9.4.0)': '@redocly/openapi-core@1.31.2(supports-color@9.4.0)':
dependencies: dependencies:
'@redocly/ajv': 8.11.2 '@redocly/ajv': 8.11.2
'@redocly/config': 0.21.0 '@redocly/config': 0.21.0
@ -9344,9 +9349,9 @@ snapshots:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
hast-util-to-html: 9.0.5 hast-util-to-html: 9.0.5
'@shikijs/core@3.1.0': '@shikijs/core@3.0.0':
dependencies: dependencies:
'@shikijs/types': 3.1.0 '@shikijs/types': 3.0.0
'@shikijs/vscode-textmate': 10.0.2 '@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4 '@types/hast': 3.0.4
hast-util-to-html: 9.0.5 hast-util-to-html: 9.0.5
@ -9377,14 +9382,14 @@ snapshots:
dependencies: dependencies:
shiki: 1.22.2 shiki: 1.22.2
'@shikijs/twoslash@3.1.0(typescript@5.7.3)': '@shikijs/twoslash@3.0.0(typescript@5.7.3)':
dependencies: dependencies:
'@shikijs/core': 3.1.0 '@shikijs/core': 3.0.0
'@shikijs/types': 3.1.0 '@shikijs/types': 3.0.0
twoslash: 0.3.1(typescript@5.7.3) twoslash: 0.2.12(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
- typescript
'@shikijs/types@1.22.2': '@shikijs/types@1.22.2':
dependencies: dependencies:
@ -9396,14 +9401,14 @@ snapshots:
'@shikijs/vscode-textmate': 9.3.1 '@shikijs/vscode-textmate': 9.3.1
'@types/hast': 3.0.4 '@types/hast': 3.0.4
'@shikijs/types@3.1.0': '@shikijs/types@3.0.0':
dependencies: dependencies:
'@shikijs/vscode-textmate': 10.0.2 '@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4 '@types/hast': 3.0.4
'@shikijs/vitepress-twoslash@1.23.1(@nuxt/kit@packages+kit)(typescript@5.7.3)': '@shikijs/vitepress-twoslash@1.23.1(@nuxt/kit@packages+kit)(typescript@5.7.3)':
dependencies: dependencies:
'@shikijs/twoslash': 3.1.0(typescript@5.7.3) '@shikijs/twoslash': 3.0.0(typescript@5.7.3)
floating-vue: 5.2.2(@nuxt/kit@packages+kit)(vue@3.5.13(typescript@5.7.3)) floating-vue: 5.2.2(@nuxt/kit@packages+kit)(vue@3.5.13(typescript@5.7.3))
mdast-util-from-markdown: 2.0.2 mdast-util-from-markdown: 2.0.2
mdast-util-gfm: 3.0.0 mdast-util-gfm: 3.0.0
@ -13497,7 +13502,7 @@ snapshots:
openapi-typescript@7.6.1(typescript@5.7.3): openapi-typescript@7.6.1(typescript@5.7.3):
dependencies: dependencies:
'@redocly/openapi-core': 1.31.3(supports-color@9.4.0) '@redocly/openapi-core': 1.31.2(supports-color@9.4.0)
ansi-colors: 4.1.3 ansi-colors: 4.1.3
change-case: 5.4.4 change-case: 5.4.4
parse-json: 8.1.0 parse-json: 8.1.0
@ -14883,8 +14888,6 @@ snapshots:
twoslash-protocol@0.2.12: {} twoslash-protocol@0.2.12: {}
twoslash-protocol@0.3.1: {}
twoslash-vue@0.2.12(typescript@5.7.3): twoslash-vue@0.2.12(typescript@5.7.3):
dependencies: dependencies:
'@vue/language-core': 2.1.10(typescript@5.7.3) '@vue/language-core': 2.1.10(typescript@5.7.3)
@ -14902,14 +14905,6 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
twoslash@0.3.1(typescript@5.7.3):
dependencies:
'@typescript/vfs': 1.6.1(typescript@5.7.3)
twoslash-protocol: 0.3.1
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
@ -14928,6 +14923,39 @@ snapshots:
ultrahtml@1.5.3: {} ultrahtml@1.5.3: {}
unbuild@3.3.1(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)):
dependencies:
'@rollup/plugin-alias': 5.1.1(rollup@4.34.8)
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.34.8)
'@rollup/plugin-replace': 6.0.2(rollup@4.34.8)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
citty: 0.1.6
consola: 3.4.0
defu: 6.1.4
esbuild: 0.24.2
hookable: 5.5.3
jiti: 2.4.2
magic-string: 0.30.17
mkdist: 2.2.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))
mlly: 1.7.4
pathe: 2.0.3
pkg-types: 1.3.1
pretty-bytes: 6.1.1
rollup: 4.34.8
rollup-plugin-dts: 6.1.1(rollup@4.34.8)(typescript@5.7.3)
scule: 1.3.0
tinyglobby: 0.2.12
untyped: 1.5.2
optionalDependencies:
typescript: 5.7.3
transitivePeerDependencies:
- sass
- supports-color
- vue
- vue-tsc
unbuild@3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)): unbuild@3.5.0(typescript@5.7.3)(vue-tsc@2.2.4(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)):
dependencies: dependencies:
'@rollup/plugin-alias': 5.1.1(rollup@4.34.8) '@rollup/plugin-alias': 5.1.1(rollup@4.34.8)

View File

@ -35,7 +35,7 @@ export default defineNuxtConfig({
} }
}) })
}, },
'~/modules/subpath', '~/custom-modules/subpath',
'./modules/test', './modules/test',
'~/modules/example', '~/modules/example',
function (_, nuxt) { function (_, nuxt) {