一棵树,多种宿主
跨平台共享组件。
使用 Widget、Scope、语义事件和类型化样式编写应用组件。将 DOM 查找、HTML 生成、窗口创建和事件循环放入小型的宿主专用入口中。
共享组件只写一次
这个组件不包含 web-sys、HTML 文档或窗口类型。无论挂载到哪里,其 Cage 和事件处理器的所有权与更新行为都保持一致。
shared.rs
use glory::prelude::*;
pub fn counter() -> impl Widget {
widget(|scope| {
let count = scope.cage(0_u64);
col().class("counter").fill((
text().content(count.map(|count| format!("Count: {count}"))),
button()
.label("Increment")
.on(activate, move |_| count.revise(|value| *value += 1)),
))
.show_in(scope)
})
}只转发使用的特性
Glory 没有默认宿主。应用特性转发到 facade 特性,使服务器、浏览器和原生依赖图保持显式。web 和 ssr 都选择 html;hydrate 选择 web;stream 选择 ssr 和 resources;blitz 仅适用于原生。渐进式浏览器客户端可用 stream-web,它选择 stream 和 hydrate(因此也包含 web);应在最后一个 End 帧后对应用执行水合。
Cargo.toml
[features]
default = []
web = ["glory/web"]
ssr = ["glory/ssr"]
hydrate = ["glory/hydrate"]
stream = ["glory/stream"]
stream-web = ["glory/stream", "glory/hydrate"]
blitz = ["glory/blitz"]
desktop = ["glory/blitz-shell"]
desktop-accessibility = ["glory/blitz-accesskit"]
[dependencies]
glory = { version = "0.3.1", default-features = false }选择宿主入口
web_and_server.rs
// Native server: produce a versioned fragment for an otherwise empty mount.
let snapshot = glory::ssr::snapshot(counter())?;
let fragment = snapshot.html;
// wasm32 browser CSR: mount into an empty element and retain the WebApp.
let app = glory::web::launch(csr_root, counter())?;
// wasm32 browser hydration: adopt the matching SSR fragment instead.
// Use the same initial widget tree, and retain this WebApp as well.
let app = glory::web::hydrate(hydration_root, counter())?;launch 需要一个空且未被占用的浏览器挂载元素。hydrate 要求 Glory 的版本化 SSR 标记,并在接管前验证整个初始子树。服务器没有浏览器输入循环;交互始于浏览器宿主。
desktop.rs
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
use glory::blitz::shell::{Shell, WindowApp, WindowAttributes};
let app = WindowApp::new();
app.mount(counter())?;
let mut shell = Shell::new()?;
shell.add_window(
app,
WindowAttributes::default().with_title("Glory counter"),
);
shell.run()?;
Ok(())
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
fn main() {}WindowApp 拥有共享 App 和原生文档。Shell 拥有桌面事件循环和窗口。该入口需启用 blitz-shell;blitz-accesskit 额外启用可选的桌面无障碍桥接。
能力矩阵
无界面 · 无需特性
App::memory() 为测试记录语义树和类型化补丁。Profile::RECORD 不执行布局,也没有物理输入、焦点、几何测量或平台动作驱动。
Web CSR · web
wasm32 DOM 渲染,支持浏览器输入、焦点、测量、滚动、资源和 RAF 调度。launch 创建新树;请维持 WebApp 的生命周期。
SSR · ssr
通过 render、render_document 和 snapshot 在原生环境中同步输出 HTML 字符串、文档和版本化快照。会记录事件兴趣,但 SSR 没有物理输入或几何测量。
水合 · hydrate
通过 hydrate 或 hydrate_with,在浏览器中接管兼容的 SSR 快照。它包含 web,在修改 DOM 前完成验证,并在不匹配时保留原挂载内容。
流式渲染 · stream
原生、按需拉取的 Shell/Patch/End 输出,具有请求资源和取消能力。添加 web 以使用经典的预编辑脚本,添加 hydrate 以最终接管应用;单独的流式输出不提供浏览器输入宿主。
Blitz 文档 · blitz
原生无界面的 CSS、盒模型和文本布局、测量及程序化滚动。可选 paint/raster 提供帧或 CPU 图像。独立 Renderer 没有操作系统输入驱动。
Blitz 桌面 · blitz-shell
WindowApp 和 Shell 在桌面目标上增加 CPU 桌面窗口、激活、焦点、导航、受控编辑和 IME 协议集成。AccessKit 需要单独启用。
共享语义不会消除平台差异
跨平台组件不保证像素完全相同。字体、文本整形、视口和 DPI 行为、CSS 覆盖范围及原生呈现均有差异。无界面测试通过既不能证明布局正确,也不能证明像素已显示;内存宿主和独立 Blitz Renderer 都不提供用户输入。
明确当前平台限制
桌面 Shell 仅支持 Windows、Linux 和 macOS,并不是 Android 宿主。Android Activity/Surface 集成、移动资源、输入连接和真机验收仍是独立工作。不能根据 Android 编译检查或桌面 winit 依赖推断移动端已受支持。
IME 协议处理不等于所有操作系统输入法均已验证。同样,可选 AccessKit 桥接和 Windows UI Automation 证据也不等于屏幕阅读器验收。Unix AT-SPI 客户端、语音播报、完整文本选择接口、操作系统输入法行为和移动无障碍仍需各平台验证。