如何将socket.io实例传递到typegraphql resolver中?
解决方案:在TypeGraphQL Resolver中复用Socket.IO单实例发送房间事件
你遇到的导出后拿到新实例的问题,通常由三个原因导致:
- 拼写错误:你代码里写的
modules.export多了一个s,正确导出语法是module.exports = io,拼写错误会导致导出失效,拿到undefined,如果你的逻辑里判断实例不存在就新建,就会生成新实例 - 循环依赖:初始化Socket.IO的文件依赖Resolver相关代码,Resolver又反过来导入IO实例,Node.js模块缓存未完成IO实例导出就被Resolver引入,拿到空值后重复初始化
- 导出的是IO创建函数而非初始化完成的实例,每次导入调用都会生成新实例
下面是两种可直接落地的解决方案:
方案1:单例模式封装IO实例(无额外依赖)
- 第一步:新建单独的IO实例管理文件,避免循环依赖
// src/utils/socket-io.js let ioInstance = null; // 全局仅初始化一次实例 exports.setIOInstance = (io) => { ioInstance = io; }; // 所有业务场景共用同一个实例 exports.getIOInstance = () => { if (!ioInstance) throw new Error("Socket.IO 实例未初始化"); return ioInstance; };
- 第二步:在入口文件初始化IO后,先存实例再加载Resolver、启动服务
// index.js const { Server } = require("socket.io"); const { setIOInstance } = require("./src/utils/socket-io"); const { buildSchema } = require("type-graphql"); // 其他基础依赖引入 const httpServer = // 你的HTTP服务实例,可基于express、koa等创建 const io = new Server(httpServer, { // 你的Socket.IO配置,比如cors规则等 }); // 先存入实例,再执行后续Resolver加载、服务启动逻辑 setIOInstance(io); // 再构建TypeGraphQL Schema const schema = await buildSchema({ resolvers: [/* 你的Resolver列表 */], // 其他Schema配置 }); // 后续启动HTTP服务、GraphQL服务的逻辑
- 第三步:在Resolver中直接获取实例发送事件
// 你的业务Resolver文件 const { getIOInstance } = require("../utils/socket-io"); const { Resolver, Mutation, Arg } = require("type-graphql"); @Resolver() class RoomResolver { @Mutation(() => Boolean) async sendRoomEvent(@Arg("roomId") roomId, @Arg("message") message) { const io = getIOInstance(); // 向指定房间发送事件 io.to(roomId).emit("room_notification", message); return true; } }
方案2:依赖注入方案(适配TypeGraphQL生态)
如果你已经在TypeGraphQL中使用typedi做依赖注入,可以直接把IO实例注入到Resolver中,代码更简洁:
- 第一步:入口文件初始化IO后存入容器
const { Container } = require("typedi"); // IO初始化完成后 Container.set("SOCKET_IO_INSTANCE", io);
- 第二步:在Resolver中注入实例使用
const { Resolver, Mutation, Arg, Inject } = require("type-graphql"); const { Server } = require("socket.io"); @Resolver() class RoomResolver { @Inject("SOCKET_IO_INSTANCE") /** @type {Server} */ io; @Mutation(() => Boolean) async sendRoomEvent(@Arg("roomId") roomId, @Arg("message") message) { this.io.to(roomId).emit("room_notification", message); return true; } }
内容的提问来源于stack exchange,提问作者Timofey Melentev
相关产品推荐
相关产品推荐

