在 Nuxt 3 中,插件(Plugins) 是一种强大的机制,用于在应用初始化阶段执行自定义逻辑。它们通常用于集成第三方库、注入全局工具/服务、或扩展 Vue/Nitro 实例。
与 Nuxt 2 不同,Nuxt 3 的插件系统更加简洁,且天然支持 TypeScript 和自动导入。
🎯 核心概念
- 位置 :所有插件必须放在项目根目录的
plugins/文件夹下。 - 加载顺序 :按文件名排序加载。可使用数字前缀控制顺序(如
01.my-plugin.ts)。 - 运行环境 :默认在 服务端和客户端 都会执行。可通过命名或配置限制仅在某一端运行。
- 异步支持:插件可以是异步函数,Nuxt 会等待其完成后再渲染应用(SSR 友好)。
📁 文件命名约定
| 文件名 | 运行环境 | 说明 |
|---|---|---|
my-plugin.ts |
通用 (Server + Client) | 两端都执行 |
my-plugin.client.ts |
仅客户端 | 浏览器专属逻辑(如 DOM 操作) |
my-plugin.server.ts |
仅服务端 | SSR 专属逻辑(如读取环境变量) |
💡 完整使用示例
以下是一个从基础到进阶的完整实战示例,涵盖最常见的几种场景。
1. 基础插件:注入全局工具 (useFetch 封装 / Toast)
创建一个通用的请求拦截器或 UI 提示工具。
ts
// plugins/01.utils.ts
export default defineNuxtPlugin((nuxtApp) => {
// 方式一:通过 provide 注入(推荐,支持类型推导)
const toast = {
success: (msg: string) => console.log(`✅ ${msg}`),
error: (msg: string) => console.error(`❌ ${msg}`),
}
return {
provide: {
toast,
},
}
// 方式二(旧版兼容,不推荐):nuxtApp.provide('toast', toast)
})
在组件中使用:
vue
<script setup lang="ts">
// Nuxt 3 自动导入,无需手动 import
const { $toast } = useNuxtApp()
$toast.success('数据加载完成!')
</script>
⚠️ 注意 :通过 provide 注入的内容,在使用时需要加 $ 前缀(如 $toast),这是为了避免与组合式函数命名冲突。
2. 客户端专属插件:集成第三方库 (以 Chart.js 为例)
很多库依赖 window / document,必须在客户端运行。
ts
// plugins/chartjs.client.ts
import { Chart, registerables } from 'chart.js'
export default defineNuxtPlugin(() => {
// 注册所有 Chart.js 组件
Chart.register(...registerables)
// 可以返回 provide 以便全局访问 Chart 构造函数
return {
provide: {
Chart,
},
}
})
3. 服务端专属插件:初始化服务端 SDK
ts
// plugins/analytics.server.ts
export default defineNuxtPlugin(() => {
// 仅在 Node.js 环境中执行
const apiKey = process.env.ANALYTICS_API_KEY
if (!apiKey) {
console.warn('⚠️ ANALYTICS_API_KEY 未配置')
return
}
// 初始化服务端分析 SDK...
console.log('📊 服务端分析已初始化')
})
4. 高级:监听 Nuxt 生命周期钩子
插件可以订阅应用级别的事件,如路由切换、错误处理等。
ts
// plugins/router-hooks.ts
export default defineNuxtPlugin((nuxtApp) => {
// 监听路由变化
nuxtApp.hook('page:finish', () => {
console.log('📄 页面渲染完成')
// 例如:滚动到顶部、发送 PV 统计
})
// 全局错误捕获
nuxtApp.hook('app:error', (error) => {
console.error('💥 应用级错误:', error)
// 上报错误监控平台
})
// SSR 上下文增强
nuxtApp.hook('request', (event) => {
// 在每个服务端请求中添加自定义头
event.headers.set('X-Custom-Header', 'nuxt-app')
})
})
🔧 TypeScript 类型增强
为了让 $toast 等注入内容获得完整的类型提示,需要扩展 Nuxt 的类型定义:
ts
// types/nuxt.d.ts (或 plugins/01.utils.ts 底部)
declare module '#app' {
interface NuxtApp {
$toast: {
success: (msg: string) => void
error: (msg: string) => void
}
}
}
// 确保此文件被当作模块
export {}
⚡ 最佳实践 & 避坑指南
| ✅ 推荐 | ❌ 避免 |
|---|---|
使用 defineNuxtPlugin() 包裹 |
直接导出普通函数 |
用 return { provide } 注入 |
用 nuxtApp.provide() (已废弃风格) |
客户端库加 .client 后缀 |
在服务端引用 window/document |
| 用数字前缀控制关键插件顺序 | 假设文件加载顺序是随机的 |
| 插件中做轻量初始化 | 在插件中执行耗时阻塞操作 |
| 优先使用 Composables 替代插件 | 把所有逻辑都塞进插件 |
💡 重要提醒 :Nuxt 3 中大部分功能可以通过 Composables(组合式函数) 实现。只有当你需要在应用启动时 执行一次性初始化、或需要访问 nuxtApp 实例/生命周期钩子时,才应该使用插件。简单的可复用逻辑请优先使用 composables/ 目录。
🔄 插件 vs Composables 选择指南
需要在应用启动时执行? ──→ 是 ──→ 使用 Plugin
│
否
│
需要访问 nuxtApp/hooks? ──→ 是 ──→ 使用 Plugin
│
否
│
使用 Composable ✅
以上示例基于 Nuxt 3.x ,如果你使用的是 Nuxt 2,语法有较大差异(使用 export default function ({ app }, inject) 模式)