7 个版本
0.0.7 | 2019 年 9 月 2 日 |
---|---|
0.0.6 | 2019 年 8 月 9 日 |
0.0.5 | 2019 年 7 月 20 日 |
0.0.4 | 2019 年 6 月 27 日 |
0.0.1 | 2018 年 7 月 14 日 |
#2175 in 网页编程
被用于 smd_tests
80KB
1.5K SLoC
Smithy
Smithy 是一个 Rust 前端框架
什么是 Smithy?
Smithy 是一个允许你完全使用 Rust 编写 WebAssembly 应用程序的框架。其目标是让你使用惯用的 Rust 语法,同时不放弃编译器的任何安全保证。
Smithy 支持 nightly 版本
Smithy v0.0.7 目前支持 1.39.0-nightly (dfd43f0fd 2019-09-01)
。
入门
在 Smithy 中入门非常简单!
npm init smithy-app my_smithy_app
cd my_smithy_app
npm start
导航到 localhost:8080
来查看你的应用程序。
更多信息请参阅 create-smithy-app 仓库。
一个简单的 Smithy 应用
一个简单的点击计数器如下
#[wasm_bindgen(start)]
pub fn start() -> Result<(), wasm_bindgen::JsValue> {
let root_element = get_root_element()?;
let mut count = 0;
let app = smithy::smd!(
<div on_click={|_| count = count + 1}>
I have been clicked {count}{' '}times.
</div>
);
smithy::mount(Box::new(app), root_element);
Ok(())
}
fn get_root_element() -> Result<web_sys::Element, wasm_bindgen::JsValue> {
let document = web_sys::window().unwrap().document().unwrap();
document.get_element_by_id("app")
.ok_or(wasm_bindgen::JsValue::NULL)
}
Smithy 的工作原理
smd!
宏
smd!
和 smd_borrowed!
宏将类似 JSX 的东西转换为围绕 FnMut(smithy::types::Phase) -> smithy::types::PhaseResult
的包装器。例如,在以下代码中的 smd!
调用被转换为
let mut count = 0;
let app = smithy::smd!(
<div on_click={|_| count = count + 1}>
I have been clicked {count}{' '}times.
</div>
);
...
let mut app = {
#[allow(dead_code)]
use smithy::types::Component;
let component: smithy::types::SmithyComponent =
smithy::types::SmithyComponent(Box::new(move |phase| match phase {
smithy::types::Phase::Rendering => {
smithy::types::PhaseResult::Rendering(smithy::types::Node::Vec(vec![
smithy::types::Node::Dom(smithy::types::HtmlToken {
node_type: "div".into(),
attributes: std::collections::HashMap::new(),
children: {
let mut children = Vec::with_capacity(4usize);
children.push(smithy::types::Node::Text("I have been clicked ".into()));
children.push({ count }.render());
children.push({ ' ' }.render());
children.push(smithy::types::Node::Text("times.".into()));
children
},
}),
]))
},
smithy::types::Phase::UiEventHandling(ui_event_handling) => match ui_event_handling {
(evt, [0usize, 1usize, rest @ ..]) => {
smithy::types::PhaseResult::UiEventHandling({ count }.handle_ui_event(evt, rest))
},
(evt, [0usize, 2usize, rest @ ..]) => {
smithy::types::PhaseResult::UiEventHandling({ ' ' }.handle_ui_event(evt, rest))
},
(smithy::types::UiEvent::OnClick(val), [0usize, rest @ ..]) => {
({ |_| count = count + 1 })(val);
smithy::types::PhaseResult::UiEventHandling(true)
},
_ => smithy::types::PhaseResult::UiEventHandling(false),
},
smithy::types::Phase::WindowEventHandling(window_event) => {
let mut event_handled = false;
event_handled = ({ count }).handle_window_event(window_event) || event_handled;
event_handled = ({ ' ' }).handle_window_event(window_event) || event_handled;
match window_event {
_ => smithy::types::PhaseResult::WindowEventHandling(event_handled),
}
},
smithy::types::Phase::PostRendering => {
{
{
({ count }).handle_post_render();
}
({ ' ' }).handle_post_render();
}
smithy::types::PhaseResult::PostRendering
},
smithy::types::Phase::RefAssignment(path_so_far) => {
let new_path = path_so_far
.clone()
.into_iter()
.chain(vec![0usize, 1usize])
.collect();
({ count }).handle_ref_assignment(new_path);
let new_path = path_so_far
.clone()
.into_iter()
.chain(vec![0usize, 2usize])
.collect();
({ ' ' }).handle_ref_assignment(new_path);
smithy::types::PhaseResult::RefAssignment
},
}));
component
};
请注意,以下代码 |_| count = count + 1
和 {count}
位于match分支的不同部分。如果它们不在不同的分支中(例如,如果 smd!
创建了一个结构体而不是一个 FnMut
),则无法编译。借用检查器会抱怨你无法不可变地借用 count
,因为它已经在 on_click
回调中被可变借用。
Smithy 阶段
如上 smd!
宏展开所示,阶段是Smithy的核心概念。特别是,应用程序通过五个阶段驱动:
- 渲染,在这个阶段,要求应用程序返回一个包含将写入DOM的信息的结构体。
- 引用分配,在这个阶段,任何具有
ref={&mut optional_web_sys_html_element}
的应用程序都将将Some(some_html_element)
分配给该引用。 - 渲染后,在这个阶段,任何
post_render={|_| ...}
回调将被执行。这些回调保证所有引用已经分配,因此你可以执行任何直接DOM操作。 - UI事件处理和窗口事件处理,在这个阶段,Smithy会根据事件执行回调。在回调执行后,Smithy将重新运行应用程序的不同阶段。
- (UI事件处理和窗口事件处理被视为不同的阶段,尽管在概念上它们非常相似。)
smd!
与 smd_borrowed!
如上宏展开所示,smd!
宏创建了一个移动闭包。这并不总是所希望的。如果你不希望创建移动闭包,请改用 smd_borrowed!
。
如何参与
Smithy总是欢迎贡献者!请在推特上关注我 @statisticsftw
或查看 Smithy路线图。
此外,请使用 create-smithy-app 尝试Smithy。
谢谢!祝您编码愉快!
lib.rs
:
Smithy是一个用于在Rust中完全编写WebAssembly应用程序的框架。它的目标是让您使用易于使用、符合Rust语法的Rust,同时不放弃编译器的任何安全保证。
示例
let app = smd!(<div>hello world</div>);
let el_opt = web_sys::window()
.and_then(|w| w.document())
.query_selector("#app");
if let Some(el) = el_opt {
smithy::mount(app, el);
}
注意。这些文档省略了 smd!
和 smd_borrowed!
,它们是从 smd_macro
包中重导出的。
依赖关系
~8–11MB
~206K SLoC