Node.js为何生成单例类两个实例?Next.js开发环境问题求助
问题原因
Next.js 开发模式的**热重载(Fast Refresh)**机制是核心诱因:
- 开发时代码变更会触发模块重新编译加载,模块级导出的单例类会被重新实例化。
- 首次连接SSE端点时,使用的是旧模块的SSE实例(已注册客户端);发送消息时,若代码变更触发过热重载,此时
outgoing.ts会加载新模块的SSE实例(客户端列表为空),导致消息无法推送。 - 刷新页面后,客户端连接到新模块的SSE实例,后续发送消息也复用该实例,功能恢复正常。
解决方案
方案1:将单例实例挂载到全局对象(推荐)
修改serverSentEvents.ts的单例实现,把实例存储在globalThis(Node.js全局对象)上,避免模块热重载时丢失实例:
class SSE { private clients: Map<string, Response> = new Map(); private constructor() {} static getInstance(): SSE { const global = globalThis as typeof globalThis & { sseInstance?: SSE }; if (!global.sseInstance) { global.sseInstance = new SSE(); } return global.sseInstance; } // 注册客户端 registerClient(clientId: string, res: Response) { this.clients.set(clientId, res); } // 发送消息 send(clientId: string, message: string) { const res = this.clients.get(clientId); if (res) { res.write(`data: ${JSON.stringify(message)}\n\n`); } } } export default SSE.getInstance();
方案2:排除SSE模块参与热重载
在next.config.js中配置,让serverSentEvents.ts模块跳过开发模式的热重载,确保始终使用同一个实例:
/** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config, { dev }) => { if (dev) { config.module.rules.push({ test: /serverSentEvents\.ts$/, use: ['cache-loader'], include: /lib\/sse/, }); } return config; }, }; module.exports = nextConfig;
安装依赖:
npm install cache-loader --save-dev
额外说明
- 开发模式下,若修改了SSE类的核心逻辑,需手动重启开发服务器才能生效(因模块被排除在热重载外)。
- 生产模式无热重载机制,该异常不会在上线环境出现。
内容的提问来源于stack exchange,提问作者sincerely_manny
相关产品推荐
相关产品推荐

