☰
wechatferry Nuxt 模块实战:用 skills、middleware 与定时任务在 Nuxt 中构建微信机器人
2026/10/14 16:58:37 网站建设 项目流程
  • 即时通讯
  • 后端
  • AI 应用

【免费下载链接】wechatferry

-

项目地址:https://gitcode.com/gh_mirrors/wec/wechatferry
点击查看免费下载

wechatferry 的 Nuxt 模块(@wechatferry/nuxt)让你只需在nuxt.config.ts中注册模块、在server/wcferry/目录下编写技能与中间件文件,即可把一个基于 Wechaty 协议的微信机器人嵌入 Nuxt 3 服务:本文以官方文档 Nuxt 集成指南 为主线,结合packages/nuxt的模块实现源码,完整讲清安装配置、defineBotCommandHandler命令技能的编写与自动导入机制、全局/局部中间件、定时任务以及开发态 DevTools 调试面板的落地方式。

模块安装

按照官方文档 docs/integrations/nuxt.md 给出的安装方式,在 Nuxt 项目根目录执行:

pnpx nuxi module add @wechatferry/nuxt

该命令通过nuxi module add将@wechatferry/nuxt添加到依赖并写入nuxt.config.ts的modules数组(在 pnpm 项目中等价于pnpm dlx nuxi module add @wechatferry/nuxt,或使用npx前缀)。模块包信息可在 packages/nuxt/package.json 中确认,包名为@wechatferry/nuxt,当前版本 0.0.26,其核心依赖为@nuxt/kit、@nuxt/devtools-kit以及同仓库的@wechatferry/puppet、@wechatferry/plugins(均为workspace:*依赖),最终产物的入口为dist/module.mjs/dist/module.cjs。

仓库内的 playground 由于直接引用本地模块源码,其 playground/nuxt.config.ts 写的是modules: ['../src/module'];正式使用 npm 包时对应写成@wechatferry/nuxt即可。

模块配置:debug、safeMode 与 keepalive

模块通过defineNuxtModule声明了三个配置项,配置键为wcferry,见 packages/nuxt/src/module.ts:

