Skip to content

自定义模块

基础知识#

在 Nuxt 根目录下创建一个 modules 目录,然后模块文件导出一个 defineNuxtModule 方法调用:

import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
// ...
})

defineNuxtModule 方法的配置对象:

meta 用于配置模块的元数据,所谓元数据,也就是模块的基本信息,通常包括以下字段:

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 是模块的核心函数,是整个模块的逻辑主体。它会在模块加载时被调用,接收两个参数:

来看一个例子:

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 官方还提供了创建模块的模板,通过下面的命令:

Terminal window
npx nuxi init -t module <my-module>

可以创建一个模块的项目,里面还包含测试、playground 等特性。


-EOF-