首页
/ Cline 仓库中的 OpenTUI Solid Reconciler 配置全解:从 create-tui 脚手架到单文件可执行构建

Cline 仓库中的 OpenTUI Solid Reconciler 配置全解:从 create-tui 脚手架到单文件可执行构建

2026-09-04 09:14:09作者:卓艾滢Kingsley

本篇以 Cline 仓库内置的 OpenTUI 技能参考文档 .agents/skills/opentui/references/solid/configuration.md 为主体,系统讲解使用 Solid 版本 OpenTUI(@opentui/solid)搭建终端 UI 项目所需的完整工程配置:create-tui 脚手架与手动搭建、tsconfig/bunfig/package.json 三个关键配置文件、render() 渲染器选项、Bun.build 打包与跨平台可执行文件生成、环境变量与测试配置,以及三类高频配置故障的排查方法。读完后你可以从零创建一个可运行、可测试、可分发的 Solid TUI 应用,并理解每一项配置背后 Solid JSX 编译器的实际工作机制。

OpenTUI Solid 在 Cline 仓库中的位置

Cline 仓库在 .agents/skills/opentui/ 目录下维护了一套面向终端 UI 开发的技能参考体系。其入口 .agents/skills/opentui/SKILL.md 将 OpenTUI 的三层框架划分为 core(命令式 API)、react(React reconciler)与 solid(Solid reconciler),并规定每个框架参考遵循五文件结构:REFERENCE.md(总览)、api.md(运行时 API)、configuration.md(工程配置)、patterns.md(常见模式)、gotchas.md(坑点与调试)。

Solid 框架参考总览给出的选型结论是:当需要最优重渲染性能、基于 signal 的细粒度响应式控制,或构建性能敏感型终端应用时选择 solid/;若团队熟悉 React 则选 @opentui/react,需要最大控制力或构建底层框架/库时则直接使用命令式 @opentui/core

值得注意的是,Cline 自身的 CLI 应用正是基于同一套 OpenTUI 体系构建的,只是采用了 React 变体。apps/cli/tsconfig.json 中的关键配置:

"jsx": "react-jsx",
"jsxImportSource": "@opentui/react"

apps/cli/src/tui/index.tsx 通过 createCliRenderer 创建渲染器并挂载 CLI 界面,其依赖声明见 apps/cli/package.json@opentui/core@opentui/react 均为 0.4.3)。这印证了本文档所讲的配置模式是 OpenTUI 官方推荐的通用工程范式——React 变体与 Solid 变体在配置思路上同构,仅 JSX 入口包不同。

项目搭建:create-tui 脚手架

快速开始

文档给出的标准启动方式是一行命令:

bunx create-tui@latest -t solid my-app
cd my-app && bun install

使用上的硬性约束与可选项:

  • 目标目录 my-app 不能已存在,CLI 会替你创建该目录;
  • 选项 --no-git 跳过 git 初始化,--no-install 跳过 bun install;
  • SKILL.md 的 Critical Rules,create-tui 的选项必须放在参数之前:bunx create-tui -t react my-app 合法,bunx create-tui my-app -t react 不合法。该文档还特别提示 Agent 场景下应始终使用 -t <template> 自动模式,避免进入交互式提示(Agent 无法应答交互)。

手动搭建

如果不想用脚手架,手动安装三个核心依赖即可:

mkdir my-tui && cd my-tui
bun init
bun install @opentui/solid @opentui/core solid-js

三者缺一不可:@opentui/core 提供渲染器与所有底层 renderable 原语,solid-js 提供 signal/store 等响应式运行时,@opentui/solid 则是把 Solid 组件树 reconcile 到 OpenTUI renderable 的桥接层,并附带 JSX 编译预加载器与 Bun 构建插件。

TypeScript 配置

tsconfig.json 完整示例

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    "jsx": "preserve",
    "jsxImportSource": "@opentui/solid",

    "strict": true,
    "skipLibCheck": true,
    "noEmit": true,
    "types": ["bun-types"]
  },
  "include": ["src/**/*"]
}

