首页
/ Cline CLI 的 OpenTUI React 项目配置全解:tsconfig、Renderer、Bun 打包与 DevTools 调试验证

Cline CLI 的 OpenTUI React 项目配置全解:tsconfig、Renderer、Bun 打包与 DevTools 调试验证

2026-09-04 10:57:15作者:劳婵绚Shirley

本文以仓库中 .agents/skills/opentui/references/react/configuration.md 配置指南为骨架,完整覆盖 OpenTUI React(@opentui/react)从项目脚手架、TypeScript 与包配置、Renderer 参数,到 Bun 打包分发、环境变量、React DevTools 和测试配置的全部实操内容。Cline 的 CLI 应用正是基于 OpenTUI React 构建的终端界面,读完本文你既能按文档搭建一个标准的 OpenTUI React 项目,也能对照 Cline 仓库的真实配置(apps/cli/tsconfig.jsonapps/cli/src/tui/index.tsxapps/cli/bun.mts)理解每个配置项在生产项目中的实际取值与原因。

项目初始化

使用 create-tui 快速创建

官方脚手架一条命令生成项目:

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

两点约束需要注意:

  • CLI 会替你创建 my-app 目录,该目录不能已存在
  • 可选参数:--no-git(跳过 git init)、--no-install(跳过 bun install)。

同系列的 OpenTUI 技能说明 还强调了一条 Agent 使用场景下的规则:create-tui 的选项参数必须放在位置参数之前,即 bunx create-tui -t react my-app 有效,而 bunx create-tui my-app -t react 不生效。

手动搭建

不走脚手架时,手动安装三个依赖即可:

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

TypeScript 配置

tsconfig.json 完整示例

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

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

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

关键配置项及原因:

配置 取值 作用
jsx "react-jsx" 使用新版 JSX 转换,无需手动 import React
jsxImportSource "@opentui/react" 让 JSX runtime 从 OpenTUI 导入,<box><text> 等 intrinsic 元素由此获得类型
module / moduleResolution "NodeNext" 官方推荐,保证 OpenTUI 兼容性
lib ["ESNext", "DOM"] 终端环境也需要 DOM lib,因为 React 的类型依赖它,OpenTUI 的 JSX 类型是在 React 类型基础上扩展的

Cline 仓库的真实取值

对照 apps/cli/tsconfig.json,Cline CLI 的编译器配置为:

{
  "target": "ES2022",
  "module": "ESNext",
  "moduleResolution": "bundler",
  "lib": ["ES2022"],
  "jsx": "react-jsx",
  "jsxImportSource": "@opentui/react",
  "strict": true,
  "skipLibCheck": true
}

可以看出两个关键项与指南完全一致:jsx: "react-jsx"jsxImportSource: "@opentui/react",这是 OpenTUI React 项目获得 JSX 类型支持的前提。差异在于 Cline 没有引用 DOM lib(其类型体系通过 workspace 继承和 skipLibCheck 处理),且 moduleResolution 采用 "bundler" 而非 "NodeNext"——这与后文"Module Resolution Errors"一节中针对 Bun 生态建议使用 bundler 的建议相互印证。

包配置

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 build src/index.tsx --outdir=dist --target=bun"
  },
  "dependencies": {
    "@opentui/core": "latest",
    "@opentui/react": "latest",
    "react": ">=19.0.0"
  },
  "devDependencies": {
    "@types/bun": "latest",
    "@types/react": ">=19.0.0",
    "typescript": "latest"
  }
}

其中 "type": "module" 声明 ESM,dev 脚本用 --watch 提供热重载式开发体验。

作为参考,Cline CLI 在 apps/cli/package.json 中对 OpenTUI 的依赖是精确锁定的:@opentui/core@opentui/react 均为 0.4.3react19.2.4@types/react19.2.14,满足"React 19+"的最低要求;另有一个 dev 脚本 CLINE_BUILD_ENV=development bun --conditions=development ./src/index.ts,演示了用构建条件区分开发/生产代码的用法。

项目结构

推荐目录结构:

my-tui-app/
├── src/
│   ├── components/
│   │   ├── Header.tsx
│   │   ├── Sidebar.tsx
│   │   └── MainContent.tsx
│   ├── hooks/
│   │   └── useAppState.ts
│   ├── App.tsx
│   └── index.tsx
├── package.json
└── tsconfig.json

Cline 的 apps/cli/src/tui 目录按同一思路组织:root.tsxcomponents/hooks/themes.ts 等分层清晰,入口则由 index.tsx 统一装配 Renderer 与 React Root。

