TL;DR — Fitz LiveViewsFitz 的实时 UI 框架。Fitz 是一种编译型、渐进类型语言,HTTP、WebSocket、认证和 ORM 都是语法的一部分。你只需编写单文件组件(.fitzv),包含 state / event / <template>,服务器渲染 HTML,通过 WebSocket diffing 并将补丁发送到浏览器——无需 JavaScript 构建步骤,无需客户端框架。同一个 .fitzv 也可以编译为 WebAssembly,支持离线、零往返的组件。已有实时组件画廊、课程,以及用它构建的完整旗舰应用(包含认证 + Postgres + Docker 的管理面板)。仓库github.com/Thegreekman76/fitz-liveviews · 文档thegreekman76.github.io/fitz-liveviews

这是 FitzLiveViews 系列的第一篇文章。我将先介绍理念和搭建方式;后续文章将实际构建项目。

问题

构建现代 Web UI 通常需要两种语言、两种类型系统和一套构建流程:后端(Python / Node / Go)加上前端框架(React / Vue / Svelte)及其工具链(Vite / Webpack / Babel)。你需要跨网络重复类型定义,同步两种心智模型,并且 node_modules 会变得越来越臃肿。

Phoenix LiveView(Elixir)展示了另一种方式:在服务器端渲染,通过 WebSocket 推送 diff,让浏览器保持简单。无需客户端框架、无需手写 API、无需 JSON 序列化。Fitz LiveViews 将这种模式引入 Fitz——并增加一个新特性:同一个组件也可以在需要纯客户端、离线交互时编译为 WebAssembly。

Fitz LiveViews 的外观

组件是一个单独的 .fitzv 文件——包含状态、事件处理程序和模板,类似于 Vue 或 Svelte:

component Counter {
  state { count: Int = 0 }

  event increment() { count = count + 1 }
  event decrement() { count = count - 1 }
  event reset() { count = count = 0 }

  <template>
    <div id="counter-app">
      <p>Count: {count}</p>
      <button @click="increment">+1</button>
      <button @click="decrement">-1</button>
      <button @click="reset">Reset</button>
    </div>
  </template>
}

进入全屏模式 退出全屏模式

服务器渲染 目标下,框架注册该组件,发送初始 HTML,并在每次事件发生时重新计算 HTML、diff 并通过 WebSocket 发送补丁。浏览器应用这些补丁。你永远不用编写客户端 JavaScript、不用定义 API、不用手动序列化负载。

客户端 WASM 目标(fitz build --target wasm-client)下,同一个文件会编译成 wasm-bindgen + web-sys 包,直接挂载并操作 DOM——离线、无需服务器。单个组件大约 12 KB(gzip 后)。

它的不同之处

  • 前后端同一种语言。 组件、处理程序和服务器全部用 Fitz 编写。你的 type User { ... } 在两端完全一致——无需重复 DTO。
  • 零 JavaScript 构建。 无需 npm install、无需打包工具、无需 node_modulesfitz 二进制文件完成全部编译。
  • 类型检查模板。 模板有自己的检查器:属性类型错误、@event 绑定到不存在的处理程序、<slot slot="x"> 缺少对应的 <slot name="x">——所有问题都会在编译时被捕获,并精确定位到 .fitzv 文件和行号。
  • 双目标:从单一源代码 SSR WASM。 服务器渲染用于共享、数据库驱动、多用户状态;客户端 WASM 用于本地、零往返、离线小部件。无论哪种方式,组件模型都相同。
  • 打包好的 UI 库。 fitz_liveviews.ui.* 提供开箱即用的组件(Badge、Card、DataGrid、Pager、Input、Select、Tabs、Stepper、TreeView 等),通过 --flv-* 设计令牌进行主题化。

有一个 实时组件画廊——真实组件编译为 WebAssembly,在浏览器中运行,无需服务器。点击试用。

数据指标

以下是从旗舰管理应用和画廊中测得的负载/构建数据——而非合成吞吐量声明:

  • 一个完整的服务器渲染仪表盘页面仅需约 1.1 KB 的 JavaScript(3 个极小的内联 <script> 块:theme-before-paint + WebSocket live 客户端),零外部 <script src>,零构建步骤。 页面 HTML 约 38 KB,这就是全部——无需先下载框架运行时。相比之下,SPA 的框架运行时本身就有 ~40 KB(类似 Svelte)到 ~140 KB(React + ReactDOM),还不包括你的代码和 hydration 负载。
  • 一个客户端 WASM 组件约 12 KB(gzip 后)——是整个组件,而非“100 KB 运行时上的你的代码”。计数器演示为 11.4 KB(gzip);12 个组件组成的完整画廊约 44 KB。
  • node_modules,零打包工具配置。 fitz 二进制文件就是整个工具链。git clonefitz run
  • 原生二进制文件比解释器每交互快约 9 倍fitz runfitz build 渲染结果逐位相同),因此你可以在解释器上开发,发布时再构建二进制。

