添加插件、组件等
了解如何从您的模块注入插件、组件、组合式函数和服务器路由。
以下是模块作者使用的一些常见模式。
修改 Nuxt 配置
模块可以读取和更改 Nuxt 配置。这是一个启用实验性功能的模块示例。
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// 如果 `experimental` 对象尚不存在,我们创建它
nuxt.options.experimental ||= {}
nuxt.options.experimental.componentIslands = true
},
})
当您需要处理更复杂的配置更改时,您应该考虑使用 defu。
将选项暴露给运行时
由于模块不是应用程序运行时的一部分,它们的选项也不是。然而,在许多情况下,您可能需要在运行时代码中访问某些模块选项。我们建议使用 Nuxt 的 runtimeConfig 来暴露所需的配置。
import { defineNuxtModule } from '@nuxt/kit'
import { defu } from 'defu'
export default defineNuxtModule({
setup (options, nuxt) {
nuxt.options.runtimeConfig.public.myModule = defu(nuxt.options.runtimeConfig.public.myModule, {
foo: options.foo,
})
},
})
请注意,我们使用 defu 来扩展用户提供的公共运行时配置,而不是覆盖它。
然后,您可以在插件、组件、应用程序中像访问任何其他运行时配置一样访问您的模块选项:
import { useRuntimeConfig } from '@nuxt/kit'
const options = useRuntimeConfig().public.myModule
注意不要在公共运行时配置中暴露任何敏感的模块配置,例如私有 API 密钥,因为它们最终会出现在公共构建中。
添加插件
插件是模块添加运行时逻辑的常见方式。您可以使用 addPlugin 实用程序从您的模块注册它们。
import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
// 创建解析器以解析相对路径
const resolver = createResolver(import.meta.url)
addPlugin(resolver.resolve('./runtime/plugin'))
},
})
添加组件
如果您的模块应该提供 Vue 组件,您可以使用 addComponent 实用程序将它们添加为自动导入,供 Nuxt 解析。
import { addComponent, createResolver, defineNuxtModule, useRuntimeConfig } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
// 从运行时目录
addComponent({
name: 'MySuperComponent', // 要在 vue 模板中使用的组件名称
export: 'MySuperComponent', // (可选) 如果组件是命名(而不是默认)导出
filePath: resolver.resolve('runtime/app/components/MySuperComponent.vue'),
})
// 从库
addComponent({
name: 'MyAwesomeComponent', // 要在 vue 模板中使用的组件名称
export: 'MyAwesomeComponent', // (可选) 如果组件是命名(而不是默认)导出
filePath: '@vue/awesome-components',
})
},
})
或者,您可以使用 addComponentsDir 添加整个目录。
import { addComponentsDir, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addComponentsDir({
path: resolver.resolve('runtime/app/components'),
})
},
})
强烈建议为您的导出添加前缀,以避免与用户代码或其他模块发生冲突。可以传递多个条目作为数组:或者,您可以使用
请注意,通常放在您的
app/ 文件夹中的所有组件、页面、组合式函数和其他文件都需要在 runtime/app/ 中。这意味着它们可以正确地进行类型检查。添加组合式函数
如果您的模块应该提供组合式函数,您可以使用addImports 实用程序将它们添加为自动导入,供 Nuxt 解析。import { addImports, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addImports({
name: 'useComposable', // 要使用的组合式函数名称
as: 'useMyComposable', // 可选别名,将可供消费应用程序使用
from: resolver.resolve('runtime/app/composables/useComposable'), // 组合式函数的路径
})
},
})
import { addImports, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addImports([
{ name: 'useFirstComposable', from: resolver.resolve('runtime/composables/useFirstComposable') },
{ name: 'useSecondComposable', from: resolver.resolve('runtime/composables/useSecondComposable') },
])
},
})
addImportsDir 添加整个目录。import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addImportsDir(resolver.resolve('runtime/composables'))
},
})
强烈建议为您的导出添加前缀,以避免与用户代码或其他模块发生冲突。
请注意,通常放在您的
app/ 文件夹中的所有组件、页面、组合式函数和其他文件都需要在 runtime/app/ 中。这意味着它们可以正确地进行类型检查。添加键控函数
有时,您可能需要在服务器和客户端之间保持状态一致性。示例包括 Nuxt 内置的 useState 或 useAsyncData 组合式函数。Nuxt 提供了一种注册此类函数以进行自动键注入的方法。
当注册一个函数时,如果使用少于指定数量的参数调用该函数,Nuxt 的编译器会自动注入一个唯一键作为附加参数。该键在服务器端渲染和客户端水合之间保持稳定。
注入的键是从文件路径和调用位置派生的哈希值。
使用 keyedComposables 选项注册您的函数:
import { createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.options.optimization.keyedComposables.push({
name: 'useMyState',
source: resolver.resolve('./runtime/composables/state'),
argumentLength: 2,
})
},
})
keyedComposables 配置接受具有以下属性的对象数组:
| 属性 | 类型 | 描述 |
|---|---|---|
name | string | 函数名称。对于默认导出使用 'default'(可调用名称将从文件名以驼峰命名法派生)。 |
source | string | 定义函数的文件的已解析路径。支持 Nuxt 别名(~、@ 等)。 |
argumentLength | number | 函数接受的最大参数数。当使用较少的参数调用时,会注入一个唯一键。 |
例如,使用 argumentLength: 2:
useMyState() // useMyState('$HJiaryoL2y')
useMyState('myKey') // useMyState('myKey', '$HJiaryoL2y')
useMyState('a', 'b') // 不转换(已经有 2 个参数)
键注入插件会验证每个函数调用的确切已解析导入源。它不遵循桶导出。函数必须从
source 属性中指定的确切源文件导出。// ✅ 有效 - 直接导入与配置的源匹配
import { useMyState } from 'my-module/runtime/composables/state'
// ❌ 无效 - 通过桶文件重新导出
import { useMyState } from 'my-module/runtime/composables' // index.ts 桶
函数调用必须是静态可分析的。编译器无法为动态或间接的函数调用注入键。
import { useMyState } from 'my-module/runtime/composables/state'
import * as composables from 'my-module/runtime/composables/state'
// ✅ 有效 - 直接函数调用
useMyState()
// ✅ 有效 - 在命名空间导入上调用
composables.useMyState()
// ❌ 无效 - 动态属性访问
const name = 'useMyState'
composables[name]()
// ❌ 无效 - 重新赋值给变量
const myFn = useMyState
myFn()
// ❌ 无效 - 作为回调传递
someFunction(useMyState)
// ❌ 无效 - 在嵌套作用域中解构并重命名
function setup () {
const { useMyState: localState } = composables
localState() // 不转换
}
// ...
添加服务器路由
import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addServerHandler({
route: '/api/_my-module/hello',
handler: resolver.resolve('./runtime/server/api/hello/index.get'),
})
},
})
您还可以添加动态服务器路由:
import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
addServerHandler({
route: '/api/_my-module/hello/:name',
handler: resolver.resolve('./runtime/server/api/hello/[name].get'),
})
// 或使用捕获所有路由
addServerHandler({
route: '/api/_my-module/files/**:path',
handler: resolver.resolve('./runtime/server/api/files/[...path].get'),
})
},
})
强烈建议为您的服务器路由添加前缀,以避免与用户定义的路由发生冲突。像 还有一个更高级的示例,通过 Nitro 的
/api/auth、/api/login 或 /api/user 这样的常见路径可能已被应用程序使用。在为模块创建组合式函数时,请确保给它们加前缀以避免与其他包发生冲突。
添加其他资源
如果您的模块应该提供其他类型的资源,也可以注入它们。这是一个简单的模块示例,通过 Nuxt 的css 数组注入样式表。import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.options.css.push(resolver.resolve('./runtime/style.css'))
},
})
publicAssets 选项暴露资源文件夹:import { createResolver, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup (options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.hook('nitro:config', (nitroConfig) => {
nitroConfig.publicAssets ||= []
nitroConfig.publicAssets.push({
dir: resolver.resolve('./runtime/public'),
maxAge: 60 * 60 * 24 * 365, // 1 年
})
})
},
})
使用其他模块
如果您的模块依赖于其他模块,您可以使用moduleDependencies 选项指定它们。这提供了一种更强大的方式来处理模块依赖关系,包括版本约束和配置合并:import { createResolver, defineNuxtModule } from '@nuxt/kit'
const resolver = createResolver(import.meta.url)
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'my-module',
},
moduleDependencies: {
'@nuxtjs/tailwindcss': {
// 您可以为模块指定版本约束
version: '>=6',
// 任何应该覆盖 `nuxt.options` 的配置
overrides: {
exposeConfig: true,
},
// 任何应该设置的配置。它将覆盖模块默认值但
// 不会覆盖在 `nuxt.options` 中设置的任何配置
defaults: {
config: {
darkMode: 'class',
content: {
files: [
resolver.resolve('./runtime/components/**/*.{vue,mjs,ts}'),
resolver.resolve('./runtime/*.{mjs,js,ts}'),
],
},
},
},
},
},
setup (options, nuxt) {
// 我们可以注入我们的 CSS 文件,其中包括 Tailwind 的指令
nuxt.options.css.push(resolver.resolve('./runtime/assets/styles.css'))
},
})
moduleDependencies 选项替换了已弃用的 installModule 函数,并确保正确的设置顺序和配置合并。