Deep Dive | src/native-ts/yoga-layout/index.ts 2578 行 — Yoga Flexbox TS 实现¶
重要性:⭐⭐⭐(Ink UI 布局引擎——React/Ink 终端 UI 渲染基础) 真实位置:
src/native-ts/yoga-layout/index.ts(2578 行) 角色:Facebook Yoga flexbox 引擎的 纯 TypeScript 移植版——为 Ink 提供 flexbox 布局 关联:topics/deep-dive-prompt-input.md(使用 Yoga)、Ink 文档
1. 文件全景¶
yoga-layout/index.ts (2578 行)
│
├── 行 1-100 :imports + 类型 + helper
│ ├── 60+ exports (行 60)
│ ├── Value type (行 82)
│ ├── pointValue / percentValue (行 90, 93)
│ ├── resolveValue (行 97)
│ ├── isDefined / sameFloat (行 108, 113)
│
├── 行 120-220:Layout + Style
│ ├── Layout type (行 120)
│ ├── Style type (行 134, ~33 行)
│ ├── defaultStyle (行 167)
│ └── EDGE_* 常量 (行 199-202)
│
├── 行 204-310:Edge 解析
│ ├── resolveEdge (行 204, ~30 行)
│ ├── resolveEdgeRaw (行 233)
│ ├── isMarginAuto / hasAnyAutoEdge / hasAnyDefinedEdge
│ └── resolveEdges4Into (行 269, ~45 行)
│
├── 行 312-355:Direction helpers
│ ├── isRow / isReverse (行 312, 315)
│ ├── crossAxis (行 318)
│ ├── leadingEdge / trailingEdge (行 321, 333)
│
├── 行 349-403:Types + Config
│ ├── MeasureFunction type (行 349)
│ ├── Size type (行 356)
│ ├── Config type (行 361, ~13 行)
│ └── createConfig (行 374, ~30 行)
│
├── 行 403-965:**Node class (行 403, ~560 行)** — 核心 class
│ ├── 构造 + clone
│ ├── style setters/getters (flex, justify, align, ...)
│ ├── layout 计算
│ └── measure / baseline
│
├── 行 966-1100:Cache + Global
│ ├── DEFAULT_CONFIG (行 966)
│ ├── CACHE_SLOTS = 4 (行 968)
│ ├── cacheWrite (行 969, ~53 行)
│ ├── commitCacheOutputs (行 1022, ~22 行)
│ ├── getYogaCounters (行 1044, ~14 行)
│
├── 行 1058-1903:**layoutNode (行 1058, ~850 行)** — 主布局算法
│
├── 行 1904-2050:Absolute 定位
│ ├── layoutAbsoluteChild (行 1904, ~120 行)
│ ├── justifyAbsolute (行 2023)
│ ├── alignAbsolute (行 2039, ~20 行)
│
├── 行 2059-2300:Flex 解析
│ ├── computeFlexBasis (行 2059, ~115 行)
│ ├── hasMeasureFuncInSubtree (行 2174)
│ ├── resolveFlexibleLengths (行 2182, ~100 行)
│ ├── isStretchAlign (行 2284)
│ ├── resolveChildAlign (行 2294)
│
├── 行 2304-2350:Baseline
│ ├── calculateBaseline (行 2304, ~20 行)
│ ├── isBaselineLayout (行 2325)
│
└── 行 2334-2578:边距 + 边界
├── childMarginForAxis (行 2334)
├── resolveGap (行 2345)
├── boundAxis (行 2352, ~33 行)
└── zeroLayoutRecursive (行 2386)
2. 60+ Exports(行 60)¶
文件顶部 60+ exports —— 暴露给 Ink 的 API。
典型 export:
- Node (class)
- Value (type)
- createConfig (function)
- getYogaCounters (function)
- 所有 Yoga 常量
3. Value 类型¶
4 种单位:
- point —— 像素 / 字符数
- percent —— 百分比
- auto —— 自动
- undefined —— 未设置
3 个 helper:
- pointValue(v) —— 创建 point
- percentValue(v) —— 创建 percent
- resolveValue(v, ownerSize) —— 解析为绝对值
4. Style 类型 — 33 行¶
type Style = {
flexDirection: FlexDirection
justifyContent: JustifyContent
alignItems: Align
alignSelf: Align
alignContent: Align
flexWrap: Wrap
flexGrow: number
flexShrink: number
flexBasis: Value
// ... ~25 个字段
}
~25 个字段 —— 标准 Yoga flexbox 属性。
5. EDGE 常量 + 解析¶
4 个边 + resolveEdge 把逻辑边(start/end)映射到物理边(left/right)。
支持 RTL —— direction: 'rtl' 时,start = right。
6. createConfig — 30 行(行 374)¶
Config —— 错误容忍、点精度等。
7. Node class — 560 行(行 403-965)¶
核心 class —— 每个 React/Ink 组件对应一个 Node。
export class Node {
// 行 403
// 1. 构造
constructor(config?: Config)
// 2. style setters/getters
setFlexDirection(d)
setJustifyContent(j)
setAlignItems(a)
// ... 25+ setter
// 3. child 管理
insertChild(child, index)
removeChild(child)
// 4. 计算触发
calculateLayout(...)
// 5. 内部 layout
layout(...)
}
560 行 —— 包含所有 setter + 内部布局调用。
8. 4-Cache 系统¶
4-slot LRU 缓存——避免重复 layout 计算。
为什么 4: - 4 足够覆盖 99% 场景 - 多于 4 → 命中率提升小但内存大
9. getYogaCounters¶
性能监控 —— 暴露给上层 metrics。
10. layoutNode — 850 行核心(行 1058-1903)¶
850 行 —— 完整 flexbox 布局算法。
包含: - 单节点布局 - Flex line 计算 - Absolute 定位 - Justify / Align - 边距 / 间距 - 测量函数
11. layoutAbsoluteChild — 120 行(行 1904)¶
Absolute 定位 —— position: 'absolute'。
12. justifyAbsolute + alignAbsolute¶
2 个 helper —— 绝对定位的 justify / align。
13. computeFlexBasis — 115 行(行 2059)¶
115 行 —— flex basis 计算(flex-grow / flex-shrink / flex-basis 之前的初始大小)。
14. resolveFlexibleLengths — 100 行(行 2182)¶
Flex 分配 —— 剩余空间按 flex-grow / flex-shrink 分配。
15. calculateBaseline + isBaselineLayout¶
2 个 baseline helper —— baseline 对齐(少见但支持)。
16. boundAxis — 33 行(行 2352)¶
轴边界 —— min-width / max-width 等。
17. 关键设计模式¶
17.1 纯 TS 移植¶
整个 Yoga 引擎是纯 TypeScript——无 WASM / N-API。
为什么: - 启动快(无 native load) - 跨平台无坑 - 调试容易
17.2 4-slot LRU 缓存¶
CACHE_SLOTS = 4 —— 平衡内存和命中率。
17.3 Value 抽象¶
Value 类型支持 point / percent / auto —— 统一表示。
17.4 Edge 抽象¶
resolveEdge 处理 RTL / LTR —— 国际化友好。
17.5 Measure function¶
测量回调 —— 用于 dynamic content(文字宽度)。
17.6 Config 默认¶
createConfig() —— 用户可覆盖 pointScaleFactor、webDefaults 等。
17.7 性能 metrics¶
getYogaCounters —— 暴露内部 metrics(layouts、cacheHits)给上层。
17.8 560 行 Node class¶
所有 style setter 集中 —— API 简单,调用方不需要理解算法。
17.9 850 行 layoutNode¶
算法集中 —— 单函数可单元测试。
18. 复杂度分析¶
| 维度 | 数字 |
|---|---|
| 总行数 | 2578 |
| Exports | 60+ |
| Style 字段 | ~25 |
| Node class | 560 行 |
| layoutNode | 850 行 |
| Cache slots | 4 |
| 边类型 | 4 (LTR + RTL 各 4) |
19. 性能特征¶
19.1 单次 layout¶
- 简单布局:< 1ms
- 中等(10 节点):~1-5ms
- 复杂(100 节点):~10-50ms
- 病态(嵌套深):~50-100ms
19.2 缓存¶
- 4-slot LRU:命中率 ~80% (典型 UI)
- 未命中:重新 layout(~1-50ms)
19.3 优化¶
- 4-slot cache
- 早期退出(叶子节点)
- flex basis 一次计算
20. 与其他文件的关系¶
yoga-layout/index.ts
├──→ React/Ink (直接 import)
├──→ components/... (Ink 组件用 Yoga)
└──→ native-ts/... (其他 native 绑定)
yoga-layout 是"布局算法"——Ink 用它布局。
21. 关键洞察¶
21.1 纯 TS 移植 = 跨平台¶
无 N-API / WASM —— 任何平台都能跑。
21.2 850 行 layoutNode 是"算法集中"¶
易测试 / 易理解 / 易优化。
21.3 4-slot cache 平衡¶
80% 命中率 + 极少内存。
21.4 Value 抽象统一表示¶
point / percent / auto / undefined —— 4 种单位一 type。
21.5 Edge 抽象支持 RTL¶
start / end 而不是 left / right —— 国际化。
21.6 Measure function 支持动态¶
文字宽度 / 异步内容 —— 用回调延后决定。
21.7 Yoga = 工业级 flexbox¶
Facebook 开源,无数应用验证。
21.8 In-terminal 也要 flexbox¶
终端 UI 同样需要布局 —— Yoga 让 CLI 也能 flexbox。
22. 阅读建议¶
- 看 Value type(行 82)—— 单位抽象
- 看 Style type(行 134)—— 25+ 属性
- 看 Node class(行 403)—— API
- 看 4-slot cache(行 968)
- 看 layoutNode 850 行(行 1058)—— 主算法
23. 与其他深度拆解的关系¶
| 文件 | 关系 |
|---|---|
Ink 框架 |
用 Yoga |
components/... |
Ink 组件(用 Yoga) |
24. 阅读清单¶
- ✅ 看 Value type(行 82)
- ✅ 看 Style type(行 134)
- ✅ 看 Node class(行 403)
- ✅ 看 layoutNode(行 1058)
- 📌 跑一个 Ink 组件看实际布局
25. 练习任务¶
- 数 exports(grep
^export)—— 60+ - 数 Style 字段(grep in Style type)—— ~25
- 看 cache 4-slot 命中逻辑(行 968-1022)
- 手写迷你 Yoga(~100 行)—— flex 横向布局
- 思考:为什么 4-slot cache?多于 4 不好吗?