基础知识#
在 Nuxt 根目录下创建一个 modules 目录,然后模块文件导出一个 defineNuxtModule 方法调用:
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({ // ...})defineNuxtModule 方法的配置对象:
- meta
- defaults
- schema
- hooks
- setup
meta 用于配置模块的元数据,所谓元数据,也就是模块的基本信息,通常包括以下字段:
-
name:模块的名称,通常对应 npm 包的名称
-
configKey:在 nuxt 配置文件中如果要为该模块提供配置信息,对应的键是什么
import { defineNuxtModule } from '@nuxt/kit'export default defineNuxtModule({meta: {name: 'xxxx',configKey: 'abc',},})export default defineNuxtConfig({abc: {// 传入一些给模块的配置},}) -
compatibility:定义该模块和 Nuxt 版本的兼容性
compatibility: {nuxt: '^3.0.0'}
defaults 用来定义模块的默认配置选项,其值可以是一个对象,也可以是一个返回对象的函数。
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({ meta: { name: 'xxxx', configKey: 'abc', }, defaults: { message: '这是模块的默认参数', },})export default defineNuxtConfig({ abc: { message: '这是用户传递的参数', },})如果用户在 nuxt.config 中没有传递对应配置,则会自动使用 defaults 中的值;如果传递了配置,则会将用户的选项与 defaults 进行合并。如果有冲突的,用户的选项的优先级更高。
schema 用于配置选项校验,这是一个可选字段,通过定义一个 JSON Schema,对用户传入的模块选项进行校验。
schema: { type: 'object', properties: { message: { type: 'string' } }}hooks 字段也是一个选填字段,可以在模块定义时注册一些 Nuxt 的生命周期钩子。
hooks: { 'pages:extend': (pages) => { // 修改 Nuxt 自动生成的页面路由 console.log(`当前页面数:${pages.length}`) }}setup 是模块的核心函数,是整个模块的逻辑主体。它会在模块加载时被调用,接收两个参数:
- moduleOptions:经过 defaults 合并后的模块配置
- nuxt:Nuxt 实例,可以通过它修改 Nuxt 的配置、注册插件、添加中间件、扩展路由、调用各种辅助 API 等。
来看一个例子:
export default defineNuxtModule({ meta: { name: '@nuxtjs/example', configKey: 'sample', compatibility: { nuxt: '^3.0.0', }, }, defaults: { message: 'Hello from my module!', }, hooks: { 'app:error': (error) => { console.error('捕获到应用错误:', error) }, }, setup(moduleOptions, nuxt) { console.log(`模块初始化,消息:${moduleOptions.message}`) // 例如,可以动态修改 Nuxt 配置: nuxt.options.css.push('~/assets/example.css') // 或添加插件、服务器中间件等等 },})相关细节#
了解了模块的基础知识后,接下来来看一些相关的细节。
1. 模块与插件
模块和插件两者有什么区别呢?该用哪一种方式呢?
模块会先于插件执行。因此,模块往往会作为 Nuxt 扩展的整体入口,能够在 Nuxt 启动时执行一系列操作,比如修改配置、添加路由、注册中间件、注入模板、添加自动导入目录、生成类型声明等。
使用 nuxt.hook 来修改 Webpack 或 Vite 的配置:
// 示意代码import { defineNuxtModule } from '@nuxt/kit'
// 在模块中修改 Vite 的配置export default defineNuxtModule({ setup(options, nuxt) { nuxt.hook('vite:extendConfig', (config) => { config.define = { ...config.define, 'process.env.MY_CUSTOM_VAR': JSON.stringify('Hello from myModule'), } }) },})向 Nuxt 服务器添加一个中间件,例如记录请求日志:
// 示意代码import { defineNuxtModule, addServerHandler } from '@nuxt/kit'
export default defineNuxtModule({ setup(options, nuxt) { addServerHandler({ route: '/api/log', handler: (req, res) => { console.log(`Request received: ${req.url}`) res.end('Logged') }, }) },})插件则是用于在运行时向 Nuxt 应用中注入特定功能的一个机制。模块更像是组织和协调者,决定具体做什么。插件只是其中的一种实现手段。
2. runtime目录
在 Nuxt 模块开发中,通常会使用一个专门的 runtime 目录来存放需要在用户应用中运行的代码。这部分代码包括:
- 插件
- 组合式函数或其他可复用项
- 组件
- 服务器代码
这些 runtime 中的资源在构建模块时,会由 Nuxt 模块构建工具进行处理和打包,然后注入到最终用户的 Nuxt 应用中。
发布模块#
整个发布的过程和之前我们发布 layer 是一样的。
{ // ... "main": "dist/module.js", "types": "dist/utils.d.ts", "file": ["dist"] // ...}Nuxt 项目安装了对应的模块后,需要在配置文件中配置该模块:
export default defineNuxtConfig({ // ... modules: ['my-utils-module'],})另外,Nuxt 官方还提供了创建模块的模板,通过下面的命令:
npx nuxi init -t module <my-module>可以创建一个模块的项目,里面还包含测试、playground 等特性。
-EOF-