export default defineNuxtConfig({ modules: ['@wechatferry/nuxt'], wcferry: { debug: false, // 开启 debug 模式(默认 false) safeMode: false, // 为 puppet 启用安全模式(默认 false) keepalive: false, // 为 agent 启用 keepalive(默认 false,可为秒数) }, })
  • debug:开启调试模式。源码中options.debug || nuxt.options.dev时才注册开发态资源(见 module.ts#L48-L54),也就是说Nuxt 开发环境下调试面板自动启用,生产构建不会携带 DevTools 相关逻辑。
  • safeMode:开启后 puppet 会被createSafeModePuppet包裹,实现节流风控,对应文档 安全模式。
  • keepalive:透传给底层WechatferryAgent,用于登录后存活检查(详见 useBotAgent.ts 与 agent 包 types.ts 中keepalive选项说明)。

模块 setup 阶段还会做两件事:把runtime/server目录加入 Nitro 服务扫描目录(addServerScanDir),并把整个wcferry配置写入runtimeConfig(见 module.ts#L37-L55);同时强制打开 Nitro 实验特性nitro.experimental.tasks = true,这是后面定时任务defineCronTask能运行的前提。playground 中的实际配置示例为:

// packages/nuxt/playground/nuxt.config.ts export default defineNuxtConfig({ modules: ['../src/module'], wcferry: { keepalive: true, }, devtools: { enabled: true }, compatibilityDate: '2024-08-25', })

第一个技能:defineBotCommandHandler

文档中最核心的使用示例,是在server/wcferry/skills/*.ts中定义一个群聊命令技能(摘自 docs/integrations/nuxt.md):

// server/wcferry/skills/*.ts /** * 在群里说:@机器人 ping * 机器人回复:pong */ export default defineBotCommandHandler({ command: 'ping', handler({ message, _command, _args }) { message.say('pong') }, })

效果是:群内@机器人 ping后机器人回复pong。其选项类型定义在 defineBotCommandHandler.ts:

export interface CommandHandlerPayload { message: Message // wechaty 的 Message 对象 command: string // 匹配到的命令名 args: string // 命令后的剩余参数 } export interface BotCommandHandlerOptions { command: string | RegExp handler: (payload: CommandHandlerPayload) => unknown middleware?: BotHandler<'message'> | string | (string | BotHandler<'message'>)[] }

从源码实现看,当command传字符串时,会被编译为正则/@.*?\s(ping)(?:\s([\S\s]*))?/,并注册到message:room:mention钩子上;触发后从消息文本中解析出command与args再交给handler(见 defineBotCommandHandler.ts#L20-L43)。也就是说:

  1. 命令只会在群聊中 @ 机器人的消息上尝试匹配(该钩子由mentionSelf()判定后才触发,见 wcferry.ts#L13-L25);
  2. args会捕获命令之后的所有剩余文本,可用于实现带参数的子命令;
  3. 也支持直接传RegExp作为command,跳过自动正则构造。

仓库 playground 中的真实技能文件 ping.ts 与文档示例一致,并额外演示了middleware: 'local'写法:

export default defineBotCommandHandler({ command: 'ping', handler({ message }) { message.say('pong') }, middleware: 'local', })

skills 的自动导入机制

文档强调:“server/wcferry/skills文件夹下的技能和机器人命令将自动导入!” 这句话背后的实现位于 packages/nuxt/src/virtual.ts。模块在 Nitro 初始化时(nitro:init钩子,见 module.ts#L44-L46)调用setupVirtual,完成以下工作:

  1. 定位目录:遍历 Nitro 的scanDirs,在每个扫描目录下拼接出wcferry子目录(对应项目的server/wcferry),并加入 Nuxt watch 列表;
  2. 扫描技能文件:对wcferry/skills目录用 fast-glob 匹配**/*.{js,mjs,cjs,ts,mts,cts,tsx,jsx}(GLOB_SCAN_PATTERN,见 virtual.ts#L8);
  3. 生成虚拟模块#internal/wcferry/skills:把每个技能文件转成一行import("...")语句拼接导出,技能名取文件基名的 camelCase 形式;
  4. 延迟触发:真正的 import 发生在机器人ready事件之后,见 wcferry.ts#L10-L12——import('#internal/wcferry/skills')会在 bot 就绪后动态加载,避免在 puppet 尚未启动时注册钩子;
  5. 热更新:监听builder:watch,当wcferry目录下文件发生增删(event !== 'change')时触发rollup:reload重载(见 virtual.ts#L66-L73)。

同时扫描结果会写入nitro.scannedSkills,供 DevTools 面板通过 RPC 拉取展示(见 types.ts 中ScannedWcferrySkill定义与 server-rpc/index.ts)。

因此你只需要在server/wcferry/skills/下按文件新增技能,每个文件export default一个defineBot*Handler即可,无需任何手工注册或import语句。

中间件:全局与局部

与技能同级的还有server/wcferry/middleware/目录,用于编写可复用的前置处理逻辑。defineBotMiddleware定义在 defineBotMiddleware.ts,本质是返回一个{ hook, handler }对象,由虚拟模块#internal/wcferry/middleware统一收集并导出为$global与$local两个数组(见 virtual.ts#L44-L64)。

命名约定决定作用域(从源码结构看):文件名包含.global的进入全局中间件,否则为局部中间件:

// server/wcferry/middleware/global.global.ts —— 全局:对所有匹配 hook 的 handler 生效 export default defineBotMiddleware({ hook: 'message', async handler(msg) { console.error(`${msg.talker().name()}: ${msg.text()}`) }, })
// server/wcferry/middleware/local.ts —— 局部:需显式在 handler 的 middleware 选项中引用 export default defineBotMiddleware({ hook: 'message:room:mention', async handler(msg) { if (msg.text().includes('测试')) { msg.say('测试成功') return true // 返回非 undefined 时短路,后续 handler 不再执行 } }, })

两个示例分别对应仓库中的 global.global.ts(打印所有消息的群成员与文本)和 local.ts(群内被 @ 且文本含“测试”时直接应答并拦截)。

装配逻辑在 defineBotHandler.ts 中:

  • 全局中间件按hook.startsWith(middleware.hook)过滤后自动注入所有匹配的 handler;
  • 局部中间件只有在middleware选项中以字符串名引用时才被查找装配(在$local中按hook前缀匹配);
  • 中间件按“全局在前、局部在后”的顺序串行执行,任一中间件返回非undefined值即短路,不再执行主 handler——这就是local.ts中return true能拦截消息的原因。

defineBotHandler还支持when条件(正则、布尔值或异步函数),只有条件命中才执行handler,defineBotCommandHandler内部正是利用该机制以正则匹配命令文本的。

更多处理器与定时任务

除了命令技能,模块在runtime/server/utils下提供了整套处理器工具,均可通过 Nuxt 的自动导入在server/wcferry/下直接使用:

工具函数文件作用
defineBotHandlerdefineBotHandler.ts通用钩子处理器,可指定hook、when、middleware
defineBotMessageHandlerdefineBotMessageHandler.ts消息类钩子(message、message:room、message:room:mention、message:contact)
defineBotRoomHandlerdefineBotRoomHandler.ts群事件钩子(room:join、room:leave、room:topic、room:invite等)
defineBotMiddlewaredefineBotMiddleware.ts定义可复用中间件
defineCronTaskdefineCronTask.ts基于 Nitro Tasks 的定时任务

可用钩子清单定义在 useBot.ts 的BotHooks接口中,包括message、message:room、message:room:mention、message:contact、room、room:join、room:leave、room:topic、room:invite。这些钩子由 Nitro 插件 wcferry.ts 在bot.on('message'/'room-join'/...)事件中逐一callHook分发,实现了 wechaty 原生事件到模块自定义钩子体系的桥接。

定时任务方面,defineCronTask基于nitropack的defineTask加croner实现:传入pattern(cron 表达式或Date)即按表达式周期触发,应用关闭(Nitroclose钩子)时自动cron.stop();不传pattern则只注册为一个可手动调用的 Task(见 defineCronTask.ts#L9-L24)。playground 中的示例 sayHi.ts 演示了任务内直接useBot()获取当前登录用户:

export default defineCronTask({ // pattern: '* * * * *', async run() { const bot = useBot() console.error(`Hi, I am ${bot.currentUser.name()}, now is ${new Date()}`) return { result: true } }, })

运行时调用链:puppet、agent 与安全模式

理解各define*工具如何生效,需要看服务启动链路。Nitro 插件 wcferry.ts 的执行顺序为:

  1. useBotPuppet()创建 puppet(单例,见 useBotPuppet.ts);
  2. useBot()用WechatyBuilder.build({ puppet })构建 bot 并挂载hookable钩子集(见 useBot.ts#L24-L33);
  3. bot.start()启动;ready后动态加载 skills 虚拟模块、绑定消息/群事件分发;
  4. Nitro 应用close时调用bot.stop(),保证进程退出时干净停止。

其中useBotPuppet与配置项的关联是:

const agent = useBotAgent() // 读取 runtimeConfig.wcferry.keepalive const { wcferry: { safeMode } } = useRuntimeConfig() puppet = new WechatferryPuppet({ agent }) // 封装 @wechatferry/agent + @wechatferry/core if (safeMode) puppet = createSafeModePuppet(puppet)
  • keepalive最终传入 WechatferryAgent 的keepalive选项,用于登录存活检查;
  • safeMode生效时,createSafeModePuppet会返回一个 Proxy 包裹的原生 puppet,拦截所有messageSend*方法并施加三层节流,默认参数(见 safe-mode.ts):全局 40 条/分钟、同一会话 1 秒/条、不同会话之间 3~5 秒随机间隔,参数均可通过插件选项覆盖。官方文档 安全模式 也特别提醒:安全模式只限制发送频率,不能替代养号等风控规避手段。

开发态 DevTools 面板

在开发环境(nuxi dev)或显式设置wcferry.debug: true时,模块会额外做三件事(见 module.ts#L48-L54):

  1. 把runtime/nitro目录也加入 Nitro 扫描,从而注册调试路由:SSE 事件流__wcferry__/sse.ts实时推送 bot 的start/login/ready/message/error等事件(见 sse.ts),以及数据库浏览接口database.get.ts/database.post.ts;
  2. 通过setupDevToolsUI在 Nuxt DevTools 中注入一个名为 “Wcferry” 的自定义 Tab(微信图标、iframe 视图,见 devtools.ts)。生产构建时通过sirv静态服务内置的client/面板(含 skills.ts 中通过 RPCgetServerSkills()拉取技能列表的逻辑),源码仓库开发时则代理到本地localhost:3300的独立面板进程;
  3. DevTools 初始化后经extendServerRpc('wcferry', ...)暴露服务端 RPC 函数(见 server-rpc/index.ts)。

这意味着开发时可以直观查看当前被自动导入的技能清单与实时消息流,而不必逐条console.error调试。

小结与适用边界

  • 完整体验的最低配置就是文档中的两步:安装模块 + 在server/wcferry/skills/放一个defineBotCommandHandler文件;
  • 群命令、消息钩子、群事件、定时任务分别对应defineBotCommandHandler/defineBotMessageHandler/defineBotRoomHandler/defineCronTask,均支持when条件与中间件(全局自动、局部按名引用,中间件返回值非undefined即短路);
  • debug/safeMode/keepalive三个模块配置项分别控制 DevTools 调试面板、发送节流风控、登录存活检查,默认均为false;
  • 适用前提:该模块依赖 wechatferry 的 PC Hook 协议栈(@wechatferry/core调用sdk.dll),即机器人运行于 Windows 微信客户端之上;Nuxt 侧代码本身与平台无关,而 puppet 实际连通的 agent 所在环境决定了最终可行性。
  • 即时通讯
  • 后端
  • AI 应用

【免费下载链接】wechatferry

-

项目地址:https://gitcode.com/gh_mirrors/wec/wechatferry
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询