Ink
Ink 模块是 Claude Code 的终端渲染引擎核心,远超简单的 Ink 框架封装。它包含自定义 React Reconciler(reconciler.ts)、基于 Yoga 的 Flexbox 布局引擎(layout/)、双缓冲帧渲染器(renderer.ts)、ANSI 转义序列处理(Ansi.tsx)、文本测量与换行(measure-text.ts、wrap-text.ts)、终端事件系统(events/)、滚动与选择(selection.ts)、搜索高亮(searchHighlight.ts)、超链接支持(supports-hyperlinks.ts)等 40+ 个文件。它本质上是一个完整的终端 GUI 框架。
职责与设计理念
职责说明
深度定制的终端渲染引擎,基于 Yoga 布局 + React Reconciler 实现终端 UI
设计理念
终端即画布——不是在终端上"打印文本",而是在终端上"渲染界面"。双缓冲 + 差分更新 + Yoga 布局,让终端 UI 拥有与浏览器 DOM 同等的表达力。
架构决策
为什么要自己写 React Reconciler 而不是直接用 blessed/ink?
自定义 Reconciler + Yoga 布局 + 双缓冲渲染
blessed 是命令式 API,与 React 声明式范式冲突。原版 Ink 的渲染性能不满足 Claude Code 的需求(长对话、大 diff、实时流式输出)。自定义 Reconciler 让团队完全控制渲染管线,实现帧间缓存、脏帧检测等优化。
⚖️ 维护成本极高——相当于维护一个终端浏览器引擎。但对于 Claude Code 这种重度终端应用,性能收益远超维护成本。
为什么用双缓冲而不是直接写入终端?
前后帧双缓冲 + 差分输出
直接写入终端会产生闪烁(先清屏再写入的间隙可见)。双缓冲在内存中完成新帧渲染,然后只输出与旧帧的差异部分,消除闪烁且减少 I/O 量。
文件清单
| 文件名 | 用途 |
|---|---|
| renderer.ts | 双缓冲帧渲染器,管理前后帧切换和差分输出 |
| reconciler.ts | 自定义 React Reconciler,桥接 React 虚拟 DOM 与终端 DOM |
| dom.ts | 终端 DOM 实现,定义 DOMElement/TextNode 节点模型 |
| render-node-to-output.ts | 节点渲染管线,将 DOM 树转换为屏幕缓冲区 |
| output.ts | 屏幕输出缓冲区,管理字符网格和样式属性 |
| layout/ | Yoga Flexbox 布局引擎适配层 |
| components/ | 内置终端组件(ScrollBox、Box、Text 等) |
| events/ | 终端事件系统,处理键盘、鼠标、焦点事件 |
使用场景
每个 token 到达时触发 React 重渲染,Reconciler 计算最小 DOM 变更,渲染器输出差分
API Stream → React setState → Reconciler diff → Renderer 差分输出
Yoga 重新计算所有节点的 Flexbox 布局,渲染器输出完整新帧
依赖关系
无外部模块依赖
关键代码片段
双缓冲渲染器
export default function createRenderer(
node: DOMElement, stylePool: StylePool
): Renderer {
let output: Output | undefined
return (options) => {
const { frontFrame, backFrame, terminalWidth } = options
// 复用 Output 的 charCache(tokenize + grapheme clustering)
if (output) output.reset(width, height, screen)
else output = new Output({ width, height, stylePool, screen })
renderNodeToOutput(node, output, {
prevScreen: options.prevFrameContaminated
? undefined : prevScreen,
})
return { screen: output.get(), viewport, cursor }
}
} 双缓冲 + 帧间缓存复用 + 脏帧检测,实现高性能终端渲染
自定义 React Reconciler
// 桥接 React 虚拟 DOM 与终端 DOM
const reconciler = ReactReconciler({
createInstance(type, props) {
// React 创建元素 → 终端 DOMElement
return new DOMElement(type, props)
},
appendChildToContainer(container, child) {
container.appendChild(child)
// 触发 Yoga 重新布局
container.yogaNode.markDirty()
},
commitUpdate(instance, updatePayload) {
// React 更新 → 终端 DOM 属性更新
instance.applyProps(updatePayload)
},
}) React Reconciler 将 JSX 声明式 UI 翻译为终端 DOM 操作,Yoga 处理布局
技术笔记
charCache 缓存策略
Output 对象的 charCache 缓存了 tokenize 和 grapheme clustering 的结果。大多数行在帧间不变,缓存命中率通常 > 90%,显著减少 CPU 开销。
Unicode 宽字符处理
measure-text.ts 使用 grapheme clustering 正确处理 emoji、CJK 字符等宽字符的终端列宽计算,避免布局错位。