文档标注的三个关键设置及其原理:

  • jsx: "preserve" —— TypeScript 不转换 JSX,原样保留,交给 Solid 编译器处理。Solid 的响应式模型依赖编译期静态分析:<text>Count: {count()}</text> 中的 count() 调用会在编译后被替换为 createComputed 依赖跟踪结构,而非运行时虚拟 DOM diff。若此处写成 react-jsxpreserve + 错误 importSource,JSX 会被转成 React 的 jsx() 调用,运行时报 "React not found"。
  • jsxImportSource: "@opentui/solid" —— 指定 JSX runtime 的导入来源。OpenTUI Solid 在此暴露了自己的 JSX 类型定义与 intrinsics(<text><box><input><tab_select> 等),编译器据此把 JSX 元素映射到 OpenTUI renderable,而不是 DOM 元素。
  • module / moduleResolution: "NodeNext" —— 文档推荐用于 OpenTUI 兼容性。Bun 运行时下这保证了 ESM 语义("type": "module" 项目)与子路径导出(如 @opentui/solid/preload@opentui/solid/bun-plugin)能被正确解析。

对照 Cline CLI 的 apps/cli/tsconfig.json:它使用 "jsx": "react-jsx" + "jsxImportSource": "@opentui/react",结构完全同构,只是 importSource 换成 React 桥接包。此外 Solid 参考文档中的 gotchas.md 也反复强调:JSX 配置错误(编译成 React 调用)的典型症状是 "React not found" 类报错,修复方式就是把上面两项设置补全。

Bun 配置:bunfig.toml 预加载

这是 Solid 变体与 React 变体在工程配置上差异最大的一点。项目根目录必须有:

preload = ["@opentui/solid/preload"]

该 preload 让 Bun 在加载你的任何代码之前先注册 Solid 的 JSX 变换器,之后每个 .tsx 文件在运行时被 Bun 的 loader 链自动编译。文档将缺失此配置列为头号故障:症状是 SyntaxError: Unexpected token '<' 等 JSX 语法错误、组件不渲染;gotchas.md 中同样将其标记为 "Configuration Issues" 的第一条。

可以对照仓库内的同类用法来理解 preload 机制:apps/vscode/bunfig.toml 也使用了 preload 字段,只不过预加载的是测试桩替换脚本 ./src/test/bun-test-preload.ts——同一个机制,不同的预加载目标。

package.json 配置

文档给出的完整示例:

{
  "name": "my-tui-app",
  "type": "module",
  "scripts": {
    "start": "bun run src/index.tsx",
    "dev": "bun --watch run src/index.tsx",
    "test": "bun test",
    "build": "bun run build.ts"
  },
  "dependencies": {
    "@opentui/core": "latest",
    "@opentui/solid": "latest",
    "solid-js": "latest"
  },
  "devDependencies": {
    "@types/bun": "latest",
    "typescript": "latest"
  }
}

要点:

  • "type": "module" 配合 NodeNext 模块解析;
  • dev 脚本用 bun --watch 实现热重载开发循环;
  • start 必须走 bun rungotchas.md 明确警告不要用 node src/index.tsxnpm run start 绕过 Bun,因为 preload 机制由 Bun 运行时提供;
  • 生产依赖建议锁定版本(示例中的 latest 是脚手架起步写法,实际项目应按 Cline CLI 那样钉住具体版本,如 0.4.3)。

推荐项目结构与入口代码

文档推荐的结构:

my-tui-app/
├── src/
│   ├── components/
│   │   ├── Header.tsx
│   │   ├── Sidebar.tsx
│   │   └── MainContent.tsx
│   ├── stores/
│   │   └── appStore.ts
│   ├── App.tsx
│   └── index.tsx
├── bunfig.toml           # Required!
├── package.json
└── tsconfig.json

bunfig.toml 被单独标注 # Required!,因为如前所述它是 Solid 编译链的开关。

入口文件 src/index.tsx

import { render } from "@opentui/solid"
import { App } from "./App"

render(() => <App />)

render 接受一个返回 JSX 元素的函数(而非元素本身),因为 Solid 需要在自身作用域内建立响应式根;当内部需要创建渲染器时它是异步的,Bun 的 top-level await 让这一调用无需额外包装。

App 组件 src/App.tsx

