
从一个日报起头:移动端团队被要求在两周里把活动页同时上线 iOS、Android 和 macOS。时间紧,交互细,动画还不能掉帧。传统解法要么写三套原生界面,要么走"Web 容器"取巧,结果要么开发效率吃紧,要么性能打折。此时,一个名字近乎低调的框架闯进视野------Valdi 。它把界面的声明式写法留在 TypeScript,把渲染权交给平台原生视图,试图把"效率与性能只能二选一"的旧逻辑翻过来。(GitHub)
它到底是什么
官方给出的定义非常直接:使用 声明式 TypeScript/TSX 写 UI,编译为 iOS、Android、macOS 的原生视图 ,不依赖 WebView,也没有传统 JS bridge 。因此,列表滚动、复杂手势、系统级动画都沿用原生表现,避免"跨平台层"成为性能瓶颈。该框架在 Snap 的生产环境已经长期服役(内部使用达数年),如今以 MIT 许可证开源,当前对外标注为 Beta (主要是文档与工具链仍在对开源生态打磨)。(GitHub)
Valdi GitHub :github.com/Snapchat/Va...
写法长什么样
在 Valdi 里,界面被写成 TSX 组件。下面的示例展示了"声明---渲染---属性"这一套直觉式流程(语义与官方示例一致,但做了适度裁剪与注释):
ts
// HelloWorld.tsx
import { Component } from 'valdi_core/src/Component';
export class HelloWorld extends Component {
onRender() {
const message = 'Hello Valdi';
// 这里的 <view>、<label> 会被编译成平台原生视图(非 WebView)
<view backgroundColor="#FFFC00" padding={24}>
<label color="black" value={message} />
</view>;
}
}
这种写法的关键不在"看起来像 React",而在"最终落地的是原生控件 "。渲染层的工作交给平台本身,框架则在编译期与运行期开启一系列性能手段(视图池复用、按可视区域增量渲染、组件级别的独立重渲),尽量不把重负留在跨层通信上。(GitHub)
Valdi 文档与入门 :github.com/Snapchat/Va...**
为什么在意"原生性能"
跨平台 UI 的历史里,性能问题往往来自两处: 其一是 渲染容器 ------WebView 或自绘引擎在"贴近系统"上天生吃亏;其二是 桥接成本------当状态频繁变动、动画密集、列表超长时,跨语言/跨进程通信会变成隐形税。Valdi 的路径是**"把 UI 编译成原生控件"**,并围绕这个落点做优化:
- 全局 视图池 回收与复用,降低视图创建/销毁成本;
- 独立组件重渲,避免祖先节点无谓更新;
- 可视区域感知 布局与渲染,天生适配长列表与分页;
- 布局引擎以 C++ 实现并运行在主线程,减少跨层编组。(GitHub)
这些点不是花拳绣腿,而是移动端耗时热点的"直线突击"。在信息流、商城、消息类应用中尤其明显:首屏更快出现,滚动更稳,滑动手感更接近系统原生控件。
工程化与开发体验
效率层面,Valdi 不只是在语法上"像 React"。它辅以 即时热重载 (毫秒级见效)、VS Code 调试与性能剖析 、与 Bazel 的集成以保障构建复用与可重复。需要原生接口时,可通过 多语言模块(Polyglot Modules) 生成 TypeScript ↔ Kotlin/Swift/ObjC 的类型安全绑定,既能复用既有原生库,又能把性能关键路径留在原生侧实现。(GitHub)
Bazel :bazel.build/
迁移与落地的"故事线"
一个常见落地顺序是这样的: 先把一个独立页面 或新功能入口 用 Valdi 重写,内嵌到 UIKit/Android View 的树里做 A/B;性能验证后,再逐步扩大接入面。此时,原生与 Valdi 的双向嵌入 能力("在原生里放 Valdi 视图"与"在 Valdi 里嵌原生控件")就像安全带,既不破坏既有工程,又给新栈足够的发挥空间。(GitHub)
在数据通路上,团队可以把网络层、图片加载、埋点等继续留在原生模块里,通过类型安全的绑定暴露给 TypeScript。较重的计算(如协议编解码、复杂 diff、媒体管线)可以走 C++ 或平台原生语言;Valdi 提供的 worker 线程 能让 JS 侧在不阻塞 UI 的情况下完成部分并行任务。(GitHub)
与"别的跨平台"的差异
- 与 WebView 系(Hybrid/H5)不同:渲染不是网页,UI 不是 DOM;因此滚动、手势、导航条这类系统元素更贴近平台期望。
- 与 桥接式 JS Runtime(重度依赖桥的方案)不同:Valdi 通过编译期把"声明式树"降解为原生视图,并尽量在渲染与布局阶段减少跨层通信频率。
- 与 纯自绘引擎 不同:Valdi 倾向"调系统控件",从而继承各平台在无障碍、输入法、可达性、手势冲突处理等方面的成熟经验。以上差异点均来自其官方的渲染路线与性能要点描述。(GitHub)
Hacker News 讨论帖 :news.ycombinator.com/item?id=458...**
一个更完整的页面例子
下面构造一个稍微"像样"的列表页面:顶部标题、主题切换、可复用的 Cell,以及一个在可视区域内才渲染的长列表。逻辑演示为主:
ts
// Feed.tsx
import { Component, state } from 'valdi_core/src/Component';
type Item = { id: string; title: string; subtitle: string };
function FeedCell(props: { item: Item }) {
<view padding={16}>
<label value={props.item.title} fontSize={17} weight="semibold" />
<label value={props.item.subtitle} color="#666" marginTop={6} />
</view>;
}
export class Feed extends Component {
@state private dark = false;
@state private items: Item[] = [];
onMount() {
// 模拟异步请求
this.items = Array.from({ length: 2000 }).map((_, i) => ({
id: String(i),
title: `Card ${i}`,
subtitle: `Valdi compiles to native views`,
}));
}
private toggleTheme() {
this.dark = !this.dark;
}
onRender() {
<view backgroundColor={this.dark ? '#111' : '#fff'}>
<view padding={16} direction="row" align="center" justify="space-between">
<label value="Explore" fontSize={20} />
<button onTap={() => this.toggleTheme()}>
<label value={this.dark ? 'Light' : 'Dark'} />
</button>
</view>
{/* 列表仅对可视区域进行增量渲染,长列表默认可流畅滚动 */}
<list
data={this.items}
keyFor={(it: Item) => it.id}
renderItem={(it: Item) => <FeedCell item={it} />}
estimatedItemHeight={72}
/>
</view>;
}
}
这个例子对应了 Valdi 的三件"拿手活":视图池复用 (大量 Cell 循环利用)、组件级独立重渲 (切换暗黑只让受影响区域更新)、以及按可视窗口渲染 (大列表默认丝滑)。这些都在其 README 的性能段落中明确列出。(GitHub)
风险与边界
任何跨平台方案都不是"银弹"。Valdi 当前仍处 Beta 对外阶段,开源生态的文档、第三方组件、最佳实践沉淀需要时间;同时,团队需要具备原生与 TypeScript 并行的工程能力(特别是当接入平台能力、排查系统层问题时)。不过,从路线选择看,它将"性能优先"的矛盾点拉回到原生栈里,减少了"解释层/桥接层"把控体验的变量。(GitHub)
Valdi GitHub :github.com/Snapchat/Va...** Valdi 入门与示例 :github.com/Snapchat/Va...** Bazel(构建工具) :bazel.build/**
小结
Valdi 的价值主张并不花哨:用 TypeScript 写声明式 UI,把渲染交还给原生 。这一取舍,使其在"多端一致与原生体验"之间取得少见的平衡。对于正在寻找"性能不妥协、又能快速迭代"的团队,这是值得严肃评估的一条技术路径。(GitHub)
参考依据:框架定位、编译为原生视图、性能特性(视图池、布局引擎、可视区域渲染)、工程化能力(热重载、VS Code 调试、Bazel、多语言绑定)、开源许可与 Beta 状态等,均摘自 Valdi 官方 GitHub 仓库与开源发布信息。(GitHub)