Files
vf_react/src/mocks/browser.js
zdl 6829f687ee fix: 修复 MSW EventEmitter 内存泄漏警告
## 问题
控制台警告:
```
MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 response:mocked listeners added. Use emitter.setMaxListeners() to increase limit
```

## 根本原因

类似 PostHog 的问题:

1. **React StrictMode 双重渲染** - 开发环境组件渲染两次
2. **热重载** - 代码更改时频繁重新加载模块
3. **缺少启动锁** - `startMockServiceWorker()` 被多次调用
4. **事件监听器累积** - 每次启动添加新 listener,旧的未清理

## 解决方案

### 方案A: 防止重复启动
添加启动状态锁:
```javascript
let isStarting = false;
let isStarted = false;

export async function startMockServiceWorker() {
  // 防止重复启动
  if (isStarting || isStarted) {
    console.log('[MSW] 已启动,跳过重复调用');
    return;
  }

  isStarting = true;

  try {
    await worker.start({...});
    isStarted = true;  // 成功后标记
  } finally {
    isStarting = false;  // 无论成功失败都重置
  }
}
```

### 方案B: 完善 stop 逻辑
确保正确清理:
```javascript
export function stopMockServiceWorker() {
  if (!isStarted) return;  // 避免重复停止

  worker.stop();
  isStarted = false;  // 重置状态
  console.log('[MSW] Mock Service Worker 已停止');
}
```

## 影响
-  修复 EventEmitter 内存泄漏警告
-  防止热重载时重复启动 MSW
-  正确清理事件监听器
-  提升开发体验

## 验证
重启开发服务器后:
-  不再有 MaxListenersExceededWarning
-  MSW 只启动一次
-  热重载正常工作
-  Mock 功能正常

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 18:56:12 +08:00

86 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/mocks/browser.js
// 浏览器环境的 MSW Worker
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
// 创建 Service Worker 实例
export const worker = setupWorker(...handlers);
// 启动状态管理(防止重复启动)
let isStarting = false;
let isStarted = false;
// 启动 Mock Service Worker
export async function startMockServiceWorker() {
// 防止重复启动
if (isStarting || isStarted) {
console.log('[MSW] Mock Service Worker 已启动或正在启动中,跳过重复调用');
return;
}
// 只在开发环境且 REACT_APP_ENABLE_MOCK=true 时启动
const shouldEnableMock = process.env.REACT_APP_ENABLE_MOCK === 'true';
if (!shouldEnableMock) {
console.log('[MSW] Mock 已禁用 (REACT_APP_ENABLE_MOCK=false)');
return;
}
isStarting = true;
try {
await worker.start({
// 🎯 智能穿透模式(关键配置)
// 'bypass': 未定义 Mock 的请求自动转发到真实后端
// 'warn': 未定义的请求会显示警告(调试用)
// 'error': 未定义的请求会抛出错误(严格模式)
onUnhandledRequest: 'bypass',
// 自定义 Service Worker URL如果需要
serviceWorker: {
url: '/mockServiceWorker.js',
},
// 是否在控制台显示启动日志和拦截日志 静默模式(不在控制台打印启动消息)
quiet: false,
});
isStarted = true;
console.log(
'%c[MSW] Mock Service Worker 已启动 🎭',
'color: #4CAF50; font-weight: bold; font-size: 14px;'
);
console.log(
'%c智能穿透模式已定义 Mock → 返回假数据 | 未定义 Mock → 转发到 ' + (process.env.REACT_APP_API_URL || '真实后端'),
'color: #FF9800; font-size: 12px;'
);
console.log(
'%c查看 src/mocks/handlers/ 目录管理 Mock 接口',
'color: #2196F3; font-size: 12px;'
);
} catch (error) {
console.error('[MSW] 启动失败:', error);
} finally {
isStarting = false;
}
}
// 停止 Mock Service Worker
export function stopMockServiceWorker() {
if (!isStarted) {
console.log('[MSW] Mock Service Worker 未启动,无需停止');
return;
}
worker.stop();
isStarted = false;
console.log('[MSW] Mock Service Worker 已停止');
}
// 重置所有 Handlers
export function resetMockHandlers() {
worker.resetHandlers();
console.log('[MSW] Handlers 已重置');
}