import { Header } from "./components/Header"
import { Sidebar } from "./components/Sidebar"
import { MainContent } from "./components/MainContent"

export function App() {
  return (
    <box flexDirection="column" width="100%" height="100%">
      <Header />
      <box flexDirection="row" flexGrow={1}>
        <Sidebar />
        <MainContent />
      </box>
    </box>
  )
}

这里体现了 OpenTUI 的 Yoga/Flexbox 布局模型:<box> 是容器 renderable,flexDirectionflexGrow 等属性直接对应 flex 布局——终端窗口就是根容器,占满 100% 宽高后内部再行内分栏。

渲染器配置

render() 选项详解

import { render } from "@opentui/solid"
import { ConsolePosition } from "@opentui/core"

render(() => <App />, {
  // Rendering
  targetFPS: 60,

  // Behavior
  exitOnCtrlC: true,
  autoFocus: true,          // Auto-focus elements on click (default: true)
  useMouse: true,           // Enable mouse support (default: true)

  // Debug console
  consoleOptions: {
    position: ConsolePosition.BOTTOM,
    sizePercent: 30,
    startInDebugMode: false,
  },

  // Cleanup
  onDestroy: () => {
    // Cleanup code
  },
})

各选项的实际影响:

选项 说明
targetFPS 渲染循环目标帧率,终端 TUI 建议 60;帧率控制重绘节奏,直接影响动画流畅度
exitOnCtrlC 是否捕获 Ctrl+C 触发退出流程
autoFocus / useMouse 两者默认均为 true;前者让点击元素自动获得焦点,后者开启鼠标事件(onMouseDown 等)
consoleOptions OpenTUI 会捕获 console 输出并在界面内展示调试控制台,可配置位置(ConsolePosition.BOTTOM)、占屏比例(sizePercent: 30 即 30%)与是否启动即进入调试模式
onDestroy 渲染器销毁回调,是注册退出清理逻辑的正确位置

复用已有渲染器

当渲染器已被外部创建(例如测试环境、嵌入宿主、或需要先配置再挂载)时,直接把 renderer 实例传给 render 的第二个参数:

