Nuxt Kit
为什么需要 Nuxt Kit?
模块开发需要操作 Nuxt 内部 API(添加插件、注册组件、修改配置等),直接操作这些 API 容易出错且可能因版本升级而失效。Nuxt Kit 封装了稳定的公共 API,让你编写的模块跨版本兼容。
什么时候需要 Nuxt Kit?
只有开发 Nuxt 模块时才需要。日常项目开发(写页面、组件、组合式函数)不需要安装 @nuxt/kit。
bash
npm install -D @nuxt/kit核心工具
defineNuxtModule
定义 Nuxt 模块——每个模块的入口:
ts
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
meta: {
name: 'my-module',
configKey: 'myModule',
},
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
addPlugin(resolve('./runtime/plugin'))
},
})createResolver
为什么必须用 createResolver?
模块代码经过构建后,相对路径会失效。createResolver 基于源文件实际位置解析路径,确保路径始终正确。
ts
const { resolve } = createResolver(import.meta.url)
resolve('./runtime/plugin') // 解析为绝对路径
resolve('~/app/pages') // 解析项目路径
// ❌ 错误:不使用 createResolver
addPlugin('./runtime/plugin') // 构建后可能解析到错误路径添加资源
addPlugin
注册运行时插件,插件会在应用启动时自动执行:
ts
addPlugin(resolve('./runtime/plugin'))addComponent
注册全局组件,使用时不需要 import:
ts
addComponent({
name: 'MyButton', // 组件名,使用时写 <MyButton>
filePath: resolve('./runtime/components/Button.vue'),
mode: 'client', // 可选:仅客户端加载
})addComposable
注册全局组合式函数,使用时不需要 import:
ts
addComposable({
name: 'useMyFeature', // 直接使用 useMyFeature()
filePath: resolve('./runtime/composables/useMyFeature.ts'),
exported: 'useMyFeature', // 导出的函数名
})TIP
addComposable 与 nuxt.hook('imports:dirs') 的区别:前者注册单个函数 后者注册整个目录(目录下所有导出自动注册)。单个函数更精确,整个目录更方便
addLayout
注册布局:
ts
addLayout({
name: 'custom',
filePath: resolve('./runtime/layouts/custom.vue'),
})addServerHandler
注册服务端路由:
ts
addServerHandler({
route: '/api/my-module/health',
handler: resolve('./runtime/server/health'),
method: 'get', // 可选:限制 HTTP 方法
})钩子工具
钩子是什么?
Nuxt 构建过程中会在特定时机触发钩子事件,模块通过监听这些事件来修改 Nuxt 的行为。例如,在解析自动导入前添加自定义目录。
添加自动导入
ts
// 方式一:添加整个目录(目录下所有导出自动注册)
nuxt.hook('imports:dirs', (dirs) => {
dirs.push(resolve('./runtime/composables'))
})
// 方式二:从 npm 包导入指定函数
nuxt.hook('imports:sources', (sources) => {
sources.push({
from: 'my-lib',
imports: ['myFunction', 'anotherFunction'],
})
})添加组件目录
ts
nuxt.hook('components:dirs', (dirs) => {
dirs.push({
path: resolve('./runtime/components'),
prefix: 'My', // 组件名前缀,如 MyButton
})
})修改 Nitro 配置
ts
nuxt.hook('nitro:config', (nitroConfig) => {
nitroConfig.externals?.push(resolve('./runtime/server'))
})模板工具
addTemplate
生成虚拟模块文件,在构建时动态创建代码:
ts
const template = addTemplate({
filename: 'my-module-options.mjs',
write: true, // 写入 .nuxt/ 目录
getContents: () => {
return `export default ${JSON.stringify(options)}`
},
})
// template.dst 是生成文件的路径,可以在其他地方引用addTemplate vs addTypeTemplate?
addTemplate 生成 JS/TS 模块文件,addTypeTemplate 生成 .d.ts 类型声明文件。前者是运行时使用的,后者是为了 IDE 类型提示。
addTypeTemplate
ts
addTypeTemplate({
filename: 'types/my-module.d.ts',
getContents: () => {
return `declare module '#app' {
interface NuxtApp {
$myModule: MyModuleInstance
}
}`
},
})其他工具
| 函数 | 说明 | 典型场景 |
|---|---|---|
useNuxt | 获取 Nuxt 实例 | 在 setup 外访问 Nuxt 配置 |
useLogger | 创建日志器 | 模块开发时输出调试信息 |
isNuxt2 / isNuxt3 | 检查 Nuxt 版本 | 兼容 Nuxt 2/3 的模块 |
getNuxtVersion | 获取 Nuxt 版本号 | 版本判断 |
checkNuxtCompatibility | 检查兼容性 | 模块安装时检查版本 |
resolveModule | 解析模块路径 | 在模块中引用其他 npm 包 |
installModule | 安装其他模块 | 模块依赖另一个模块时使用 |
installModule 示例
ts
// 模块 A 依赖模块 B,自动安装
setup(options, nuxt) {
installModule('@nuxtjs/tailwindcss')
installModule('@pinia/nuxt')
}完整模块示例
一个日志模块的完整实现,展示 Kit 工具的综合使用:
ts
// src/module.ts
import { defineNuxtModule, addPlugin, addComposable, addServerHandler, createResolver } from '@nuxt/kit'
export interface ModuleOptions {
endpoint: string
level: 'debug' | 'info' | 'warn' | 'error'
}
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'nuxt-logger',
configKey: 'logger',
compatibility: { nuxt: '^3.0.0 || ^4.0.0' },
},
defaults: {
endpoint: '/api/log',
level: 'info',
},
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
// 注册运行时插件
addPlugin(resolve('./runtime/plugin'))
// 注册组合式函数
addComposable({
name: 'useLogger',
filePath: resolve('./runtime/composables/useLogger'),
})
// 注册服务端路由
addServerHandler({
route: options.endpoint,
handler: resolve('./runtime/server/log'),
method: 'post',
})
// 传递配置到运行时
nuxt.options.appConfig.logger = options
},
})常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
createResolver 路径错误 | 没有传 import.meta.url | 始终使用 createResolver(import.meta.url) |
addTemplate 后找不到文件 | 没有设置 write: true | 需要写入时设置 write: true |
| 钩子中异步操作报错 | nuxt.hook 回调中使用了 await 但未声明为 async | 确保异步钩子回调标记为 async |
installModule 循环依赖 | 模块 A 安装模块 B,B 又安装 A | 检查模块依赖关系,避免循环 |