feat(kit): support typed module options in installModule (#26744)

This commit is contained in:
Inesh Bose 2024-06-10 09:54:40 +01:00 committed by GitHub
parent ad82474894
commit 0d84300218
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 10 deletions

View File

@ -1,5 +1,5 @@
import { existsSync, promises as fsp, lstatSync } from 'node:fs'
import type { ModuleMeta, Nuxt, NuxtModule } from '@nuxt/schema'
import type { ModuleMeta, Nuxt, NuxtConfig, NuxtModule } from '@nuxt/schema'
import { dirname, isAbsolute, join, resolve } from 'pathe'
import { defu } from 'defu'
import { isNuxt2 } from '../compatibility'
@ -12,7 +12,10 @@ import { logger } from '../logger'
const NODE_MODULES_RE = /[/\\]node_modules[/\\]/
/** Installs a module on a Nuxt instance. */
export async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt: Nuxt = useNuxt()) {
export async function installModule<
T extends string | NuxtModule,
Config extends Extract<NonNullable<NuxtConfig['modules']>[number], [T, any]>,
> (moduleToInstall: T, inlineOptions?: [Config] extends [never] ? any : Config[1], nuxt: Nuxt = useNuxt()) {
const { nuxtModule, buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleToInstall, nuxt)
const localLayerModuleDirs = new Set<string>()
@ -43,10 +46,16 @@ export async function installModule (moduleToInstall: string | NuxtModule, inlin
}
nuxt.options._installedModules = nuxt.options._installedModules || []
const entryPath = typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined
if (typeof moduleToInstall === 'string' && entryPath !== moduleToInstall) {
buildTimeModuleMeta.rawPath = moduleToInstall
}
nuxt.options._installedModules.push({
meta: defu(await nuxtModule.getMeta?.(), buildTimeModuleMeta),
timings: res.timings,
entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined,
entryPath,
})
}

View File

@ -156,21 +156,29 @@ export const schemaTemplate: NuxtTemplate = {
const relativeRoot = relative(resolve(nuxt.options.buildDir, 'types'), nuxt.options.rootDir)
const getImportName = (name: string) => (name[0] === '.' ? './' + join(relativeRoot, name) : name).replace(/\.\w+$/, '')
const modules = moduleInfo.map(meta => [genString(meta.configKey), getImportName(meta.importName)])
const modules = moduleInfo.map(meta => [genString(meta.configKey), getImportName(meta.importName), meta])
const privateRuntimeConfig = Object.create(null)
for (const key in nuxt.options.runtimeConfig) {
if (key !== 'public') {
privateRuntimeConfig[key] = nuxt.options.runtimeConfig[key]
}
}
return [
'import { NuxtModule, RuntimeConfig } from \'nuxt/schema\'',
'declare module \'nuxt/schema\' {',
' interface NuxtConfig {',
const moduleOptionsInterface = [
...modules.map(([configKey, importName]) =>
` [${configKey}]?: typeof ${genDynamicImport(importName, { wrapper: false })}.default extends NuxtModule<infer O> ? Partial<O> : Record<string, any>`,
),
modules.length > 0 ? ` modules?: (undefined | null | false | NuxtModule | string | [NuxtModule | string, Record<string, any>] | ${modules.map(([configKey, importName]) => `[${genString(importName)}, Exclude<NuxtConfig[${configKey}], boolean>]`).join(' | ')})[],` : '',
modules.length > 0 ? ` modules?: (undefined | null | false | NuxtModule | string | [NuxtModule | string, Record<string, any>] | ${modules.map(([configKey, importName, meta]) => `[${genString(meta?.rawPath || importName)}, Exclude<NuxtConfig[${configKey}], boolean>]`).join(' | ')})[],` : '',
]
return [
'import { NuxtModule, RuntimeConfig } from \'@nuxt/schema\'',
'declare module \'@nuxt/schema\' {',
' interface NuxtConfig {',
moduleOptionsInterface,
' }',
'}',
'declare module \'nuxt/schema\' {',
' interface NuxtConfig {',
moduleOptionsInterface,
' }',
generateTypes(await resolveSchema(privateRuntimeConfig as Record<string, JSValue>),
{

View File

@ -1,4 +1,4 @@
import { addTypeTemplate } from 'nuxt/kit'
import { addTypeTemplate, installModule } from 'nuxt/kit'
export default defineNuxtConfig({
experimental: {
@ -54,6 +54,15 @@ export default defineNuxtConfig({
filename: 'test.d.ts',
getContents: () => 'declare type Fromage = "cheese"',
})
function _test () {
installModule('~/modules/example', {
typeTest (val) {
// @ts-expect-error module type defines val as boolean
const b: string = val
return !!b
},
})
}
},
'./modules/test',
[