import { render } from "@opentui/solid"
import { createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer({
  exitOnCtrlC: false,
})

render(() => <App />, renderer)

这正是 Cline CLI 的用法:apps/cli/src/tui/index.tsxawait createCliRenderer({...}) 再挂载 React 组件树;其单测 apps/cli/src/tui/index.test.ts 中甚至直接 mock 了 createCliRenderer,可见"renderer 与组件树解耦"是框架刻意支持的一等公民能力,Solid 变体完全同理。

构建与分发

普通构建脚本

开发时 preload 在运行时完成 JSX 编译;但打包分发时必须在构建期内完成变换,靠的是 @opentui/solid/bun-plugin

// build.ts
import solidPlugin from "@opentui/solid/bun-plugin"

await Bun.build({
  entrypoints: ["./src/index.tsx"],
  outdir: "./dist",
  target: "bun",
  minify: true,
  plugins: [solidPlugin],
})

console.log("Build complete!")

运行 bun run build.ts。遗漏该插件的症状是产物中残留未变换的 JSX(gotchas.md 将其列为 Build Without Plugin),产物在非 Bun 预加载环境下必然崩溃。

编译为单文件可执行

利用 compile 选项可以把应用连同 Bun 运行时一起编译成跨平台单文件可执行程序:

import solidPlugin from "@opentui/solid/bun-plugin"

await Bun.build({
  entrypoints: ["./src/index.tsx"],
  target: "bun",
  plugins: [solidPlugin],
  compile: {
    target: "bun-darwin-arm64",  // or bun-linux-x64, etc.
    outfile: "my-app",
  },
})

文档列出的可用目标:

  • bun-darwin-arm64 — macOS Apple Silicon
  • bun-darwin-x64 — macOS Intel
  • bun-linux-x64 — Linux x64
  • bun-linux-arm64 — Linux ARM64
  • bun-windows-x64 — Windows x64

注意 compile 模式下产物是二进制,依赖 Bun 运行时被内联,因此入口文件中的 preload 机制不再参与——这再次说明必须依赖构建期的 solidPlugin 完成 JSX 变换,两者不可互相替代。

环境变量

开发期创建 .env 文件:

# Debug settings
OTUI_SHOW_STATS=false
SHOW_CONSOLE=false

# App settings
API_URL=https://api.example.com

Bun 会自动加载 .env 文件,代码中直接读取:

const apiUrl = process.env.API_URL

前两个变量是 OpenTUI 的调试开关:OTUI_SHOW_STATS 控制帧率/统计信息展示,SHOW_CONSOLE 控制是否显示内置调试控制台——与 render()consoleOptions 形成互补(一个从代码侧、一个从环境侧控制)。

测试配置

测试工具封装

OpenTUI 为测试提供 testRender,文档建议封装一个统一的测试渲染入口:

// src/test-utils.tsx
import { testRender } from "@opentui/solid"

export async function renderForTest(
  Component: () => JSX.Element,
  options = { width: 80, height: 24 }
) {
  return await testRender(Component, options)
}

width/height 指定虚拟终端尺寸(默认 80x24),这是终端 UI 快照测试的基础——所有布局断言都依赖确定的终端几何尺寸。

快照测试示例

// src/components/Counter.test.tsx
import { test, expect } from "bun:test"
import { renderForTest } from "../test-utils"
import { Counter } from "./Counter"

test("Counter renders initial value", async () => {
  const { snapshot } = await renderForTest(() => <Counter initialValue={5} />)
  expect(snapshot()).toContain("Count: 5")
})

snapshot() 返回当前帧的文本快照,配合 toContain 即可对渲染结果做内容断言。更完整的快照/交互测试方法可参考仓库内 testing/REFERENCE.md

常见配置问题排查

文档"Common Configuration Issues"一节归纳了三类故障,与 solid/gotchas.md 的 Configuration Issues 章节一一对应:

1. 缺失 bunfig.toml

  • 症状:JSX 未被变换,报语法错误(如 SyntaxError: Unexpected token '<'
  • 原因:Bun 未预加载 Solid 变换器
  • 修复:创建 bunfig.toml 并写入 preload = ["@opentui/solid/preload"]

2. JSX 设置错误

  • 症状:JSX 被编译成 React 调用,运行时报 "React not found"
  • 原因jsx/jsxImportSource 指向了 React 而非 OpenTUI Solid
  • 修复:确认 tsconfig 包含 "jsx": "preserve""jsxImportSource": "@opentui/solid"

3. 构建缺少插件

  • 症状:打包产物中包含未变换的原始 JSX
  • 原因Bun.build 未挂 solidPlugin
  • 修复
import solidPlugin from "@opentui/solid/bun-plugin"

await Bun.build({
  // ...
  plugins: [solidPlugin],
})

三条规则的本质是同一件事:Solid 的 JSX 必须经过 OpenTUI 的专用变换(运行时靠 preload、构建期靠 bun-plugin、类型期靠 jsxImportSource),任何一环缺失都会让 <text><box> 这些自定义元素失去正确语义。

小结

@opentui/solid 的工程配置可以浓缩为一张检查清单:

  1. 脚手架bunx create-tui@latest -t solid my-app(选项在前,目录不存在),或手动 bun install @opentui/solid @opentui/core solid-js
  2. tsconfig.jsonjsx: "preserve" + jsxImportSource: "@opentui/solid" + NodeNext 模块解析;
  3. bunfig.tomlpreload = ["@opentui/solid/preload"],运行时编译的开关;
  4. package.json"type": "module",所有脚本走 bun run
  5. render():按需配置 targetFPSautoFocususeMouseconsoleOptionsonDestroy;已有 renderer 实例则作为第二参数传入;
  6. 构建Bun.build 必须挂 @opentui/solid/bun-plugin,跨平台分发用 compile.target 指定 bun-<os>-<arch>
  7. 测试testRender + 固定终端尺寸 + 文本快照断言。

这套配置体系在 Cline 仓库中并非孤立存在——CLI 应用基于同族的 React 变体(@opentui/react)实现了完全对应的 tsconfig、renderer 创建与 mock 测试实践,可作为跨框架对照的阅读材料。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
docsdocs
暂无描述
Markdown
889
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341