你为什么渲染mcp
   
运作原理
Browser (React app)
│
│ why-did-you-render detects unnecessary re-render
│
▼
Client (runs in browser) ── WebSocket ──▶ MCP Server (Node.js)
│
├─ Persists to ~/.wdyr-mcp/renders/
│
▼
Coding Agent (Claude, etc.)
queries via MCP tools这 客户端 在React应用程序中运行 why-did-you-render每当检测到不必要的重新渲染时,它都会对渲染数据进行清理,并通过WebSocket将其发送到 MCP服务器服务器将报告存储为JSONL文件,并通过编码代理可以查询的MCP工具公开它们。
包裹
此项目是一个包含两个已发布包的monorepo:
| 包 | npm | 描述 |
|---|---|---|
@0x1f320.sh/why-did-you-render-mcp | ](https://www.npmjs.com/package/@0x1f320.sh/why-did-you-render-mcp) | MCP服务器(Node.js)——将渲染数据作为MCP工具公开 |
@0x1f320.sh/why-did-you-render-mcp-client | ](https://www.npmjs.com/package/@0x1f320.sh/why-did-you-render-mcp-client) | 浏览器客户端——捕获重新渲染的数据并将其发送到服务器 |
客户端可以独立安装,无需引入服务器依赖项(MCP SDK、socket.io服务器等)。
安装
# In your React project (client only — no server deps)
npm install @0x1f320.sh/why-did-you-render-mcp-client@latest @welldone-software/why-did-you-render设置
1.配置为什么使用客户端渲染
在应用程序的入口点(例如。 src/main.tsx 或 src/index.tsx),设置 why-did-you-render 以MCP客户端作为其通知者:
import React from "react";
import whyDidYouRender from "@welldone-software/why-did-you-render";
import { buildOptions } from "@0x1f320.sh/why-did-you-render-mcp-client";
if (process.env.NODE_ENV === "development") {
whyDidYouRender(React, {
...buildOptions(),
trackAllPureComponents: true,
});
}客户端自动使用 location.origin 作为项目标识符并连接到 ws://localhost:4649 默认情况下。您可以对两者进行自定义:
const { notifier } = buildOptions({
wsUrl: "ws://localhost:5555",
projectId: "my-app",
});2.将MCP服务器添加到您的代理
Claude Code
claude mcp add why-did-you-render -- npx -y @0x1f320.sh/why-did-you-render-mcp@latestClaude Desktop
claude mcp add-json why-did-you-render '{"command":"npx","args":["-y","@0x1f320.sh/why-did-you-render-mcp@latest"]}' -s user或手动编辑 ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)/ %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"why-did-you-render": {
"command": "npx",
"args": ["-y", "@0x1f320.sh/why-did-you-render-mcp@latest"]
}
}
}Cursor
cursor --add-mcp '{"name":"why-did-you-render","command":"npx","args":["-y","@0x1f320.sh/why-did-you-render-mcp@latest"]}'或添加到 .cursor/mcp.json 在您的项目中:
{
"mcpServers": {
"why-did-you-render": {
"command": "npx",
"args": ["-y", "@0x1f320.sh/why-did-you-render-mcp@latest"]
}
}
}Windsurf
添加 ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"why-did-you-render": {
"command": "npx",
"args": ["-y", "@0x1f320.sh/why-did-you-render-mcp@latest"]
}
}
}VS Code (GitHub Copilot)
code --add-mcp '{"name":"why-did-you-render","command":"npx","args":["-y","@0x1f320.sh/why-did-you-render-mcp@latest"]}'或添加到 .vscode/mcp.json 在您的项目中:
{
"servers": {
"why-did-you-render": {
"command": "npx",
"args": ["-y", "@0x1f320.sh/why-did-you-render-mcp@latest"]
}
}
}3.启动开发服务器并与应用程序交互
MCP服务器和React开发服务器都运行后,在浏览器中与您的应用程序进行交互。代理现在可以使用下面的MCP工具查询重新渲染数据。
MCP工具
| 工具 | 说明 |
|---|---|
get_renders | 返回所有捕获的不必要的重新渲染,包括堆栈跟踪。可选过滤条件 component 名字。 |
get_render_summary | 返回按组件分组的重新呈现摘要,包括计数和持续时间。 |
get_commits | 列出已记录渲染数据的React提交ID。使用这些ID get_renders_by_commit. |
get_renders_by_commit | 返回特定React提交ID的所有不必要的重新呈现,包括堆栈跟踪。 |
get_tracked_components | 按渲染原因列出当前跟踪的组件。 |
get_projects | 列出所有活动项目(由其源URL标识)。 |
save_snapshot | 将当前渲染摘要另存为命名快照,以便以后进行比较。 |
list_snapshots | 列出所有已保存的渲染快照及其时间戳。 |
compare_snapshots | 比较两个已保存的渲染快照,并显示每个组件的渲染计数变化。 |
delete_snapshot | 按名称删除已保存的渲染快照。 |
wait_for_renders | 在代码更改后等待新的渲染(例如HMR),并具有可配置的超时。 |
clear_renders | 清除所有存储的渲染数据。可选范围为特定项目。 |
pause_renders | 暂停浏览器中的渲染数据收集。客户端停止报告,直到恢复。 |
resume_renders | 恢复以前暂停的渲染数据收集 pause_renders. |
当多个项目处于活动状态时,工具接受可选 project 参数(浏览器的源URL,例如。 http://localhost:3000).如果省略并且只存在一个项目,则会自动选择它。
堆栈复写
每份渲染报告包括 stackFrames 跟踪触发重新渲染的钩子链和组件树的数组。客户端在每次渲染更新时捕获堆栈跟踪,并使用 error-stack-parser,过滤掉React/WDYR内部,并通过源代码映射将捆绑的位置解析回原始源文件。
每个帧具有以下结构:
{
type: "hook" | "component", // "hook" for names starting with `use`, otherwise "component"
name: string, // e.g. "useFilter", "Dashboard"
location: {
path: string, // source file path (source-mapped when available)
line: number, // line number in the source file
},
}代理商可以使用 stackFrames 精确定位每个不必要的重新渲染的确切源位置——直接导航到导致它的文件和行,而不需要手动浏览器检查。
快照
快照允许代理捕获某个时间点的当前渲染摘要,并将其与以后的状态进行比较。这对于衡量代码更改是否真正减少了不必要的重新呈现非常有用:
- 呼叫
save_snapshot带有名称(例如。"before-fix") - 更改代码并与应用程序交互
- 呼叫
save_snapshot用另一个名字(例如。"after-fix") - 呼叫
compare_snapshots查看每个组件的渲染计数变化
快照以JSON文件的形式存储在 ~/.wdyr-mcp/snapshots/.
HMR感知等待
wait_for_renders 让代理在代码更改后等待新的呈现。它检测来自Vite和webpack的HMR(热模块替换)事件,因此它知道浏览器何时应用了更新。这可以实现以下工作流:
- 代理编辑代码
- 客服电话
wait_for_renders(可选超时) - 工具等待HMR完成和新渲染到达
- 返回新的渲染数据以供分析
提交级别分组
每个渲染报告都标记了一个React 提交ID,允许代理检查哪些组件在同一提交中一起重新呈现。客户端通过挂钩来跟踪提交 __REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberRoot,React每次提交都会同步调用一次。典型的工作流程:
- 呼叫
get_commits列出可用的提交ID - 呼叫
get_renders_by_commit使用特定ID查看该提交中的所有呈现
建筑
Browser (project-a) ──┐
Browser (project-b) ──┤
▼
MCP #1 → WS(:4649) (first instance binds, "owner")
MCP #2 → WS(:4649) → relay client ──▶ MCP #1
│
▼
~/.wdyr-mcp/
├─ renders/ (JSONL files, shared across instances)
│ ├─ http___localhost_3000.jsonl
│ └─ http___localhost_5173.jsonl
└─ snapshots/ (JSON files, named snapshots)
└─ before-fix.json- 多个MCP实例 可以同时运行。只有第一个实例(“所有者”)启动WebSocket服务器;其他客户端作为socket.io客户端连接,将命令(例如暂停/恢复)转发给所有者。所有实例共享相同的数据目录。
- 多项目支持 --每个项目由以下人员标识
location.origin。渲染数据存储在每个项目的JSONL文件中。 - 不需要守护进程 --每个MCP实例都是独立的。无论哪个实例首先启动,WebSocket服务器都会被机会主义地声明。需要WS访问的命令会转发给所有者。
- 值字典重复数据删除 --渲染报告经常重复相同的内容
prevValue/nextValue数千个条目中的对象。每个JSONL文件在其第一行存储一个内容寻址字典,将xxhash wasm哈希映射到唯一值。渲染线通过以下方式引用它们@@ref:哨兵而不是内联整个对象,大大减小了文件大小。透明地读取水合物参考值。
配置
| 环境变量 | 默认值 | 描述 |
|---|---|---|
WDYR_WS_PORT | 4649 | WebSocket服务器端口 |
许可证
麻省理工学院
