WASM(WebAssembly)是一个可移植、体积小、加载快并且兼容 Web 的全新格式,使得使用后端语言也能编写前端界面,能够充分发挥硬件能力以达到原生的执行效率,且其沙箱化的环境和二进制形式的文件更为安全。Rust 语言,这门近年来多次被评选为最受程序员喜爱的计算机语言,在 WASM 领域有着长足的发展。Yew,这个设计先进的 WASM 框架,就是其中的优秀例子。
简介
Yew,是 yewstack 组织在 Github 上开源的 WASM 框架,项目位于 https://github.com/yewstack/yew,目前版本为 0.17.2。
Yew 设计先进,很简单就可以构建多线程的前端 Web 应用。Yew 基于组件,可以轻松地创建交互式的用户界面,拥有 React 或 Elm 等框架经验的开发者会觉得十分熟悉。Yew 通过把工作分流到后台的 Web Worker 来最少化 DOM API 的调用,以达到高速性能。Yew 还支持与 Javascript 进行交互,可以使用 NPM 包,并与现有的 Javascript 应用整合。
安装
Yew 安装简单,可以直接把依赖添加到项目的 Cargo.toml 中:
[dependencies]
yew = { version = "0.14.3", features = ["std_web"] }
此外,还需要安装 WASM 构建工具以方便 WASM 与 Javascript 间的互相操作,可选择的工具包括:wasm-pack、wasm-bindgen 和 cargo-web?。例如,选择使用 cargo-web,则需安装:
cargo install cargo-web
示例
使用 Yew 创建前端应用十分简单,我们来看一个基本的例子。首先创建一个二进制项目:
cargo new --bin yew-app && cd yew-app
然后,在 Cargo.toml 中添加 Yew 依赖:
[package]
name = "yew-app"
version = "0.1.0"
authors = ["Yew App Developer <name@example.com>"]
edition = "2018"
[dependencies]
yew = { version = "0.14.3", features = ["std_web"] }
然后,编写代码文件 src/main.rs,添加代码
use yew::prelude::*;
struct Model {
link: ComponentLink<Self>,
value: i64,
}
enum Msg {
AddOne,
}
impl Component for Model {
type Message = Msg;
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
value: 0,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::AddOne => self.value += 1
}
true // 指示组件应该重新渲染
}
fn view(&self) -> Html {
html! {
<div>
<button onclick=self.link.callback(|_| Msg::AddOne)>{ "+1" }</button>
<p>{ self.value }</p>
</div>
}
}
}
fn main() {
yew::initialize();
App::<Model>::new().mount_to_body();
}
可以看到,代码中定义了一个名为 Model 的组件,它还包含了一个 value 的数值属性。在 Model 的 view 方法中,通过特有的 html! 宏,以类似 JSX 的方式返回了该组件的 HTML 构成:由一个 div 容器,包裹这一个按钮和一个文本段落。其中文本显示 Model 的 value 属性;而按钮设置了点击事件的回调,每次点击就会为 value 的值加 1。最后,在 main 函数中,进行 yew 的初始化,并实例化 Model,把其挂载到应用的 body 上。
使用 cargon-web 运行:
cargo web start
cargo-web 就会自动构建应用,并启动一个开发服务器,这个应用就可以在 http://[::1]:8000 被访问。访问服务,就可以看到一个按钮和一个数字显示,每次点击按钮,数字就会加 1。一个简单的 WSAM 前端应用就完成了。
Yew 还可以实现定制化的组件,来替代原生的元素,实现更为复杂的功能。
use yew::prelude::*;
pub struct Button {
link: ComponentLink<Self>,
title: String,
onsignal: Callback<()>,
}
pub enum Msg {
Clicked,
}
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
#[prop_or_default]
pub title: String,
pub onsignal: Callback<()>,
}
impl Component for Button {
type Message = Msg;
type Properties = Props;
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
Button {
link,
title: props.title,
onsignal: props.onsignal,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::Clicked => {
self.onsignal.emit(());
}
}
false
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
self.title = props.title;
self.onsignal = props.onsignal;
true
}
fn view(&self) -> Html {
html! {
<button onclick=self.link.callback(|_| Msg::Clicked)>
{ &self.title }
</button>
}
}
}
在这个例子中,我们实现了一个定制的按钮,把按钮的创建、更新、修改和渲染都进行了重新的实现,添加了一个自定义的属性变量 title。在应用中,我们就可以直接使用这个自定义的按钮,替换原生的 button,实现更为复杂的功能。
总结
Yew 作为一个 WASM 框架,既拥有 Rust 语言带来的类型安全和极致性能,又以其先进的设计,引入了类似 JSX 的方式实现了方便的渲染,遵循了组件化的设计思想,并简化了与 Javascript 之间的交互,使得使用 WASM 快速开发一个大型前端应用成为可能。