长桥 nsh(Native Shell)解读:用 TSX 写原生界面的 Rust 跨平台 UI 框架,前端该关注什么
长桥开源的 nsh(Native Shell)对前端意味着什么:TSX + signal、各平台原生控件、热更新、面向 AI Agent 的工具链,以及与 React Native、Flutter、Tauri 的对比。
10 月 28 日,长桥工程师 Jason Lee(@huacnlee)在 X 上宣布:“Longbridge 接下来会将所有手机客户端里面的 H5 逐步淘汰迁移改造,改用 NSH 来实现”。做 App 内嵌 H5 的前端可以留意一下。
nsh(Native Shell)是长桥开源的跨平台 UI 框架,支持用 Rust、TSX 或两者混写。渲染层在 iOS、Android、macOS、Linux 上调用系统原生 UI 控件;Windows 端用 Direct2D 自绘;Web 端输出普通 HTML 元素。仓库采用 Apache-2.0 许可,截至发稿刚建仓 18 天,发了 4 个版本,其中两个带有破坏性 API 变更。
想用一套 TSX 或 Rust 代码覆盖手机、桌面和 Web,又不想套 WebView,可以花个周末用 nsh 做个原型。但目前 API 变动频繁,还不适合直接上生产环境。
nsh 是什么
项目定位是 “a Rust-first native UI framework”。按官方文档的说法,应用可以用 Rust 写(编译成原生代码),也可以用 TSX 写(由 QuickJS 运行,Web 端跑在浏览器自己的 JS 引擎上),或者两者混写。底层共用一个 Rust 引擎:所有平台的布局都由 Taffy 计算(支持 Flexbox 和 Grid),架构文档提到响应式核心沿用了 Solid 1.9 的算法。
各平台后端与最低版本要求如下(数据来自对比文档):
| 目标平台 | 由谁绘制界面 | 最低要求 |
|---|---|---|
| iOS | UIKit | iOS 15 |
| Android | Android View | Android 9(API 28) |
| macOS | AppKit | macOS 14 |
| Windows | NSH 自绘(Direct2D/DirectWrite) | Windows 10 1809 |
| Linux | GTK 4 | GTK 4.14 |
| Web | 用 CSS 样式化的 HTML 元素 | 现代浏览器 |
| GPUI | 把 nsh 应用嵌进 GPUI / GPUI Kit 应用 | 桌面端 |
提交记录最多的作者是 Jason Lee。他在 X 上解释过“Native”的含义(2026-10-25 15:43,北京时间):“除 Windows 之外,各平台都不是自绘 UI”,输入框、滚动、文本选择、输入法、无障碍都直接用系统自带的能力。
前端视角:在 nsh 里怎么写界面
我们用 nsh 0.3.0 执行 nsh init my-app --template ts,生成了下面这个计数器模板,原样照录:
import { mount, signal, Text, View } from "nsh";
function App() {
const count = signal(0);
return (
<View class="flex-1 pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] items-center justify-center gap-4 bg-background">
<Text class="text-3xl font-semibold text-foreground">{count()}</Text>
<View
onPress={() => count.update((c) => c + 1)}
role="button"
class="rounded-(--radius) bg-primary px-5 py-3 active:bg-primary/90"
>
<Text class="text-lg text-primary-foreground">Tap</Text>
</View>
</View>
);
}
mount(App);
模板自带一个可无头运行的测试:
import { expect, open, test } from "nsh/test";
test("counts taps", async () => {
const app = await open("./App.tsx");
expect(app.texts()).toContain("0");
await app.press("Tap");
await app.press("Tap");
expect(app.texts()).toContain("2");
});
习惯了 React 或 React Native,上手时会遇到几个明显差异:
- 没有 React,也没有虚拟 DOM。 架构文档写明,组件函数只执行一次,后续只更新数据绑定,没有组件重渲染和虚拟 DOM diff。写过 Solid 的人对
signal()、count()、count.update()会很熟悉;只用过 React Hooks 的话,得先把组件重渲染的心智模型扭转过来。 - 不是 HTML。 标签用
View、Text,事件用onPress,看着像 React Native。Jason Lee 在回复里说:“不是 HTML + CSS 这是我们特有的 DSL,只是看起来像 TSX”。早期版本里仿 React Native 的 API,在 v0.2.0 已经换成了 nsh 自己的命名。 - 样式靠 Tailwind class。
class接收 Tailwind 工具类,style={{ … }}接收驼峰命名的样式对象;主题沿用了 shadcn/ui 的 token(如bg-primary、text-foreground)。Tailwind 类在运行时由 Rust 直接解析,不需要过一遍 PostCSS。 - 不依赖 Node.js。 单个
nsh可执行文件包揽了整个构建链路:Oxc 擦除类型、自研编译器转换 JSX、rolldown 打包,最后编译成 QuickJS 字节码。运行nsh check时会从 npm 下载一次 TypeScript 原生编译器做类型检查,同样不需要装 Node。 - 基础组件不带样式。
nsh/base只提供导航、对话框、菜单、标签页、表格、编辑器等组件的交互逻辑,长什么样由业务方自己写。设计目标文档明确写了,带样式的组件库交由应用层或社区去建,官方不做类似 shadcn 的现成皮肤。
快速上手
以下命令整理自入门文档和发布说明:
# macOS / Linux(也可用 Homebrew:brew install longbridge/tap/nsh)
curl -fsSL https://nsh.dev/install.sh | sh
# Windows PowerShell:irm https://nsh.dev/install.ps1 | iex
nsh init my-app --template ts # 也可选 rust、mixed
nsh run my-app # macOS 用 AppKit,Linux 用 GTK,Windows 用 Win32
nsh run my-app --target web # 也可选 ios、android、gpui、catalyst
nsh test my-app # 无头测试
nsh package my-app/App.tsx --target web
官方预编译包目前提供 Linux x86_64、macOS arm64、Windows x86_64 三个桌面版本,外加 iOS 和 Android 的嵌入包。v0.3.0 发布页没有提供 Intel Mac 版本。
我们在 Linux 上实际跑了什么
2026 年 11 月 1 日,我们在一台 Debian 13 虚拟机里安装了预编译的 nsh 0.3.0,测试了命令行工具和 Web 构建产物(未在手机、Mac 或 Windows 真机测试):
- 安装后的发行包占用 451 MB 磁盘空间。
nsh init生成上文展示的模板;执行nsh build输出 “1.1 KB js, 3.0 KB bytecode, 6ms”。nsh test无头模式跑通模板测试:“1 test: 1 passed, 0 failed (322ms)”。nsh package --target web产出一个 13.1 MB 的静态目录,其中nsh.wasm占了 13.6 MB,gzip -9 压缩后为 4.7 MB。- 用无头 Chrome 156 打开页面显示正常,点击两次按钮计数变为 2。检查 DOM 结构,里面只有 6 个
div和 2 个span,没有用到canvas,每个节点都挂着内联的left、top、width、height样式。 - GTK 桌面窗口没跑起来:Linux 运行时依赖 WebKitGTK 6.0,测试虚拟机安装该依赖失败,桌面端未能跑通。
相关日志和截图已归档在证据目录。wasm 体积要结合版本看,见下一节。
Web 端:确实是 HTML,但布局归 NSH 管
Jason Lee 在 X 上说 nsh 的 Web 版 “not the wasm. All are HTML + JavaScript”(2026-10-19 20:22,北京时间)。评论区有用户 @PeterKogo2 追问:“Why is there a 1.3mb wasm loaded and most of the frametime is spent in wasm?”
这两句话其实不矛盾。渲染出来的节点确实是原生 HTML,滚动、选字、输入都走浏览器默认行为;但按照 Web 文档的说明,组件状态、布局计算和更新调度依然由编译成 WebAssembly 的 Rust 引擎接管。我们实测看到的 DOM 证实了这一点:节点位置由 Rust 里的 Taffy 算好,直接写成绝对定位坐标,浏览器自身的 CSS Flexbox 并不介入布局。前端打开 DevTools 调布局时,看到的会是算好的像素偏移量,而不是 display: flex。
产物大小要分版本看。按 v0.3.0 的文档,TSX 应用在 Web 端会把 QuickJS 一起打进 wasm,体积“约 3.5 MB,gzip 后 1.2 MB”(我们实测用 v0.3.0 打出来的包大得多,具体原因尚未查明)。到了 10 月 28 日(v0.3.0 发布之后),PR #603 合入主干,改成让 TSX 直接跑在浏览器自带的 JS 引擎上,最新文档随之把仅含核心组件的应用下载体积改写为“约 1.1 MB”。截至 11 月 1 日,这个改动还没发正式版。
热更新与开发流程
执行 nsh run 和 nsh dev 会启动支持模块热替换的宿主环境。开发服务器文档给出的数据是:应用 TSX 改动补丁耗时“远低于 1 毫秒”,从保存文件到界面更新“约 120 毫秒”,未改动的组件会保留实例和 signal 状态;修改 Rust 代码则会触发重新编译并重启应用。以上为官方文档数据,我们这次没有实测热更新耗时。
用 AI 写,也为 AI 而写
nsh 从开发方式到应用场景都和 AI 绑得很深:
- 方便 Agent 读取的文档与类型。 官方文档直接提供
llms.txt和llms-full.txt,所有页面都有对应的 Markdown 版本。框架内全部元素、属性、样式键的 TypeScript 声明均由 Rust 源码自动生成到.nsh/types目录下,方便 Agent 写代码时直接通过编译器做类型检查。 - 用 Tailwind 减少 token 消耗。 Jason Lee 写道(2026-10-20 21:54,北京时间):“for AI, the Tailwind API is less token cost.” 这是他个人的判断,我们没见到测量数据。
- 动态下发 AI 生成的界面。 宿主 App 支持下载带签名的
.nshpkg包(内含 TSX 代码)并在沙箱中运行。沙箱文档列明了内存上限、单次调用耗时、节点数量等限制,以及宿主下发的权限控制。Jason Lee 在发布帖(2026-10-19 18:57,北京时间)里提到,当周就会在长桥手机端接入 nsh,“主要解决 AI 动态生成模块支持”。 - 大部分提交由 AI 参与。 我们克隆下来的仓库共有 640 个 commit(截至 2026-11-01 21:20,北京时间),其中 518 个带有 AI 共同作者标记或 “Generated with Claude Code” 字样。出现频率最高的是 “Co-authored-by: Claude Opus 5.5”(353 次),Codex、Devin、GitHub Copilot 的 Agent 也有参与。仓库里有一份 614 行的
AGENTS.md,CLAUDE.md里只有一行指向它的引用。Jason Lee 还在 X 上提到 “NSH 项目每天有超过 50 个 PRs”(2026-10-29)。
对前端团队而言,把创建项目、类型检查、无头测试、打包塞进同一个命令行工具,确实方便让 Agent 自己写完页面自己跑通验证。但反过来,靠 Agent 这么快写出来的 API,变起来也会一样快。
和 GPUI、GPUI Kit、gpui-component 的关系
在做 nsh 之前,长桥已经在维护 GPUI Kit(原名 gpui-component,GitHub 约 1.88 万星),这是为 Zed 编辑器的 GPUI 打造的组件库,同时他们还维护着自己的分支 GPUI Fast。GPUI 走的是纯 GPU 自绘路线。
nsh 文档解释了另起炉灶的原因:这个项目最初是给长桥手机 App 做插件层,起点是 GPUI Shell。但团队发现在手机上搞自绘,就得把系统现成的文本选择及弹出菜单(拷贝、共享、翻译、查询)、输入法、无障碍等功能全部重造一遍。Jason Lee 在 X 上也谈到了同样的问题:移动端离不开原生的文本选择、翻译和自动填充,对多点触控和功耗也更敏感,GPUI 的 immediate mode 模式在这些场景下比较吃亏。
目前两条线的定位很清晰:追求自绘的桌面端继续用 GPUI Kit;nsh 里的 nsh/base 延续了 gpui-base 行为与样式分离的设计,并且提供了 GPUI 后端,可以把 nsh 应用直接嵌进 GPUI Kit 桌面应用里。至于有用户 @tdomhan 询问 GPUI Kit 后续是否会停止维护,我们没找到公开回复。
nsh 与 React Native、Flutter、Tauri、Electron 对比
| nsh | React Native | Flutter | Tauri | Electron | |
|---|---|---|---|---|---|
| 界面由谁绘制 | 平台原生 UI(Windows 自绘) | 平台原生 View | 自带引擎 | 系统 WebView | 内置 Chromium |
| 写界面用 | TSX + signal,或 Rust | JS/TS + React | Dart | 任意 Web 框架 | 任意 Web 框架 |
| 原生 App 里的 JS 运行时 | TSX 用 QuickJS;纯 Rust 应用没有 | 有 | 无 | 用 WebView 的 | Chromium + Node.js |
| 移动端 | iOS 15+、Android 9+ | iOS 15.1+、Android 7+ | iOS 15+、Android 7+ | 支持(Tauri 2) | 不支持 |
| 桌面端 | macOS、Windows、Linux | 需另外的 macOS/Windows 项目 | macOS、Windows、Linux | macOS、Windows、Linux | macOS、Windows、Linux |
| Web | HTML 元素 | 通过 react-native-web | Canvas | 本身就是网页 | 本身就是网页 |
| 许可证 | Apache-2.0 | MIT | BSD-3-Clause | MIT 或 MIT/Apache-2.0 | MIT |
数据来源:nsh 对比文档(引用了 React Native 0.76 与 Flutter 支持平台)、Tauri 文档、Electron 文档 及各项目 GitHub 许可证。
nsh 官方文档自己也划出了不适用场景:要求多端像素级一致,去用 Flutter 或 Slint;依赖庞大第三方生态,去用 React Native、Flutter 或 Qt;遇到持续高频刷新的界面,去用自家的 GPUI Fast。
在技术选型上,Jason Lee 对 Web 套壳方案态度鲜明,10 月 26 日(09:25,北京时间)他在 X 上写道:“如果你还在考虑 Electron, Tauri 这些工具,那应该赶紧放弃”。这代表项目维护者的个人倾向,并非客观评测结论。
性能:目前只有项目方数据
我们未做独立性能测试,以下均为官方公布的数据:
- 对比文档引用的 nsh-perf-bench 基准测试(Linux 环境,500 行行情表,GTK 后端):每秒推送 1,000 条行情时,NSH Rust 占用单核 18% CPU,GPUI Fast 占 20%;加压到每秒 20,000 条时,GPUI Fast 占 25%,NSH 升至 73% 到 78%。
- Jason Lee 晒出的 Gallery “Stocks” 示例运行数据:M3 Mac 上跑满 120 FPS、CPU 占用 33% 到 36%;Linux + NVIDIA 环境下 117 到 120 FPS、CPU 占用 31% 到 32%;Windows 上 144 FPS、CPU 占用 36% 到 43%。
局限与风险
- API 变动频繁。 10 月 22 日的 v0.2.0 和 10 月 26 日的 v0.3.0 均包含破坏性变更。向后兼容文档虽然承诺 “an app built for a compatible release runs on every later release, unchanged”,但具体的“兼容版本”列表记录在单独的 nsh-compat 里,我们这次没有核查,暂不确定当前覆盖到了哪个版本。
- 立项时间极短。 仓库第一个 commit 提交于 10 月 14 日。截至 11 月 1 日共有 914 星、72 个 open 状态的 issue。GitHub API 识别出的许可证状态为 “NOASSERTION”,不过仓库里放的是 Apache-2.0 协议文件。
- 跨平台不等于一次出所有安装包。 正如用户 @trymorewz 在评论区提醒的:“‘跨平台’也不等于一次编译出所有安装包,桌面应用仍需在对应系统打包。”
- Windows 端非原生控件。 Windows 平台由 NSH 基于 Direct2D 自绘实现。
- Web 运行时比纯 HTML 重。 前面展示了实测的 wasm 体积数据,准备上生产前务必拿当前版本的构建产物实测一下体积。
- Linux 端完成度还不高。 有用户反馈“linux环境下bug有点儿多”;还有用户提到
llms.txt没有及时更新指向最新版本,导致他的 Agent 一直锁在旧版本上写代码。 - 鸿蒙支持尚未落地。 Jason Lee 说社区已经有人提了 HarmonyOS 的 PR,但他还在考虑要不要合入。
X 上的反应
我们看到的讨论主要集中在 Jason Lee 的推文评论区,大多是中文:
- @xiaoshan0413 总结:“重性能拼定制就选GPUI,要快要跨端就选Native Shell。”
- @maddada 吐槽:“TypeScript feels like ‘ew’ for desktop or mobile apps 😅 Any performance comparasions between Native Shell and GPUI?”
- 写过 C++ Skia 跨平台框架的 @faywanghq 问:nsh 是不是只用平台提供的容器 View、内部子 View 自绘?否则这么多平台怎么保证能力一致。
- @sufunds 晒出了自己基于 nsh 写的 macOS + iOS 应用 Vela,配合 Tailscale 让 iPhone 直接访问 Mac 上的本地开发服务。
- @thejingtao 说:“我在用 NSH 做 Generative UI 了,效果非常好”。
- @emojiiii007 问:nsh 既然构建成原生代码,动态更新怎么做?答案就是前文提到的下发签名 TSX 包。
对前端意味着什么
回到开头那条淘汰客户端 H5 的推文,Jason Lee 的原话后半段是:“以后将不再需要用前端来开发这些动态更新的手机界面。采用 NSH 既能获得 Native 的体验,又能继续如同 H5 一样动态更新且高效开发。” 除了这条推文,我们没有找到具体的迁移时间表。
真要切过去,前端手里的 TSX、Tailwind、Flexbox 布局经验以及写单测的习惯都能直接复用;需要扔掉的是 React 框架本身、依赖浏览器 DOM 的 npm 包,以及“靠浏览器算 CSS 布局”的调试习惯。
我们目前的看法:nsh 想同时拿到 H5 的动态下发和各平台的原生控件,长桥自己也在往里押注。靠 Agent 驱动的开发速度是它的优势,也是现阶段最大的风险。想尝鲜的话,可以先锁定版本号,用 TSX 写个独立页面试试,等兼容性记录稳定下来,再讨论存量项目的迁移。
一手资料
相关文章
更多AI 工具 →mygo 上手:AI 写出来的 Go 桌面应用框架,原生 UI 和 Webview 都能用
mygo 是 EGOIST 用 Claude Opus 5.5 五周写出的 Go 桌面框架:纯 Go、不用 cgo、单个二进制约 9 MB。本文讲它是什么、怎么起步、Linux 实测结果,以及和 Wails、Tauri、Electron、Fyne 的对比。
Cline:开源 AI 编程智能体详解、核心功能与上手指南
全面介绍开源 AI 编程智能体 Cline,它支持 IDE、命令行与桌面端,能够跨多文件协调修改代码,并自主执行终端工作流以解决开发问题。
Aider:终端 AI 结对编程工具与快速上手指南
介绍开源终端工具 Aider,支持终端内 AI 结对编程、代码库全景构建、Git 自动集成与多模型代码编辑。