入口文件 src/index.tsx

import { createCliRenderer } from "@opentui/core"
import { createRoot } from "@opentui/react"
import { App } from "./App"

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

createRoot(renderer).render(<App />)

模式是固定的两步:先从 @opentui/core 创建 CLI Renderer,再用 @opentui/reactcreateRoot(renderer) 把 React 树挂载到该 Renderer 上。

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 的 Flexbox 布局语义:根 <box> 纵向铺满(width="100%" height="100%"),第二层横向排列侧边栏与主内容区,主区用 flexGrow={1} 占满剩余宽度。

Renderer 配置:createCliRenderer 完整选项

import { createCliRenderer, ConsolePosition } from "@opentui/core"

const renderer = await createCliRenderer({
  // 渲染
  targetFPS: 60,

  // 行为
  exitOnCtrlC: true,        // 设为 false 可自己接管 Ctrl+C
  autoFocus: true,           // 点击元素时自动聚焦(默认 true)
  useMouse: true,           // 启用鼠标支持(默认 true)

  // 调试控制台
  consoleOptions: {
    position: ConsolePosition.BOTTOM,
    sizePercent: 30,
    startInDebugMode: false,
  },

  // 清理
  onDestroy: () => {
    // 清理代码
  },
})

各选项的语义:

  • targetFPS:渲染帧率上限,60 为默认目标值;
  • exitOnCtrlCtrue 时按 Ctrl+C 直接退出进程;false 时事件交给你处理,适合需要优雅退出(先销毁 Renderer、恢复 stdio)的场景;
  • autoFocus / useMouse:均默认开启,分别控制点击聚焦与鼠标事件;
  • consoleOptions:内置调试控制台,可配置位置(ConsolePosition)、占屏百分比、是否启动即进入调试模式;
  • onDestroy:Renderer 销毁时的清理回调。

Cline 中的真实用法

apps/cli/src/tui/index.tsx 展示了生产环境如何取舍这些选项:

const renderer = await createCliRenderer({
  exitOnCtrlC: false,
  autoFocus: false,
  enableMouseMovement: true,
});

Cline 选择 exitOnCtrlC: false,自行监听 renderer.on("destroy") 事件来卸载 React Root、恢复 stdio 并解析退出 Promise(见同文件 L55-L73);autoFocus 关闭则是为了让 TUI 自己掌控焦点流转。此外该文件还演示了 renderer.getPalette({ timeout: 150 }) 探测终端默认配色、renderer.setBackgroundColor() 在首帧前铺背景,避免主题闪屏——这些都是在 Renderer 配置层面可做的进阶操作。

构建与分发

用 Bun 打包

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

运行 bun run build.ts 得到压缩后的 dist/ 产物,目标运行时为 Bun。

编译为独立可执行文件

// build.ts
await Bun.build({
  entrypoints: ["./src/index.tsx"],
  outdir: "./dist",
  target: "bun",
  compile: {
    target: "bun-darwin-arm64",  // 或 bun-linux-x64 等平台
    outfile: "my-app",
  },
})

compile.target 指定目标平台(bun-darwin-arm64bun-linux-x64 等),产物是无需安装 Bun 的单一可执行文件。

Cline 的生产构建脚本

apps/cli/bun.mts 给出了一个更完整的 Bun.build 实战样例。它的几个关键决策值得参考:

const result = await Bun.build({
  entrypoints: ["./src/index.ts"],
  outdir: "./dist",
  target: "node",
  format: "esm",
  sourcemap,
  packages: "bundle",
  external: [
    // OpenTUI resolves a platform-specific native package at runtime.
    // Bundling through that resolution path rewrites the import in a way that
    // breaks Linux e2e runs from dist/. Keep React external too so OpenTUI and
    // the CLI share one React runtime instead of ending up with duplicate hook
    // dispatchers in the bundle.
    "@opentui/core",
    "@opentui/react",
    "@opentui-ui/dialog",
    "opentui-spinner",
    "react",
    "react/jsx-runtime",
    "react/jsx-dev-runtime",
    "react-devtools-core",
  ],
  // ...
})

源码注释解释了两条重要经验:其一,OpenTUI 在运行时解析平台相关的原生包,若让打包器跟随这条解析链改写 import,会破坏从 dist/ 出发的 Linux e2e 运行,因此 @opentui/core@opentui/react 必须保持 external;其二,React 也必须外置,否则 bundle 内会出现两份 React 运行时(重复的 hook dispatcher),导致 OpenTUI 与业务代码"各自为政"。这与"React Version Mismatch"一节同属一类问题——TUI 应用里绝不能让两份 React 共存。

