ESC
开源 1 分钟阅读

Bonsai:Jane Street的UI库

Jane Street 开源了 Bonsai,一个用于构建增量、可组合状态机的 OCaml UI 库。它支持纯函数状态机和增量渲染,适用于 Web 和终端界面,并提供了强大的测试工具。

来源:Hacker News

module Dice = struct
 let faces =
 [ "⚀"; "⚁"; "⚂"; "⚃"; "⚄"; "⚅" ]
 ;;

 let component (graph @ local) =
  (* 组件以纯函数状态机实现。 *)
 let face, set_face = Bonsai.state (List.hd_exn faces) graph in
  (* 组件是增量渲染的,仅在相关状态变化时重新计算。 *)
 let%arr face and set_face in
 {%html|
 <div>
 你掷出了 #{face}
 <button
  style="" on_click=%{fun _ ->
   let index = Random.int (List.length faces) in
   set_face (List.nth_exn faces index)}
 >
 掷骰子
 </button>
 </div>
 |}
 ;;
end

大多数 Jane Street 内部 Web 应用都使用 Bonsai 构建。

组件以纯函数状态机实现,并且易于组合。框架内的增量计算意味着值只在必要时才重新计算。这适用于每个值,而不仅仅是视图。

其他 Web 框架倾向于将状态、增量性和渲染合并到一个抽象中,即 UI 组件。相比之下,Bonsai 允许你按需组合状态和增量原语。那些在用户交互期间防止重新渲染整个页面的相同原语,也可以用于在实时更新的数据集上增量计算昂贵的业务逻辑。(如果你习惯于 React,想象一下所有东西都使用非常类似于 hooks 的东西,而状态管理在组件层次结构之外。)

由于状态不与显式组件关联,因此有一个广泛的 API 来管理用户与页面交互时的状态生命周期和作用域。例如,如果你想将一组有状态的 UI 组件嵌入到另一个 UI 组件中(比如在标签界面中),Bonsai 会为你处理状态管理,而不是要求你手动将每个内部组件的状态提升到应用的顶层模型中。更多关于状态如何组合的例子,请参阅 Bonsai 创建者编写的这个组合比较。

而且因为 Bonsai 是用 OCaml 编写的,所以在后端和前端使用相同的语言和类型成为可能。这对于可读性和保持大型 Web 应用代码库的可管理性的影响难以夸大,特别是当你广泛使用 OCaml 的类型系统来减少错误时。在 Jane Street,许多内部系统以前只有终端 UI,而该框架使得将现有类型和业务逻辑移植到 Web 变得容易。

Bonsai 还附带了一个强大的模板语言、对组件特定样式表的支持,以及一个全应用自动化测试系统。

Bonsai 最强大的功能之一是它允许你轻松编写真实的测试,其中你程序化地操作 UI 元素并观察你的 DOM 演变。

在下面的例子中,我们测试一个用户选择器的行为。无论你在文本框中输入什么,都会附加到一个小“hello”消息中:

let%expect_test “shows hello to a specified user” = let handle = Handle.create (Result_spec.vdom Fn.id) hello_textbox in Handle.show handle; [%expect {

hello
|}]; Handle.input_text handle ~get_vdom:Fn.id ~selector:"input" ~text:"Bob"; Handle.show_diff handle; [%expect {
- hello + hello Bob
|}];

注意,有两个 expect 块。(这允许你在给定场景中进行多个断言,并将设置/辅助代码仅作用于该场景。)

第一个使我们的 UI 可见,第二个——包含一个 diff——显示在程序化输入一些文本后的一些行为。Bonsai 甚至会向你展示 HTML 属性或类名如何响应用户输入而变化。测试可以包括模拟服务器调用,并且可以涉及不仅仅是 UI 的变化,还有驱动它的状态的变化。有了这样的测试,你可以在不打开浏览器的情况下编写整个组件。

Bonsai Quick Start 和 Thinking in Bonsai 提供了 Bonsai 的动手介绍,是开始学习的最佳起点。还有:

厄,一个细节:Bonsai 本身——这个库——实际上比上面听起来的更通用。它允许你构建通用的增量、可组合的状态机。Bonsai_web 构建在该核心库之上,专门用于基于浏览器的交互式 UI,但我们还有 Bonsai_term 用于构建基于终端的交互式 UI。甚至有一个用于愚人节的 Bonsai_vr 原型,用于响应式虚拟现实 UI。

Bonsai 是一个用于构建增量、可组合状态机的库。