7.2 编写自己的Nuxt模块


7.2 编写自己的 Nuxt 模块

用过装备(第 4 章的 Pinia 集成),现在进车间学造装备。本节把"一段每次新项目都要复制的配置与插件"提炼成模块:defineNuxtModule 的结构、模块能改什么(配置、钩子、模板)、本地开发调试循环。写完这节你会重新理解 modules 数组里每一项的价值。

从重复劳动到模块

先看症状:你在第五个项目里复制同一段"给所有接口加统一前缀、注册一个埋点插件、注入一个默认配置"的样板。每次复制都要手改三处,漏一处出隐晦 bug。模块化就是把这三件事封装成一个可安装单元:

// modules/telemetry/index.ts // 本地模块:统一埋点能力,任何项目一行配置接入 import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'telemetry', // 模块名,配置命名空间 configKey: 'telemetry', // nuxt.config 里读取的键名 }, // 默认配置:用户没写时兜底 defaults: { endpoint: '/api/telemetry', sampleRate: 1, }, setup(options, nuxt) { // 能力一:读用户配置并与默认值合并 if (options.sampleRate <= 0) { throw new Error('采样率必须大于零') } // 能力二:注册插件——埋点插件的物理载体 const resolver = createResolver(import.meta.url) addPlugin(resolver.resolve('./runtime/plugin')) // 能力三:注入运行时配置,插件里用 useRuntimeConfig 读到 nuxt.options.runtimeConfig.public.telemetry = { endpoint: options.endpoint, sampleRate: options.sampleRate, } // 能力四:挂构建钩子——构建期做事的标准时机 nuxt.hook('nitro:config', (nitroConfig) => { // 让 Nitro 知道埋点上报端点,服务端也能上报 nitroConfig.runtimeConfig = nitroConfig.runtimeConfig || {} }) }, })
// modules/telemetry/runtime/plugin.ts // 模块注入的插件:跑在应用两端 export default defineNuxtPlugin((nuxtApp) => { const config = useRuntimeConfig().public.telemetry // 暴露全局能力:组件里 useNuxtApp().$telemetry 即可用 return { provide: { telemetry: { track(event: string, data?: Record<string, unknown>) { if (Math.random() > config.sampleRate) return // 采样 $fetch(config.endpoint, { method: 'POST', body: { event, data, ts: Date.now() }, }).catch(() => {}) // 埋点失败静默,不打扰业务 }, }, }, } })

接入只需两行:

// nuxt.config.ts export default defineNuxtConfig({ modules: ['~/modules/telemetry'], // 本地路径直接可装 telemetry: { sampleRate: 0.5 }, // 配置进模块的命名空间 })
<!-- 任意组件 --> <script setup> const { $telemetry } = useNuxtApp() function checkout() { $telemetry.track('checkout-click', { from: 'cart' }) } </script>

模块能改什么

@nuxt/kit 提供的改装面,按频率排序:

能力 API 典型场景
加插件 addPlugin 注入全局能力(上例)
加组件 addComponentsDir 组件库模块注册自己的组件
加组合函数 addImports 模块提供 useXxx 自动导入
改配置 nuxt.options 合并默认 runtimeConfig
挂钩子 nuxt.hook 构建期介入(加模板、改产物)
加服务端处理器 addServerHandler 模块自带 API 端点
生成模板 addTemplate 按配置生成代码文件

模块与插件的区别值得一表说清:插件跑在应用运行时(每个请求/每次加载),模块跑在构建时(只在 nuxt dev / build 启动阶段)。模块是"改装车间",装完就不在运行时存在;插件是"装上去的零件",随应用跑。模块的常见产出就是往应用里塞插件、组件、配置。

本地模块的开发循环

本地模块目录(modules/xxx)会被 Nuxt 自动发现(较新版本支持 modules 目录约定),改模块代码需要重启开发服务器——它只在启动时执行一次。调试三个手段:

// 手段一:安装时打印,确认模块被加载、配置长什么样 setup(options, nuxt) { if (nuxt.options.dev) { console.log('[telemetry] 装载,配置:', options) } } // 手段二:用 nuxt.hook 观察构建流程走到哪一步 nuxt.hook('modules:done', () => console.log('[telemetry] 所有模块装载完成')) // 手段三:kit 的 buildLog 类工具输出结构化信息(或直接 console)

成熟后发布成 npm 包,modules 数组里写包名即可给别人用——你写模块的姿势没变,变的只是安装方式。团队内部常见形态是私有包:公司统一埋点、鉴权、设计系统各一个模块,新项目接入成本从"复制三十行改三处"降到"写一行配置"。

什么时候该写模块

判据三条,满足其一就值得:

  • 重复三次以上:同样的配置与插件在多个项目出现;
  • 需要构建期介入:按配置生成代码、改构建产物——插件做不到,只有模块能做;
  • 要分发给他人:装一行配置就能用,比"复制这份文档照做"体面得多。

反过来,单项目的一次性定制直接写 nuxt.config 与 plugins 就好,过早模块化是负资产。

⚠️ 常见坑:在模块 setup 里做异步重活拖慢每次 dev 启动。模块启动期执行,一次远程请求加两秒,团队每次热重启都交这笔税。构建期数据要么缓存,要么挪到 nitro 钩子里按需做。

💡 关键直觉:模块是"带安装器的配置包"——它把你对项目做的所有手工改造(插件、组件、配置、端点)打包成一个可声明依赖的单元。读懂 defineNuxtModule,Nuxt 生态对你就从魔法变成工具箱。

本节要点回顾

  • 定义四要素:meta(命名)、defaults(配置兜底)、setup(执行体)、@nuxt/kit 工具(改装面);
  • 模块在构建时跑,插件在运行时跑:模块的产出常常就是注入插件;
  • 改装面高频四件:addPlugin、addImports、nuxt.options、nuxt.hook;
  • 本地模块约定:modules 目录自动发现,改模块要重启 dev,调试靠启动期日志;
  • 该写模块的判据:重复三次、需构建期介入、要分发他人。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U