(跨框架请求吞吐量基准测试是诚实的未来工作——我更愿意提供实测负载数据,而不是空谈负载测试。)

对比

Fitz LiveViews Phoenix LiveView Hotwire (Turbo) React/Vue/Svelte (SPA) HTMX
通过 WebSocket 实时 diff ✅ 内置 ✅ 内置 ~ (Turbo Streams) 手动 ~ (扩展)
JavaScript 构建步骤 必需
技术栈中的语言 1 (Fitz) 1 (Elixir) 2 (Ruby + JS) 2+ (后端 + JS/TS) 1 后端 + HTML
离线 / 纯客户端目标 WASM,同一源代码 ✅ (JS)
类型检查模板 ✅ 编译器 ~ (HEEx) ~ (TS/JSX)
编译为原生二进制 ❌ (BEAM VM)
打包的 UI 组件库 fitz_liveviews.ui.* 社区 社区 庞大生态 社区

Fitz LiveViews 的真正不同之处在于:整个技术栈仅用一种语言单一源代码支持 SSR/WASM 双目标编译为独立原生二进制文件,以及编译器检查的模板。它的不足之处也很诚实:它还很新,生态系统较小——React/Vue/Svelte 已有十年的库和人才储备。如果“以更小的生态换取极简技术栈”这种权衡适合你的项目,请继续阅读。

入门

1. 安装 Fitz。 Fitz LiveViews 是 Fitz 语言的库,因此请先安装 Fitz:

curl -sSf https://thegreekman76.github.io/fitz/install.sh | sh
fitz --version

进入全屏模式 退出全屏模式

Fitz 课程详细介绍了安装 / 卸载 / 更新——请参阅 Fitz 课程 · C1 — 安装

2. 安装编辑器扩展。 两个 VSCode 扩展提供语法高亮、诊断、悬停提示和跳转到定义:

  • Fitz — 用于 .fitz 文件(语言本身)。从 Fitz releases 获取 .vsix,然后执行 code --install-extension fitz-language-*.vsix
  • Fitz LiveViews — 用于 .fitzv 单文件组件。从 fitz-liveviews releases 获取扩展,然后执行 code --install-extension fitz-liveviews-*.vsix

3. 添加依赖。 在项目的 fitz.toml 中:

[dependencies]
fitz_liveviews = { git = "https://github.com/Thegreekman76/fitz-liveviews" }

进入全屏模式 退出全屏模式

这就是全部设置——无需 Node、无需打包工具、无需 package.json

不是玩具——有旗舰应用

为了在真实场景中验证该模型,我们用 Fitz + Fitz LiveViews 构建了一个完整的后台 管理面板:登录(Argon2id + 签名 JWT 会话 Cookie)、响应式外壳(可折叠侧边栏、320px 以下的移动抽屉、ES/EN 切换、亮/暗/自动主题)、从 Postgres 获取真实数据的仪表盘,以及两个实时 CRUD 页面(员工 + 部门),支持搜索、筛选、排序、分页、富标签表单、多选删除、分组、行展开和 CSV 导出——全部通过 WebSocket diff、全部国际化、全部通过 docker compose up 启动。

所有可复用部分都打包在 fitz_liveviews.ui.* 中——该库是从这个应用中提取出来的。它是活的参考实现。

前往

本系列后续内容

  • #2 — 你的第一个组件,两次。 一个计数器,服务器端通过 WebSocket 渲染,同时编译为 WebAssembly——同一源代码,两个目标。
  • #3 — 表单、负载和实时输入。 事件如何携带数据,以及 @input / @change 如何绑定表单值。
  • #4+ — 构建旗舰应用。 深入管理面板:Cookie 认证、通过 Postgres 的实时 DataGrid、打包的 UI 库、i18n 和 Docker。

如果无需 JavaScript 构建就能实现实时 UI 听起来不错,请为 仓库 加星并关注本系列。下一篇:计数器,两次。