feat(kit): allow direct function in defineNuxtModule (#20763)

This commit is contained in:
Inesh Bose 2023-06-16 15:47:38 +01:00 committed by GitHub
parent 7e74e7c2fc
commit c73bed8c6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 21 deletions

View File

@ -127,7 +127,19 @@ export default function (inlineOptions, nuxt) {
} }
``` ```
Outside of short inline modules defined in `nuxt.config.ts`, **we do not recommend** using this low-level function definition. Instead, to define a module, **we recommend** using the higher-level `defineNuxtModule` helper provided by [Nuxt Kit](/docs/api/advanced/kit). You can get type-hint support for this function using the higher-level `defineNuxtModule` helper provided by [Nuxt Kit](/docs/api/advanced/kit).
```js
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule((options, nuxt) => {
nuxt.hook('pages:extend', pages => {
console.log(`Discovered ${pages.length} pages`)
})
})
```
However, **we do not recommend** using this low-level function definition. Instead, to define a module, **we recommend** using the object-syntax with `meta` property to identify your module, especially when publishing to npm.
This helper makes writing Nuxt Module more straightforward by implementing many common patterns seen in modules, guaranteeing future compatibility, and improving your module author developer experience and the one of your module users. This helper makes writing Nuxt Module more straightforward by implementing many common patterns seen in modules, guaranteeing future compatibility, and improving your module author developer experience and the one of your module users.

View File

@ -13,20 +13,22 @@ import { compileTemplate, templateUtils } from '../internal/template'
* Define a Nuxt module, automatically merging defaults with user provided options, installing * Define a Nuxt module, automatically merging defaults with user provided options, installing
* any hooks that are provided, and calling an optional setup function for full control. * any hooks that are provided, and calling an optional setup function for full control.
*/ */
export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: ModuleDefinition<OptionsT>): NuxtModule<OptionsT> { export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: ModuleDefinition<OptionsT> | NuxtModule<OptionsT>): NuxtModule<OptionsT> {
if (typeof definition === 'function') { return defineNuxtModule({ setup: definition }) }
// Normalize definition and meta // Normalize definition and meta
if (!definition.meta) { definition.meta = {} } const module: ModuleDefinition<OptionsT> & Required<Pick<ModuleDefinition<OptionsT>, 'meta'>> = defu(definition, { meta: {} })
if (definition.meta.configKey === undefined) { if (module.meta.configKey === undefined) {
definition.meta.configKey = definition.meta.name module.meta.configKey = module.meta.name
} }
// Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema // Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema
async function getOptions (inlineOptions?: OptionsT, nuxt: Nuxt = useNuxt()) { async function getOptions (inlineOptions?: OptionsT, nuxt: Nuxt = useNuxt()) {
const configKey = definition.meta!.configKey || definition.meta!.name! const configKey = module.meta.configKey || module.meta.name!
const _defaults = definition.defaults instanceof Function ? definition.defaults(nuxt) : definition.defaults const _defaults = module.defaults instanceof Function ? module.defaults(nuxt) : module.defaults
let _options = defu(inlineOptions, nuxt.options[configKey as keyof NuxtOptions], _defaults) as OptionsT let _options = defu(inlineOptions, nuxt.options[configKey as keyof NuxtOptions], _defaults) as OptionsT
if (definition.schema) { if (module.schema) {
_options = await applyDefaults(definition.schema, _options) as OptionsT _options = await applyDefaults(module.schema, _options) as OptionsT
} }
return Promise.resolve(_options) return Promise.resolve(_options)
} }
@ -38,7 +40,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
} }
// Avoid duplicate installs // Avoid duplicate installs
const uniqueKey = definition.meta!.name || definition.meta!.configKey const uniqueKey = module.meta.name || module.meta.configKey
if (uniqueKey) { if (uniqueKey) {
nuxt.options._requiredModules = nuxt.options._requiredModules || {} nuxt.options._requiredModules = nuxt.options._requiredModules || {}
if (nuxt.options._requiredModules[uniqueKey]) { if (nuxt.options._requiredModules[uniqueKey]) {
@ -48,10 +50,10 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
} }
// Check compatibility constraints // Check compatibility constraints
if (definition.meta!.compatibility) { if (module.meta.compatibility) {
const issues = await checkNuxtCompatibility(definition.meta!.compatibility, nuxt) const issues = await checkNuxtCompatibility(module.meta.compatibility, nuxt)
if (issues.length) { if (issues.length) {
logger.warn(`Module \`${definition.meta!.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`) logger.warn(`Module \`${module.meta.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`)
return return
} }
} }
@ -63,14 +65,14 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
const _options = await getOptions(inlineOptions, nuxt) const _options = await getOptions(inlineOptions, nuxt)
// Register hooks // Register hooks
if (definition.hooks) { if (module.hooks) {
nuxt.hooks.addHooks(definition.hooks) nuxt.hooks.addHooks(module.hooks)
} }
// Call setup // Call setup
const key = `nuxt:module:${uniqueKey || (Math.round(Math.random() * 10000))}` const key = `nuxt:module:${uniqueKey || (Math.round(Math.random() * 10000))}`
const mark = performance.mark(key) const mark = performance.mark(key)
const res = await definition.setup?.call(null as any, _options, nuxt) ?? {} const res = await module.setup?.call(null as any, _options, nuxt) ?? {}
const perf = performance.measure(key, mark?.name) // TODO: remove when Node 14 reaches EOL const perf = performance.measure(key, mark?.name) // TODO: remove when Node 14 reaches EOL
const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL
@ -93,7 +95,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
} }
// Define getters for options and meta // Define getters for options and meta
normalizedModule.getMeta = () => Promise.resolve(definition.meta) normalizedModule.getMeta = () => Promise.resolve(module.meta)
normalizedModule.getOptions = getOptions normalizedModule.getOptions = getOptions
return normalizedModule as NuxtModule<OptionsT> return normalizedModule as NuxtModule<OptionsT>

View File

@ -0,0 +1,8 @@
import { defineNuxtModule } from 'nuxt/kit'
export default defineNuxtModule(
function (_, nuxt) {
nuxt.options.optimization.treeShake.composables.server[nuxt.options.rootDir] = ['useClientOnlyComposable', 'setTitleToPink']
nuxt.options.optimization.treeShake.composables.client[nuxt.options.rootDir] = ['useServerOnlyComposable']
}
)

View File

@ -117,10 +117,6 @@ export default defineNuxtConfig({
internalParent!.children = newPages internalParent!.children = newPages
}) })
}, },
function (_, nuxt) {
nuxt.options.optimization.treeShake.composables.server[nuxt.options.rootDir] = ['useClientOnlyComposable', 'setTitleToPink']
nuxt.options.optimization.treeShake.composables.client[nuxt.options.rootDir] = ['useServerOnlyComposable']
},
// To test falsy module values // To test falsy module values
undefined undefined
], ],