环境变量

开发期创建 .env 文件:

# 调试设置
OTUI_SHOW_STATS=false
SHOW_CONSOLE=false

# 应用设置
API_URL=https://api.example.com

Bun 会自动加载 .env 文件,代码内通过 process.env 读取:

const apiUrl = process.env.API_URL

其中 OTUI_SHOW_STATS 控制 OpenTUI 的渲染统计展示,SHOW_CONSOLE 控制调试控制台开关;自定义变量(如 API_URL)则属于应用自身配置。

React DevTools 集成

OpenTUI React 支持接入标准 React DevTools,用于检查组件树:

  1. 安装 DevTools 核心包作为 dev 依赖(必须使用 7 版):

    bun add react-devtools-core@7 -d
    
  2. 单独启动 DevTools 应用:

    npx react-devtools@7
    
  3. DEV=true 环境变量启动应用:

    DEV=true bun run src/index.tsx
    

重要:只有设置 DEV=true 时才会自动连接 DevTools。OpenTUI 在启动时检查 process.env["DEV"] === "true",为真才动态 import("react-devtools-core") 并连接独立运行的 DevTools 应用;未设置该变量时,DevTools 连接代码根本不会加载。

Cline 仓库同样遵循这一约定:apps/cli/package.json 依赖了 react-devtools-core: "^7.0.1"apps/cli/DEVELOPMENT.md 中的开发指引也明确"Run with React DevTools (requires react-devtools-core@7)",并像上文构建脚本一样把它列入 external 以保持单一副本。

测试配置

测试工具封装

// src/test-utils.tsx
import { createTestRenderer } from "@opentui/core/testing"
import { createRoot } from "@opentui/react"

export async function renderForTest(
  element: React.ReactElement,
  options = { width: 80, height: 24 }
) {
  const testSetup = await createTestRenderer(options)
  createRoot(testSetup.renderer).render(element)
  return testSetup
}

核心是 @opentui/core/testing 导出的 createTestRenderer:它创建一个可离屏渲染的测试 Renderer,默认尺寸 80×24,可自定义宽高以模拟不同终端大小。

测试用例示例

// 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() 取终端帧文本 → 断言文本包含",属于典型的 TUI 快照测试。指南默认使用 bun test 运行;如果你用 Vitest,Cline CLI 的 apps/cli/vitest.config.ts 提供了一个可借鉴的配置形态:environment: "node"pool: "forks"、串行执行(maxWorkers: 1fileParallelism: false),以避免 TUI 测试中进程级资源竞争,并用 resolve.alias 把 workspace 包指向源码目录。快照测试与交互测试的完整能力,可参考同技能的 testing 参考

常见问题排查

JSX 类型不生效

确认 jsxImportSource 已指向 OpenTUI:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@opentui/react"
  }
}

缺少该项时,<box> 等 intrinsic 元素会报"属性不存在"一类错误,因为 TS 去的是标准 React JSX 命名空间而非 OpenTUI 的扩展命名空间。

React 版本不匹配

确保 React 19+:

bun install react@19 @types/react@19

@types/react 版本应与 react 主版本对齐,否则类型层面会出现 JSX 命名空间冲突。

模块解析错误

针对 Bun 生态,使用 moduleResolution: "bundler"

{
  "compilerOptions": {
    "moduleResolution": "bundler"
  }
}

这与"关键配置"一节中推荐 NodeNext 的建议并不矛盾:指南默认推荐 NodeNext,而当你遇到 Bun 打包链的解析差异时,bundler 是官方给出的回退方案——Cline 的 apps/cli/tsconfig.json 正是采用了 bundler 这一组合(module: "ESNext" + moduleResolution: "bundler")。

小结

OpenTUI React 项目的配置主线可以归纳为五个层次:脚手架或手动安装三件套(@opentui/react@opentui/corereact@19+);tsconfig 中 jsx/jsxImportSource 两个关键开关;createCliRenderer 的行为选项(退出策略、焦点、鼠标、调试控制台);Bun 打包时把 OpenTUI 与 React 外置以保证单一运行时;以及 DEV=true 门控的 DevTools 与 createTestRenderer 快照测试。文档中的完整速查可回看 configuration 原文,组件与 Hook 细节见 React API 参考避坑指南

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

项目优选

收起
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