diff --git a/packages/kit/src/internal/cjs.ts b/packages/kit/src/internal/cjs.ts index 7e30acfec7..b2c01e8c69 100644 --- a/packages/kit/src/internal/cjs.ts +++ b/packages/kit/src/internal/cjs.ts @@ -61,7 +61,7 @@ function getRequireCacheItem (id: string) { } } -export function getModulePaths (paths?: string[] | string) { +export function getNodeModulesPaths (paths?: string[] | string) { return ([] as Array).concat( global.__NUXT_PREPATHS__, paths || [], @@ -73,7 +73,7 @@ export function getModulePaths (paths?: string[] | string) { /** @deprecated Do not use CJS utils */ export function resolveModule (id: string, opts: ResolveModuleOptions = {}) { return normalize(_require.resolve(id, { - paths: getModulePaths(opts.paths), + paths: getNodeModulesPaths(opts.paths), })) } diff --git a/packages/kit/src/internal/template.ts b/packages/kit/src/internal/template.ts index 5b40a2a214..343393e5ec 100644 --- a/packages/kit/src/internal/template.ts +++ b/packages/kit/src/internal/template.ts @@ -32,10 +32,11 @@ const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"\{(.+)\ /** @deprecated */ const importSources = (sources: string | string[], { lazy = false } = {}) => { return toArray(sources).map((src) => { + const safeVariableName = genSafeVariableName(src) if (lazy) { - return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}` + return `const ${safeVariableName} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}` } - return genImport(src, genSafeVariableName(src)) + return genImport(src, safeVariableName) }).join('\n') } diff --git a/packages/kit/src/loader/config.ts b/packages/kit/src/loader/config.ts index b2c4d1b883..8e2c1354a9 100644 --- a/packages/kit/src/loader/config.ts +++ b/packages/kit/src/loader/config.ts @@ -12,7 +12,12 @@ export interface LoadNuxtConfigOptions extends Omit layerSchemaKeys.includes(key))) +const layerSchema = Object.create(null) +for (const key of layerSchemaKeys) { + if (key in NuxtConfigSchema) { + layerSchema[key] = NuxtConfigSchema[key] + } +} export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise { // Automatically detect and import layers from `~~/layers/` directory diff --git a/packages/kit/src/module/compatibility.ts b/packages/kit/src/module/compatibility.ts index 446e7e3fce..5bccbf8654 100644 --- a/packages/kit/src/module/compatibility.ts +++ b/packages/kit/src/module/compatibility.ts @@ -51,11 +51,10 @@ export async function getNuxtModuleVersion (module: string | NuxtModule, nuxt: N // need a name from here if (!moduleMeta.name) { return false } // maybe the version got attached within the installed module instance? - const version = nuxt.options._installedModules - // @ts-expect-error _installedModules is not typed - .filter(m => m.meta.name === moduleMeta.name).map(m => m.meta.version)?.[0] - if (version) { - return version + for (const m of nuxt.options._installedModules) { + if (m.meta.name === moduleMeta.name && m.meta.version) { + return m.meta.version + } } // it's possible that the module will be installed, it just hasn't been done yet, preemptively load the instance if (hasNuxtModule(moduleMeta.name)) { diff --git a/packages/kit/src/pages.ts b/packages/kit/src/pages.ts index a5f7fc1d3e..04c7592a55 100644 --- a/packages/kit/src/pages.ts +++ b/packages/kit/src/pages.ts @@ -51,11 +51,12 @@ export function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], op for (const middleware of middlewares) { const find = app.middleware.findIndex(item => item.name === middleware.name) if (find >= 0) { - if (app.middleware[find].path === middleware.path) { continue } + const foundPath = app.middleware[find].path + if (foundPath === middleware.path) { continue } if (options.override === true) { app.middleware[find] = { ...middleware } } else { - logger.warn(`'${middleware.name}' middleware already exists at '${app.middleware[find].path}'. You can set \`override: true\` to replace it.`) + logger.warn(`'${middleware.name}' middleware already exists at '${foundPath}'. You can set \`override: true\` to replace it.`) } } else { app.middleware.push({ ...middleware }) diff --git a/packages/kit/src/resolve.ts b/packages/kit/src/resolve.ts index 392dec86d8..b170210efe 100644 --- a/packages/kit/src/resolve.ts +++ b/packages/kit/src/resolve.ts @@ -168,8 +168,8 @@ export function createResolver (base: string | URL): Resolver { } } -export async function resolveNuxtModule (base: string, paths: string[]) { - const resolved = [] +export async function resolveNuxtModule (base: string, paths: string[]): Promise { + const resolved: string[] = [] const resolver = createResolver(base) for (const path of paths) { @@ -209,6 +209,12 @@ function existsInVFS (path: string, nuxt = tryUseNuxt()) { } export async function resolveFiles (path: string, pattern: string | string[], opts: { followSymbolicLinks?: boolean } = {}) { - const files = await globby(pattern, { cwd: path, followSymbolicLinks: opts.followSymbolicLinks ?? true }) - return files.map(p => resolve(path, p)).filter(p => !isIgnored(p)).sort() + const files: string[] = [] + for (const file of await globby(pattern, { cwd: path, followSymbolicLinks: opts.followSymbolicLinks ?? true })) { + const p = resolve(path, file) + if (!isIgnored(p)) { + files.push(p) + } + } + return files.sort() } diff --git a/packages/kit/src/template.ts b/packages/kit/src/template.ts index 1816ccf536..8e729c2f20 100644 --- a/packages/kit/src/template.ts +++ b/packages/kit/src/template.ts @@ -11,7 +11,7 @@ import { readPackageJSON } from 'pkg-types' import { tryResolveModule } from './internal/esm' import { getDirectory } from './module/install' import { tryUseNuxt, useNuxt } from './context' -import { getModulePaths } from './internal/cjs' +import { getNodeModulesPaths } from './internal/cjs' import { resolveNuxtModule } from './resolve' /** @@ -113,18 +113,55 @@ export async function updateTemplates (options?: { filter?: (template: ResolvedN } export async function _generateTypes (nuxt: Nuxt) { - const nodeModulePaths = getModulePaths(nuxt.options.modulesDir) - const rootDirWithSlash = withTrailingSlash(nuxt.options.rootDir) + const relativeRootDir = relativeWithDot(nuxt.options.buildDir, nuxt.options.rootDir) - const modulePaths = await resolveNuxtModule(rootDirWithSlash, - nuxt.options._installedModules - .filter(m => m.entryPath) - .map(m => getDirectory(m.entryPath!)), - ) + const include = new Set([ + './nuxt.d.ts', + join(relativeRootDir, '.config/nuxt.*'), + join(relativeRootDir, '**/*'), + ]) + + if (nuxt.options.srcDir !== nuxt.options.rootDir) { + include.add(join(relative(nuxt.options.buildDir, nuxt.options.srcDir), '**/*')) + } + + if (nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir) { + include.add(join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), '**/*')) + } + + for (const layer of nuxt.options._layers) { + const srcOrCwd = layer.config.srcDir ?? layer.cwd + if (!srcOrCwd.startsWith(rootDirWithSlash) || srcOrCwd.includes('node_modules')) { + include.add(join(relative(nuxt.options.buildDir, srcOrCwd), '**/*')) + } + } + + const exclude = new Set([ + // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 + relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')), + ]) + + for (const dir of nuxt.options.modulesDir) { + exclude.add(relativeWithDot(nuxt.options.buildDir, dir)) + } + + const moduleEntryPaths: string[] = [] + for (const m of nuxt.options._installedModules) { + if (m.entryPath) { + moduleEntryPaths.push(getDirectory(m.entryPath)) + } + } + + const modulePaths = await resolveNuxtModule(rootDirWithSlash, moduleEntryPaths) + + for (const path of modulePaths) { + const relative = relativeWithDot(nuxt.options.buildDir, path) + include.add(join(relative, 'runtime')) + exclude.add(join(relative, 'runtime/server')) + } const isV4 = nuxt.options.future?.compatibilityVersion === 4 - const hasTypescriptVersionWithModulePreserve = await readPackageJSON('typescript', { url: nuxt.options.modulesDir }) .then(r => r?.version && gte(r.version, '5.4.0')) .catch(() => isV4) @@ -168,23 +205,8 @@ export async function _generateTypes (nuxt: Nuxt) { noImplicitThis: true, /* enabled with `strict` */ allowSyntheticDefaultImports: true, }, - include: [ - './nuxt.d.ts', - join(relativeWithDot(nuxt.options.buildDir, nuxt.options.rootDir), '.config/nuxt.*'), - join(relativeWithDot(nuxt.options.buildDir, nuxt.options.rootDir), '**/*'), - ...nuxt.options.srcDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.srcDir), '**/*')] : [], - ...nuxt.options._layers.map(layer => layer.config.srcDir ?? layer.cwd) - .filter(srcOrCwd => !srcOrCwd.startsWith(rootDirWithSlash) || srcOrCwd.includes('node_modules')) - .map(srcOrCwd => join(relative(nuxt.options.buildDir, srcOrCwd), '**/*')), - ...nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), '**/*')] : [], - ...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime')), - ], - exclude: [ - ...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)), - ...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server')), - // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 - relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')), - ], + include: [...include], + exclude: [...exclude], } satisfies TSConfig) const aliases: Record = { @@ -195,7 +217,9 @@ export async function _generateTypes (nuxt: Nuxt) { // Exclude bridge alias types to support Volar const excludedAlias = [/^@vue\/.*$/] - const basePath = tsConfig.compilerOptions!.baseUrl ? resolve(nuxt.options.buildDir, tsConfig.compilerOptions!.baseUrl) : nuxt.options.buildDir + const basePath = tsConfig.compilerOptions!.baseUrl + ? resolve(nuxt.options.buildDir, tsConfig.compilerOptions!.baseUrl) + : nuxt.options.buildDir tsConfig.compilerOptions = tsConfig.compilerOptions || {} tsConfig.include = tsConfig.include || [] @@ -237,12 +261,13 @@ export async function _generateTypes (nuxt: Nuxt) { } } - const references: TSReference[] = await Promise.all([ - ...nuxt.options.modules, - ...nuxt.options._modules, - ] - .filter(f => typeof f === 'string') - .map(async id => ({ types: (await readPackageJSON(id, { url: nodeModulePaths }).catch(() => null))?.name || id }))) + const references: TSReference[] = [] + await Promise.all([...nuxt.options.modules, ...nuxt.options._modules].map(async (id) => { + if (typeof id !== 'string') { return } + + const pkg = await readPackageJSON(id, { url: getNodeModulesPaths(nuxt.options.modulesDir) }).catch(() => null) + references.push(({ types: pkg?.name || id })) + })) const declarations: string[] = [] @@ -302,7 +327,11 @@ export async function writeTypes (nuxt: Nuxt) { } function renderAttrs (obj: Record) { - return Object.entries(obj).map(e => renderAttr(e[0], e[1])).join(' ') + const attrs: string[] = [] + for (const key in obj) { + attrs.push(renderAttr(key, obj[key])) + } + return attrs.join(' ') } function renderAttr (key: string, value: string) { diff --git a/packages/kit/test/generate-types.spec.ts b/packages/kit/test/generate-types.spec.ts index 7ac10ba8d1..b5bcc9a6bb 100644 --- a/packages/kit/test/generate-types.spec.ts +++ b/packages/kit/test/generate-types.spec.ts @@ -53,12 +53,12 @@ describe('tsConfig generation', () => { })) expect(tsConfig.exclude).toMatchInlineSnapshot(` [ + "../dist", "../modules/test/node_modules", "../modules/node_modules", "../node_modules/@some/module/node_modules", "../node_modules", "../../node_modules", - "../dist", ] `) })