消息渲染
概述
消息渲染是 Claude Code 终端 UI 中最性能敏感的部分。长对话可能包含数百条消息,每条消息包含文本、代码块、工具调用等复杂内容。
Source:
src/components/Messages.tsx,src/components/VirtualMessageList.tsx
VirtualMessageList — 虚拟滚动列表
Source:
src/components/VirtualMessageList.tsx(1081 行)
JumpHandle 接口
typescript
type JumpHandle = {
jumpToIndex(i: number) // 跳转到指定消息
setSearchQuery(q: string) // 设置搜索查询
nextMatch() // 下一个匹配
prevMatch() // 上一个匹配
setAnchor() // 捕获滚动位置
warmSearchIndex(): Promise<number> // 预热搜索索引
disarmSearch() // 清除位置高亮
}高度缓存
typescript
// 按消息 + 终端宽度缓存高度
// 终端调整大小时失效
heightCache: Map<string, number>搜索优化
typescript
// WeakMap 自动 GC 被替换的消息
const fallbackLowerCache = new WeakMap<RenderableMessage, string>();
// 每次按键只做 indexOf(零 toLowerCase 分配)
function search(msg: RenderableMessage, query: string): boolean {
let lower = fallbackLowerCache.get(msg);
if (!lower) {
lower = extractSearchText(msg).toLowerCase();
fallbackLowerCache.set(msg, lower);
}
return lower.indexOf(query) !== -1;
}Messages 组件
Source:
src/components/Messages.tsx(400+ 行)
LogoHeader 记忆化
typescript
// React.memo 避免 logo 子树触发级联重渲染
const LogoHeader = React.memo(({ agentDefinitions }) => {
// 如果 logo 变脏,renderChildren 设置 seenDirtyChild=true
// 禁用后续兄弟节点的 prevScreen blit
// 长对话中可能导致 150K+ 写/帧
return <LogoV2 agentDefinitions={agentDefinitions} />;
});Brief 模式过滤
typescript
function filterForBriefTool(messages, briefToolNames) {
// Brief-only 模式:
// 只保留 Brief tool_use 块 + 结果 + 真实用户输入
// 过滤所有助手文本
// 跳过 api_metrics 系统消息
}消息处理管线
typescript
// 标准化 → 构建索引 → 排序 → 过滤
normalizeMessages(rawMessages) // 扁平化消息结构
buildMessageLookups(messages) // 创建工具结果索引
reorderMessagesInUI(messages) // UI 排序
shouldShowUserMessage(msg) // 过滤谓词MessageRow 组件
每条消息由 MessageRow 渲染,根据消息类型选择不同的渲染器:
| 消息类型 | 渲染内容 |
|---|---|
| 用户消息 | 用户输入文本 |
| 助手文本 | Markdown 渲染的回复 |
| 工具调用 | 工具名称 + 参数 + 权限状态 |
| 工具结果 | 执行输出(代码、文件内容等) |
| 系统消息 | 系统通知 |
| 思考块 | 折叠的思考过程 |
性能策略
1. 虚拟滚动
只渲染视口内可见的消息,不渲染视口外的内容。
2. 高度缓存
预计算每条消息的渲染高度,避免重复布局计算。
3. WeakMap 搜索缓存
使用 WeakMap 缓存搜索文本的小写版本。当消息被压缩替换时,旧缓存自动被 GC。
4. LogoHeader 隔离
将 Logo 组件用 React.memo 隔离,防止它变脏时导致级联重渲染。
5. 粘性滚动
typescript
// 自动锚定到底部
stickyScroll: true
// 新消息到来时自动滚动下一步
- 组件体系 — 设计系统组件