From fb9ee0a4ea385d5e8c77e8cf60a30bff7a987749 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 26 Feb 2025 17:02:04 +0000 Subject: [PATCH] perf(nuxt): migrate to use `exsolve` for module resolution (#31124) --- packages/kit/package.json | 1 + packages/kit/src/internal/esm.ts | 21 +-- packages/kit/src/loader/config.ts | 11 +- packages/kit/src/module/install.ts | 121 ++++++++---------- packages/kit/src/plugin.ts | 8 +- packages/kit/src/resolve.ts | 10 +- packages/kit/src/template.ts | 5 +- packages/nuxt/package.json | 1 + packages/nuxt/src/components/module.ts | 5 +- packages/nuxt/src/core/app.ts | 19 ++- packages/nuxt/src/core/builder.ts | 64 +++++---- packages/nuxt/src/core/nuxt.ts | 21 ++- .../src/core/plugins/resolve-deep-imports.ts | 22 +++- packages/nuxt/src/core/schema.ts | 12 +- packages/nuxt/src/core/utils/types.ts | 7 +- packages/nuxt/src/head/module.ts | 7 +- pnpm-lock.yaml | 116 ++++++++++------- .../subpath/index.ts | 0 .../subpath/module.ts | 0 test/fixtures/basic/nuxt.config.ts | 2 +- 20 files changed, 250 insertions(+), 203 deletions(-) rename test/fixtures/basic/{modules => custom-modules}/subpath/index.ts (100%) rename test/fixtures/basic/{modules => custom-modules}/subpath/module.ts (100%) diff --git a/packages/kit/package.json b/packages/kit/package.json index afcefb03c0..30ba2e3c54 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -31,6 +31,7 @@ "consola": "^3.4.0", "defu": "^6.1.4", "destr": "^2.0.3", + "exsolve": "^1.0.1", "globby": "^14.1.0", "ignore": "^7.0.3", "jiti": "^2.4.2", diff --git a/packages/kit/src/internal/esm.ts b/packages/kit/src/internal/esm.ts index 0e0da84bfb..2ceb24de68 100644 --- a/packages/kit/src/internal/esm.ts +++ b/packages/kit/src/internal/esm.ts @@ -1,5 +1,6 @@ import { pathToFileURL } from 'node:url' -import { interopDefault, resolvePath, resolvePathSync } from 'mlly' +import { interopDefault } from 'mlly' +import { resolveModulePath } from 'exsolve' import { createJiti } from 'jiti' export interface ResolveModuleOptions { @@ -20,17 +21,19 @@ export function directoryToURL (dir: string): URL { */ export async function tryResolveModule (id: string, url: URL | URL[]): Promise /** @deprecated pass URLs pointing at files */ -export async function tryResolveModule (id: string, url: string | string[]): Promise -export async function tryResolveModule (id: string, url: string | string[] | URL | URL[] = import.meta.url) { - try { - return await resolvePath(id, { url }) - } catch { - // intentionally empty as this is a `try-` function - } +export function tryResolveModule (id: string, url: string | string[]): Promise +export function tryResolveModule (id: string, url: string | string[] | URL | URL[] = import.meta.url) { + return Promise.resolve(resolveModulePath(id, { + from: url, + suffixes: ['', 'index'], + try: true, + })) } 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 { diff --git a/packages/kit/src/loader/config.ts b/packages/kit/src/loader/config.ts index 125146e462..c7682ad3c4 100644 --- a/packages/kit/src/loader/config.ts +++ b/packages/kit/src/loader/config.ts @@ -8,8 +8,9 @@ import type { NuxtConfig, NuxtOptions } from '@nuxt/schema' import { globby } from 'globby' import defu from 'defu' import { basename, join, relative } from 'pathe' -import { isWindows } from 'std-env' -import { directoryToURL, tryResolveModule } from '../internal/esm' +import { resolveModuleURL } from 'exsolve' + +import { directoryToURL } from '../internal/esm' export interface LoadNuxtConfigOptions extends Omit, 'overrides'> { // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type @@ -110,10 +111,10 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise r.NuxtConfigSchema) + const schemaPath = resolveModuleURL('@nuxt/schema', { try: true, from: urls }) ?? '@nuxt/schema' + return await import(schemaPath).then(r => r.NuxtConfigSchema) } diff --git a/packages/kit/src/module/install.ts b/packages/kit/src/module/install.ts index 17b9005e6b..5e9cf24c6e 100644 --- a/packages/kit/src/module/install.ts +++ b/packages/kit/src/module/install.ts @@ -1,16 +1,16 @@ 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 { dirname, isAbsolute, join, resolve } from 'pathe' +import { dirname, isAbsolute, resolve } from 'pathe' import { defu } from 'defu' import { createJiti } from 'jiti' -import { parseNodeModulePath, resolve as resolveModule } from 'mlly' +import { parseNodeModulePath } from 'mlly' +import { resolveModuleURL } from 'exsolve' import { isRelative } from 'ufo' import { isNuxt2 } from '../compatibility' import { directoryToURL } from '../internal/esm' import { useNuxt } from '../context' -import { resolveAlias, resolvePath } from '../resolve' -import { logger } from '../logger' +import { resolveAlias } from '../resolve' const NODE_MODULES_RE = /[/\\]node_modules[/\\]/ @@ -87,84 +87,63 @@ export const normalizeModuleTranspilePath = (p: string) => { 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, buildTimeModuleMeta: ModuleMeta, resolvedModulePath?: string }> { 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 }) - let resolvedNuxtModule: NuxtModule | undefined - let hadNonFunctionPath = false // Import if input is string - if (typeof nuxtModule === 'string') { - const paths = new Set() - nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias) + nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias) - if (isRelative(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 (isRelative(nuxtModule)) { + nuxtModule = resolve(nuxt.options.rootDir, nuxtModule) } - if (!resolvedNuxtModule) { - // Module was resolvable but returned a non-function - if (hadNonFunctionPath) { + try { + const src = resolveModuleURL(nuxtModule, { + 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>(src, { default: true }) + + if (typeof resolvedNuxtModule !== 'function') { 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?`) } + 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, buildTimeModuleMeta: ModuleMeta, resolvedModulePath?: string } + throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`) } diff --git a/packages/kit/src/plugin.ts b/packages/kit/src/plugin.ts index 26ae9b70dc..bdaa5ffb59 100644 --- a/packages/kit/src/plugin.ts +++ b/packages/kit/src/plugin.ts @@ -1,10 +1,8 @@ import { existsSync } from 'node:fs' import { isAbsolute } from 'node:path' -import { pathToFileURL } from 'node:url' import { normalize } from 'pathe' import type { NuxtPlugin, NuxtPluginTemplate } from '@nuxt/schema' -import { resolvePathSync } from 'mlly' -import { isWindows } from 'std-env' +import { resolveModulePath } from 'exsolve' import { MODE_RE, filterInPlace } from './utils' import { tryUseNuxt, useNuxt } from './context' import { addTemplate } from './template' @@ -35,7 +33,9 @@ export function normalizePlugin (plugin: NuxtPlugin | string): NuxtPlugin { if (!existsSync(plugin.src) && isAbsolute(plugin.src)) { 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 { // ignore errors as the file may be in the nuxt vfs } diff --git a/packages/kit/src/resolve.ts b/packages/kit/src/resolve.ts index 79b83a2146..d65a4e4d30 100644 --- a/packages/kit/src/resolve.ts +++ b/packages/kit/src/resolve.ts @@ -2,7 +2,7 @@ import { promises as fsp } from 'node:fs' import { fileURLToPath } from 'node:url' import { basename, dirname, isAbsolute, join, normalize, resolve } from 'pathe' import { globby } from 'globby' -import { resolvePath as _resolvePath } from 'mlly' +import { resolveModulePath } from 'exsolve' import { resolveAlias as _resolveAlias } from 'pathe/utils' import { directoryToURL } from './internal/esm' import { tryUseNuxt } from './context' @@ -172,7 +172,7 @@ async function _resolvePathGranularly (path: string, opts: ResolvePathOptions = const modulesDir = nuxt ? nuxt.options.modulesDir : [] // Resolve aliases - path = resolveAlias(path) + path = _resolveAlias(path, opts.alias ?? nuxt?.options.alias ?? {}) // Resolve relative to cwd if (!isAbsolute(path)) { @@ -200,7 +200,11 @@ async function _resolvePathGranularly (path: string, opts: ResolvePathOptions = } // 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) { return { path: resolvedModulePath, diff --git a/packages/kit/src/template.ts b/packages/kit/src/template.ts index a4682fd495..22988897ab 100644 --- a/packages/kit/src/template.ts +++ b/packages/kit/src/template.ts @@ -7,9 +7,10 @@ import { defu } from 'defu' import type { TSConfig } from 'pkg-types' import { gte } from 'semver' import { readPackageJSON } from 'pkg-types' +import { resolveModulePath } from 'exsolve' import { filterInPlace } from './utils' -import { directoryToURL, tryResolveModule } from './internal/esm' +import { directoryToURL } from './internal/esm' import { getDirectory } from './module/install' import { tryUseNuxt, useNuxt } from './context' import { resolveNuxtModule } from './resolve' @@ -250,7 +251,7 @@ export async function _generateTypes (nuxt: Nuxt) { let absolutePath = resolve(basePath, aliases[alias]!) let stats = await fsp.stat(absolutePath).catch(() => null /* file does not exist */) if (!stats) { - const resolvedModule = await tryResolveModule(aliases[alias]!, importPaths) + const resolvedModule = resolveModulePath(aliases[alias]!, { try: true, from: importPaths }) if (resolvedModule) { absolutePath = resolvedModule stats = await fsp.stat(resolvedModule).catch(() => null) diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index d6555feb03..b607d27b09 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -94,6 +94,7 @@ "esbuild": "^0.25.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", + "exsolve": "^1.0.1", "globby": "^14.1.0", "h3": "^1.15.1", "hookable": "^5.5.3", diff --git a/packages/nuxt/src/components/module.ts b/packages/nuxt/src/components/module.ts index d597e7312f..f08f629bad 100644 --- a/packages/nuxt/src/components/module.ts +++ b/packages/nuxt/src/components/module.ts @@ -1,8 +1,9 @@ import { existsSync, statSync, writeFileSync } from 'node:fs' 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 { resolveModulePath } from 'exsolve' import { distDir } from '../dirs' import { logger } from '../utils' import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates' @@ -175,7 +176,7 @@ export default defineNuxtModule({ for (const component of newComponents) { if (!(component as any /* untyped internal property */)._scanned && !(component.filePath in nuxt.vfs) && isAbsolute(component.filePath) && !existsSync(component.filePath)) { // 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')) { newComponents.push({ diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index 91e867041b..5743bcb8ad 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -1,7 +1,7 @@ import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs' import { dirname, join, relative, resolve } from 'pathe' 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 { PluginMeta } from 'nuxt/app' @@ -217,8 +217,8 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { } // Normalize and de-duplicate plugins and middleware - app.middleware = uniqueBy(await resolvePaths([...app.middleware].reverse(), 'path'), 'name').reverse() - app.plugins = uniqueBy(await resolvePaths(app.plugins, 'src'), 'src') + app.middleware = uniqueBy(await resolvePaths(nuxt, [...app.middleware].reverse(), 'path'), 'name').reverse() + app.plugins = uniqueBy(await resolvePaths(nuxt, app.plugins, 'src'), 'src') // Resolve app.config app.configs = [] @@ -233,16 +233,21 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { await nuxt.callHook('app:resolve', app) // Normalize and de-duplicate plugins and middleware - app.middleware = uniqueBy(await resolvePaths(app.middleware, 'path'), 'name') - app.plugins = uniqueBy(await resolvePaths(app.plugins, 'src'), 'src') + app.middleware = uniqueBy(await resolvePaths(nuxt, app.middleware, 'path'), 'name') + app.plugins = uniqueBy(await resolvePaths(nuxt, app.plugins, 'src'), 'src') } -function resolvePaths> (items: Item[], key: { [K in keyof Item]: Item[K] extends string ? K : never }[keyof Item]) { +function resolvePaths> (nuxt: Nuxt, items: Item[], key: { [K in keyof Item]: Item[K] extends string ? K : never }[keyof Item]) { return Promise.all(items.map(async (item) => { if (!item[key]) { return item } return { ...item, - [key]: await resolvePath(resolveAlias(item[key])), + [key]: await resolvePath(item[key], { + alias: nuxt.options.alias, + extensions: nuxt.options.extensions, + fallbackToOriginal: true, + virtual: true, + }), } })) } diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index e57f7af832..add72926b1 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -1,7 +1,7 @@ import type { EventType } from '@parcel/watcher' import type { FSWatcher } 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 { normalize, relative, resolve } from 'pathe' import type { Nuxt, NuxtBuilder } from 'nuxt/schema' @@ -196,37 +196,36 @@ async function createParcelWatcher () { // eslint-disable-next-line no-console console.time('[nuxt] builder:parcel:watch') } - const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(d => directoryToURL(d))) - if (!watcherPath) { + try { + const { subscribe } = await importModule('@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.') return false } - - const { subscribe } = await importModule(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) { @@ -248,10 +247,9 @@ async function bundle (nuxt: Nuxt) { } async function loadBuilder (nuxt: Nuxt, builder: string): Promise { - const builderPath = await tryResolveModule(builder, [directoryToURL(nuxt.options.rootDir), new URL(import.meta.url)]) - - if (!builderPath) { + try { + return await importModule(builder, { url: [directoryToURL(nuxt.options.rootDir), new URL(import.meta.url)] }) + } 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\``) } - return importModule(builderPath) } diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index d4d5d26947..01d035adc7 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -6,7 +6,7 @@ import { join, normalize, relative, resolve } from 'pathe' import { createDebugger, createHooks } from 'hookable' import ignore from 'ignore' 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 { PackageJson } from 'pkg-types' import { readPackageJSON } from 'pkg-types' @@ -24,6 +24,7 @@ import defu from 'defu' import { gt, satisfies } from 'semver' import { hasTTY, isCI } from 'std-env' import { genImport } from 'knitwork' +import { resolveModulePath, resolveModuleURL } from 'exsolve' import pagesModule from '../pages/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))) // Add unctx transform addBuildPlugin(UnctxTransformPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, transformerOptions: { ...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) { const mod = Array.isArray(_mod) ? _mod[0] : _mod if (typeof mod !== 'string') { continue } - const modPath = await resolvePath(resolveAlias(mod), { fallbackToOriginal: true }) - specifiedModules.add(modPath) + const modAlias = resolveAlias(mod) + 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 @@ -919,9 +926,9 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { } export async function checkDependencyVersion (name: string, nuxtVersion: string): Promise { - 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) if (version && gt(nuxtVersion, version)) { diff --git a/packages/nuxt/src/core/plugins/resolve-deep-imports.ts b/packages/nuxt/src/core/plugins/resolve-deep-imports.ts index abc281830e..01734c9c77 100644 --- a/packages/nuxt/src/core/plugins/resolve-deep-imports.ts +++ b/packages/nuxt/src/core/plugins/resolve-deep-imports.ts @@ -1,4 +1,5 @@ -import { parseNodeModulePath, resolvePath } from 'mlly' +import { parseNodeModulePath } from 'mlly' +import { resolveModulePath } from 'exsolve' import { isAbsolute, normalize } from 'pathe' import type { Plugin } from 'vite' import { directoryToURL, resolveAlias } from '@nuxt/kit' @@ -36,13 +37,24 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin { const normalisedImporter = importer.replace(/^\0?virtual:(?:nuxt:)?/, '') const dir = parseNodeModulePath(normalisedImporter).dir || pkgDir - return await this.resolve?.(normalisedId, dir, { skipSelf: true }) ?? await resolvePath(id, { - url: [dir, ...nuxt.options.modulesDir].map(d => directoryToURL(d)), + const res = await this.resolve?.(normalisedId, dir, { skipSelf: true }) + if (res !== undefined && res !== null) { + return res + } + + const path = resolveModulePath(id, { + from: [dir, ...nuxt.options.modulesDir].map(d => directoryToURL(d)), + suffixes: ['', 'index'], conditions, - }).catch(() => { + try: true, + }) + + if (!path) { logger.debug('Could not resolve id', id, importer) return null - }) + } + + return normalize(path) }, } } diff --git a/packages/nuxt/src/core/schema.ts b/packages/nuxt/src/core/schema.ts index 4a1a69eeb0..58ab52bd48 100644 --- a/packages/nuxt/src/core/schema.ts +++ b/packages/nuxt/src/core/schema.ts @@ -5,7 +5,7 @@ import { resolve } from 'pathe' import { watch } from 'chokidar' import { defu } from 'defu' 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 type { Schema, SchemaDefinition } from 'untyped' import untypedPlugin from 'untyped/babel-plugin' @@ -57,9 +57,10 @@ export default defineNuxtModule({ }) if (nuxt.options.experimental.watcher === 'parcel') { - const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(dir => directoryToURL(dir))) - if (watcherPath) { - const { subscribe } = await importModule(watcherPath) + try { + const { subscribe } = await importModule('@parcel/watcher', { + url: [nuxt.options.rootDir, ...nuxt.options.modulesDir].map(dir => directoryToURL(dir)), + }) for (const layer of nuxt.options._layers) { const subscription = await subscribe(layer.config.rootDir, onChange, { ignore: ['!nuxt.schema.*'], @@ -67,8 +68,9 @@ export default defineNuxtModule({ nuxt.hook('close', () => subscription.unsubscribe()) } 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) diff --git a/packages/nuxt/src/core/utils/types.ts b/packages/nuxt/src/core/utils/types.ts index 504962b989..6a86e99db1 100644 --- a/packages/nuxt/src/core/utils/types.ts +++ b/packages/nuxt/src/core/utils/types.ts @@ -1,11 +1,14 @@ import { resolvePackageJSON } from 'pkg-types' -import { resolvePath as _resolvePath } from 'mlly' +import { resolveModulePath } from 'exsolve' import { dirname } from 'pathe' import { directoryToURL, tryUseNuxt } from '@nuxt/kit' export async function resolveTypePath (path: string, subpath: string, searchPaths = tryUseNuxt()?.options.modulesDir) { 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) { return r.replace(/(?:\.d)?\.[mc]?[jt]s$/, '') } diff --git a/packages/nuxt/src/head/module.ts b/packages/nuxt/src/head/module.ts index 198d74e9d9..8c2165b122 100644 --- a/packages/nuxt/src/head/module.ts +++ b/packages/nuxt/src/head/module.ts @@ -1,6 +1,7 @@ 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 { resolveModulePath } from 'exsolve' import { distDir } from '../dirs' const components = ['NoScript', 'Link', 'Base', 'Title', 'Meta', 'Style', 'Head', 'Html', 'Body'] @@ -10,7 +11,7 @@ export default defineNuxtModule({ name: 'nuxt:meta', configKey: 'unhead', }, - async setup (options, nuxt) { + setup (options, nuxt) { const runtimeDir = resolve(distDir, 'head/runtime') // Transpile @unhead/vue @@ -53,7 +54,7 @@ export default defineNuxtModule({ // Opt-out feature allowing dependencies using @vueuse/head to work 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) { // backwards compatibility nuxt.options.alias['@vueuse/head'] = unheadVue diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b5e6b4d38..83049033ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -241,6 +241,9 @@ importers: destr: specifier: ^2.0.3 version: 2.0.3 + exsolve: + specifier: ^1.0.1 + version: 1.0.1 globby: specifier: ^14.1.0 version: 14.1.0 @@ -310,7 +313,7 @@ importers: version: 2.10.4(typescript@5.7.3) unbuild: 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: 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) @@ -401,6 +404,9 @@ importers: estree-walker: specifier: ^3.0.3 version: 3.0.3 + exsolve: + specifier: ^1.0.1 + version: 1.0.1 globby: specifier: ^14.1.0 version: 14.1.0 @@ -539,7 +545,7 @@ importers: version: 3.5.13 unbuild: 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: 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) @@ -684,7 +690,7 @@ importers: version: 4.34.8 unbuild: 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: specifier: 3.5.13 version: 3.5.13(typescript@5.7.3) @@ -974,7 +980,7 @@ importers: version: 4.34.8 unbuild: 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: specifier: 3.5.13 version: 3.5.13(typescript@5.7.3) @@ -1113,7 +1119,7 @@ importers: version: 2.25.9 unbuild: 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: specifier: 3.5.13 version: 3.5.13(typescript@5.7.3) @@ -2378,8 +2384,8 @@ packages: '@redocly/config@0.21.0': resolution: {integrity: sha512-JBtrrjBIURTnzb7KUIWOF46vSgpfC3rO6Mm8LjtRjtTNCLTyB+mOuU7HrTkVcvUCEBuSuzkivlTHMWT4JETz9A==} - '@redocly/openapi-core@1.31.3': - resolution: {integrity: sha512-SyE/1TwM33tgldc3k367sg2i1kqnILOJZo6J96Y/Tt1PHhJp+na637CzCuTgdyY86GTPvNw42834Ks0Lkfk3Hg==} + '@redocly/openapi-core@1.31.2': + resolution: {integrity: sha512-HScpiSuluLic9+QpsI2JWaegeDuRn3hximPBpiUpy4WdXf74Ev094kpUgjhiD3xDuP/KpVdchooAkLnzQ0X+vg==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} '@rollup/plugin-alias@5.1.1': @@ -2631,8 +2637,8 @@ packages: '@shikijs/core@1.23.1': resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==} - '@shikijs/core@3.1.0': - resolution: {integrity: sha512-1ppAOyg3F18N8Ge9DmJjGqRVswihN33rOgPovR6gUHW17Hw1L4RlRhnmVQcsacSHh0A8IO1FIgNbtTxUFwodmg==} + '@shikijs/core@3.0.0': + resolution: {integrity: sha512-gSm3JQf2J2psiUn5bWokmZwnu5N0jfBtRps4CQ1B+qrFvmZCRAkMVoaxgl9qZgAFK5KisLAS3//XaMFVytYHKw==} '@shikijs/engine-javascript@1.22.2': resolution: {integrity: sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==} @@ -2649,10 +2655,8 @@ packages: '@shikijs/transformers@1.22.2': resolution: {integrity: sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==} - '@shikijs/twoslash@3.1.0': - resolution: {integrity: sha512-cEaS6Nw1IhcJRc0RxJWIaZLXq0A5d9aJ9LoRfO4+y1L1wqC/+YCqrMEZqxkdjep3usCbZRae13fcXMd4pz8fHQ==} - peerDependencies: - typescript: 5.7.3 + '@shikijs/twoslash@3.0.0': + resolution: {integrity: sha512-Il7XsIzbBLGV67i4yCoBDFvlMOuky1DpMyHgBjNjBu7gEw/DcmpoEEs1MwVH6Lk6fX4wXDhMQ+pDL2EwqzWqdQ==} '@shikijs/types@1.22.2': resolution: {integrity: sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==} @@ -2660,8 +2664,8 @@ packages: '@shikijs/types@1.23.1': resolution: {integrity: sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==} - '@shikijs/types@3.1.0': - resolution: {integrity: sha512-F8e7Fy4ihtcNpJG572BZZC1ErYrBrzJ5Cbc9Zi3REgWry43gIvjJ9lFAoUnuy7Bvy4IFz7grUSxL5edfrrjFEA==} + '@shikijs/types@3.0.0': + resolution: {integrity: sha512-kh/xgZHxI6m9trVvPw+C47jyVHx190r0F5gkF+VO5vYB54UtcoPJe66dzZmK7GbJbzmtGEGbOwct/jsoPjjUqg==} '@shikijs/vitepress-twoslash@1.23.1': resolution: {integrity: sha512-L67HkzDkbECjYdWxQA9BuKAIB0c7eaa+7sD6dZUQ6/cdJGiWvaPLYMRwMWZQ4ToRsz1X6MQmOKQp6Xb6FEc3Bg==} @@ -7180,9 +7184,6 @@ packages: twoslash-protocol@0.2.12: resolution: {integrity: sha512-5qZLXVYfZ9ABdjqbvPc4RWMr7PrpPaaDSeaYY55vl/w1j6H6kzsWK/urAEIXlzYlyrFmyz1UbwIt+AA0ck+wbg==} - twoslash-protocol@0.3.1: - resolution: {integrity: sha512-BMePTL9OkuNISSyyMclBBhV2s9++DiOCyhhCoV5Kaht6eaWLwVjCCUJHY33eZJPsyKeZYS8Wzz0h+XI01VohVw==} - twoslash-vue@0.2.12: resolution: {integrity: sha512-kxH60DLn2QBcN2wjqxgMDkyRgmPXsytv7fJIlsyFMDPSkm1/lMrI/UMrNAshNaRHcI+hv8x3h/WBgcvlb2RNAQ==} peerDependencies: @@ -7193,11 +7194,6 @@ packages: peerDependencies: typescript: 5.7.3 - twoslash@0.3.1: - resolution: {integrity: sha512-OGqMTGvqXTcb92YQdwGfEdK0nZJA64Aj/ChLOelbl3TfYch2IoBST0Yx4C0LQ7Lzyqm9RpgcpgDxeXQIz4p2Kg==} - peerDependencies: - typescript: 5.7.3 - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -7228,6 +7224,15 @@ packages: ultrahtml@1.5.3: 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: resolution: {integrity: sha512-DPFttsiADnHRb/K+yJ9r9jdn6JyXlsmdT0S12VFC14DFSJD+cxBnHq+v0INmqqPVPxOoUjvJFYUVIb02rWnVeA==} hasBin: true @@ -9132,7 +9137,7 @@ snapshots: '@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: '@redocly/ajv': 8.11.2 '@redocly/config': 0.21.0 @@ -9344,9 +9349,9 @@ snapshots: '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 - '@shikijs/core@3.1.0': + '@shikijs/core@3.0.0': dependencies: - '@shikijs/types': 3.1.0 + '@shikijs/types': 3.0.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 @@ -9377,14 +9382,14 @@ snapshots: dependencies: shiki: 1.22.2 - '@shikijs/twoslash@3.1.0(typescript@5.7.3)': + '@shikijs/twoslash@3.0.0(typescript@5.7.3)': dependencies: - '@shikijs/core': 3.1.0 - '@shikijs/types': 3.1.0 - twoslash: 0.3.1(typescript@5.7.3) - typescript: 5.7.3 + '@shikijs/core': 3.0.0 + '@shikijs/types': 3.0.0 + twoslash: 0.2.12(typescript@5.7.3) transitivePeerDependencies: - supports-color + - typescript '@shikijs/types@1.22.2': dependencies: @@ -9396,14 +9401,14 @@ snapshots: '@shikijs/vscode-textmate': 9.3.1 '@types/hast': 3.0.4 - '@shikijs/types@3.1.0': + '@shikijs/types@3.0.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 '@shikijs/vitepress-twoslash@1.23.1(@nuxt/kit@packages+kit)(typescript@5.7.3)': 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)) mdast-util-from-markdown: 2.0.2 mdast-util-gfm: 3.0.0 @@ -13497,7 +13502,7 @@ snapshots: openapi-typescript@7.6.1(typescript@5.7.3): 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 change-case: 5.4.4 parse-json: 8.1.0 @@ -14883,8 +14888,6 @@ snapshots: twoslash-protocol@0.2.12: {} - twoslash-protocol@0.3.1: {} - twoslash-vue@0.2.12(typescript@5.7.3): dependencies: '@vue/language-core': 2.1.10(typescript@5.7.3) @@ -14902,14 +14905,6 @@ snapshots: transitivePeerDependencies: - 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: dependencies: prelude-ls: 1.2.1 @@ -14928,6 +14923,39 @@ snapshots: 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)): dependencies: '@rollup/plugin-alias': 5.1.1(rollup@4.34.8) diff --git a/test/fixtures/basic/modules/subpath/index.ts b/test/fixtures/basic/custom-modules/subpath/index.ts similarity index 100% rename from test/fixtures/basic/modules/subpath/index.ts rename to test/fixtures/basic/custom-modules/subpath/index.ts diff --git a/test/fixtures/basic/modules/subpath/module.ts b/test/fixtures/basic/custom-modules/subpath/module.ts similarity index 100% rename from test/fixtures/basic/modules/subpath/module.ts rename to test/fixtures/basic/custom-modules/subpath/module.ts diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index 472baa86ea..ebb34b5256 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -35,7 +35,7 @@ export default defineNuxtConfig({ } }) }, - '~/modules/subpath', + '~/custom-modules/subpath', './modules/test', '~/modules/example', function (_, nuxt) {