2026-05-29 学习日志
今日主题
- React TUI 架构
- Solid.js 核心理念
- JSX 编译与自定义运行时
- CC Bypass 权限模式的三层 CLI 参数关系
- CC CLI 参数与 settings 的映射不对称
- Hono JSX 实现原理
- 终端 UI 渲染原理
新增认知
React TUI 架构
-
OpenTUI 的 Zig-TS 分层架构:核心渲染引擎用 Zig(系统级语言)编写,
负责 ANSI 转义码输出、Yoga Flexbox 布局、Tree-sitter 语法高亮、键盘输入等底层操作。Zig 编译后暴露 C ABI,
@opentui/core 通过 FFI 调用这个原生库,@opentui/react 再封装成 React 组件。用户写 React 组件,
内部最终由 Zig 原生代码渲染到终端。对比 Ink(纯 JS),OpenTUI 的代价是安装需要本机装 Zig 编译器来 build 原生模块。 -
React Renderer 的可替换设计:React 设计时就把 reconciler(协调器,
管理 state/hooks/fiber/diff)和 renderer(渲染器)分离。react-dom 输出 DOM 操作,
react-native 输出原生控件,ink 和 @opentui/react 输出 ANSI 终端序列——React 核心完全不变,
useState/useEffect/Fiber 调度都在,只是对宿主环境的操作被替换了。这意味着学习一次 React,就能在不同渲染目标上复用。
Solid.js 核心理念
- Solid 与 React 的本质区别:React 每次状态变化都重新执行组件函数并 Virtual DOM diff;Solid 组件函数只执行一次,
用 Signals 做细粒度响应式更新,无 Virtual DOM,直接编译成精准的 DOM 操作。写法(JSX)几乎一样,但底层理念相反——
React 是重新运行再 diff,Solid 是运行一次然后按需更新。
JSX 编译与自定义运行时
-
JSX 编译模式 5 种取值:tsconfig 的 jsx 字段有 5 个值——react(经典,
编译为 React.createElement)、react-jsx(自动,编译为 jsx 运行时调用,
无需手动 import React)、react-jsxdev(同 react-jsx 但注入调试信息)、preserve(保留 JSX 不转换,
交由其他编译器处理)、react-native(同 preserve 但输出 .js)。现代项目一般用 react-jsx。 -
JSX 本质是函数调用语法糖:JSX 只是 fn(name, props, ...children) 的语法糖,
fn 指向谁由 tsconfig 的 jsxFactory(经典模式)或 jsxImportSource(自动模式)控制。
这意味着可以用 JSX 语法生成任意数据结构,不限于 DOM——Ink 用它生成终端输出就是典型例子。
自动模式下只需导出 jsx(type, props, key?) 和 jsxs(type, props, key?) 两个函数即可接管 JSX 编译结果。
CC Bypass 权限模式的三层 CLI 参数关系
-
激活 vs 解锁是两层独立机制:
--dangerously-skip-permissions 和 --permission-mode bypassPermissions 都直接激活 bypass 模式,
区别仅在前者优先级更高(在 orderedModes 数组中最先检查)。
--allow-dangerously-skip-permissions 不激活 bypass,
只设置 allowDangerouslySkipPermissions=true,
使 isBypassPermissionsModeAvailable 为 true,从而在 Shift+Tab 模式循环中解锁 bypass 选项。
判断逻辑在 permissionSetup.ts:939-943,
allowDangerouslySkipPermissions 和当前已是 bypass 模式两者任一为真即视为 bypass 可用。 -
解锁 bypass 不等于绕过安全检查:
即使只传 --allow-dangerously-skip-permissions 而未实际进入 bypass 模式,
setup.ts:396-441 的安全环境检查(root 检测、Ant 员工的 Docker/沙盒+断网检测)仍会执行,
interactiveHelpers.tsx:218 的危险警告弹窗也会显示。源码注释确认这是有意设计——
CCD 无条件传此 flag 以解锁会话中切换 bypass 的能力。
CC CLI 参数与 settings 的映射不对称
- 并非所有 CLI flag 都有 settings.json 等价项:
--permission-mode 对应 permissions.defaultMode,
--dangerously-skip-permissions 的效果也可通过 permissions.defaultMode: "bypassPermissions" 实现。
但 --allow-dangerously-skip-permissions 在 settings 中无对应字段——
permissions 下只有 defaultMode、disableBypassPermissionsMode、additionalDirectories 等,
没有 allowDangerouslySkipPermissions 或类似选项。这意味着"解锁 bypass 但不默认激活"的行为只能在启动命令上配置,
无法下沉到 settings.json。
Hono JSX 实现原理
-
JSX 服务端渲染无需 VDOM:
Hono 的 hono/jsx 运行时证明服务端 JSX 可以不依赖虚拟 DOM diff 和 reconciliation。
jsx() 函数仅创建持有 tag/props/children 的 JSXNode 对象;调用 .toString() 时才递归拼接 HTML 字符串。
本质是把 JSX 当作类型安全的模板字面量,无运行时开销。前提:仅适用于服务端一次性渲染场景,
客户端需要交互式更新时仍需 hono/jsx/dom 这类带 reconcile 的运行时。 -
编译器导入路径是固定契约:TypeScript 编译器只提供 jsxImportSource 一个配置项来控制 JSX 运行时来源。
具体路径(/jsx-runtime 或 /jsx-dev-runtime)和导出名称(jsx、jsxs、Fragment)均为编译器写死。
开发者能做的就是在对应路径下导出符合签名的函数,把编译器的 JSX 调用导向自己的实现。
这个契约使得任何库只需在指定位置提供三个导出即可"接管"JSX 编译产物。
终端 UI 渲染原理
-
React TUI 的渲染本质是输出 ANSI 序列到 stdout:浏览器中 react-dom 操作 DOM 树,由浏览器引擎绘制像素;
TUI 中没有 DOM,renderer(ink/@opentui/react)将 React 组件树翻译成 ANSI 转义序列,
通过 process.stdout.write 输出到终端,终端模拟器(iTerm 等)解析后显示为彩色字符界面。画布本质是一个字符网格,
更新时用 ANSI 控制码移动光标、改色、清行来重写对应位置的字符,而非增减 DOM 节点。 -
Docker 容器内无法运行 TUI:TUI 依赖 stdout 字符流 + ANSI 控制序列 + stdin 原始按键输入,
Docker 默认 -it 模式下伪终端才提供这些。若不分配伪终端(如 CI 环境),stdout 只是纯文本流,ANSI 控制码失效或显示乱码。
浏览器环境(无终端模拟器)同样无法渲染 TUI。