本地模块
为什么需要本地模块?
当项目中有可复用的功能需要封装时,你有三种选择:
| 方式 | 能力 | 适用场景 |
|---|---|---|
| 组合式函数 | 封装逻辑 | 简单状态/逻辑复用 |
| 插件 | 提供全局方法、初始化 | 全局注册、应用初始化 |
| 本地模块 | 添加自动导入、注册组件、修改构建配置 | 跨页面复用的功能包 |
简单说:插件和组合式函数做不到的事(如添加自动导入、注册全局组件、修改 Nitro 配置),才需要本地模块。
创建本地模块
text
modules/
└── my-module/
├── index.ts # 模块入口(构建时执行)
└── runtime/
├── plugin.ts # 运行时插件
└── composables/
└── useMyFeature.ts模块入口
ts
// modules/my-module/index.ts
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
meta: {
name: 'my-module',
configKey: 'myModule',
},
defaults: {
enabled: true,
},
setup(options, nuxt) {
if (!options.enabled) return
const { resolve } = createResolver(import.meta.url)
// 添加插件
addPlugin(resolve('./runtime/plugin'))
// 添加自动导入
nuxt.hook('imports:dirs', (dirs) => {
dirs.push(resolve('./runtime/composables'))
})
// 添加自动导入预设(从 npm 包导入指定函数)
nuxt.hook('imports:sources', (sources) => {
sources.push({
from: 'my-lib',
imports: ['myFunction'],
})
})
},
})为什么需要 createResolver?
核心原因
模块代码经过构建后,相对路径会失效。createResolver(import.meta.url) 基于模块文件的实际位置创建路径解析器,确保无论构建后代码在哪里,路径都能正确指向源文件。
ts
// ❌ 错误:构建后 ./runtime/plugin 可能解析到错误路径
addPlugin('./runtime/plugin')
// ✅ 正确:createResolver 始终相对于源文件位置解析
const { resolve } = createResolver(import.meta.url)
addPlugin(resolve('./runtime/plugin'))nuxt.hook 的常用钩子
| 钩子名 | 用途 | 触发时机 |
|---|---|---|
imports:dirs | 添加自动导入目录 | 构建时,解析自动导入前 |
imports:sources | 添加自动导入预设 | 构建时,解析自动导入前 |
components:dirs | 添加组件目录 | 构建时,解析组件前 |
nitro:config | 修改 Nitro 配置 | 构建时,创建 Nitro 实例前 |
prepare:types | 添加类型声明 | 构建时,生成类型前 |
TIP
这些钩子名来源于 Nuxt 内部的构建流程 你不需要记住所有钩子,按需查阅即可
注册本地模块
ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
// 方式一:路径引用
'./modules/my-module',
// 方式二:带配置
['./modules/my-module', { enabled: true }],
],
// 方式三:通过配置键(对应 meta.configKey)
myModule: {
enabled: true,
},
})配置合并机制
defaults 中的默认值会被 nuxt.config.ts 中的配置覆盖。即:defaults → 用户配置 → 最终 options。
运行时 vs 构建时
INFO
这是理解本地模块最关键的概念
| 代码位置 | 执行时机 | 可用 API | 典型用途 |
|---|---|---|---|
index.ts(setup) | 构建时 | @nuxt/kit 工具、nuxt.hook | 注册插件、添加自动导入、修改配置 |
runtime/ 目录 | 运行时 | Vue 组合式函数、浏览器/Node API | 实际功能逻辑 |
ts
// ❌ 错误:在 setup 中使用运行时 API
setup(options, nuxt) {
const route = useRoute() // 报错!构建时没有路由
const state = useState() // 报错!构建时没有响应式系统
}
// ✅ 正确:运行时逻辑放在 runtime/ 中
// runtime/composables/useMyFeature.ts
export const useMyFeature = () => {
const route = useRoute() // OK,运行时有路由
const state = useState() // OK,运行时有响应式系统
}实战示例:通知模块
一个更实用的本地模块示例,展示模块的完整能力:
text
modules/
└── notification/
├── index.ts
└── runtime/
├── plugin.ts
├── composables/
│ └── useNotification.ts
└── components/
└── NotificationToast.vuets
// modules/notification/index.ts
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
meta: { name: 'notification', configKey: 'notification' },
defaults: { position: 'top-right' as const, duration: 3000 },
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
addPlugin(resolve('./runtime/plugin'))
nuxt.hook('imports:dirs', (dirs) => {
dirs.push(resolve('./runtime/composables'))
})
nuxt.hook('components:dirs', (dirs) => {
dirs.push(resolve('./runtime/components'))
})
// 把配置传给运行时
nuxt.options.appConfig.notification = options
},
})ts
// modules/notification/runtime/composables/useNotification.ts
export const useNotification = () => {
const notifications = ref<{ id: number; message: string; type: string }[]>([])
function notify(message: string, type = 'info') {
const id = Date.now()
notifications.value.push({ id, message, type })
setTimeout(() => {
notifications.value = notifications.value.filter(n => n.id !== id)
}, 3000)
}
return { notifications, notify }
}模块模板
使用 CLI 创建模块模板:
bash
npx nuxi init -t module my-moduleTIP
这会创建一个完整的模块开发环境 包含 playground/ 测试项目、TypeScript 配置等
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 模块安装后不生效 | 忘记在 modules 中注册 | 确认 nuxt.config.ts 的 modules 包含模块路径 |
resolve 路径报错 | 没有使用 createResolver | 始终用 createResolver(import.meta.url) 创建解析器 |
setup 中 useState 报错 | 在构建时使用了运行时 API | 运行时逻辑放到 runtime/ 目录 |
| 配置不生效 | configKey 与 nuxt.config.ts 中的键名不匹配 | 确保 meta.configKey 与配置键名一致 |
@nuxt/kit 导入失败 | 未安装 @nuxt/kit | 本地模块也需要 npm install -D @nuxt/kit |