嘗試用 Rust - Yew 寫高性能前端頁面
作者:騰訊 @Edward https://zhuanlan.zhihu.com/p/101118828
前言
看到這篇文章,可能很多人會有個疑問:“已經有 React + TypeScript 這麼好的組合,爲什麼還想着使用 Rust 來寫前端頁面,不折騰嗎?”
首先值得討論的一點,接下來幾年的前端方向有哪些?
個人的愚見,在全棧領域必然是 serverless,我在業務開發中已經嚐到甜頭,高效、簡便、心智負擔很低了;而在 Web 領域,由於 2019 年 12 月 5 日— 萬維網聯盟(W3C)宣佈 WebAssembly 核心規範成爲正式標準,WASM 勢必它的影響力會逐步提升。
WASM 的框架 / 庫的選擇已經比較豐富了,如:C# + Blazor、Go + Vugu、Rust + Yew 等等。
可能有人會問,爲什麼不能使用 TypeScript / JavaScript 來編譯到 WASM,歸根結底是因爲 WASM 要求語言必須是靜態強類型。當然可以魔改 TypeScript / JavaScript 做到這一點,例如 AssemblyScript / TurboScript 就是如此在 TypeScript / JavaScript 上做靜態規範的。與其如此魔改,我個人覺得倒不如大大方方的使用靜態強類型語言來編譯到 WASM,反正魔改後也無法共享原有的生態。
那麼爲什麼選擇 Rust 而不是其他的諸如 Go、C#、C / C++ 呢?這個確實沒有很有說服力的理由,只是出於個人的技術偏好,或者說是受到 RY 使用 Rust 實現 Deno 的鼓舞吧。
準備
環境陳述
我使用的是 macOS,很多人自然會想到使用 homebrew 來完成 Rust 環境 setup。一開始我也是這麼做的,不過會遇到下面問題:
error[E0463]: can't find crate for `std` | = note: the `wasm32-unknown-unknown` target may not be installed
最後還是走官方推薦的方式解決的。
Rust Installation
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Yew Installation
cargo install wasm-pack
cargo install cargo-web
上手
一些說明
Rust 本身就能實現編譯到 WASM,使用 Yew 框架的原因就如其官網宣傳:只是爲了方便前端組件整合,以及對 JavaScript 互通性的考量。
項目初始化
這裏不採用官網提供的參考,因爲示例過於簡單,有些脫離真正應用場景。下面的步驟是我個人認爲比較接近真實開發的狀態,相關源碼我也放到 GitHub 供大家玩耍 ➡️ https://github.com/SASUKE40/yew-starter
git clone --depth=1 https://github.com/SASUKE40/yew-starter.git <project_name>
目錄結構
.
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── index.html
├── index.js
├── package-lock.json
├── package.json
└── src
├── app.rs
└── lib.rs
這裏面最重要的就是 Cargo.toml
了,其中最關鍵的依賴如下:
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
yew = "0.10.0"
cdylib
是用於配置構建 C interoperability(C FFI),wasm-bindgen
依賴是用於 WASM 模塊和 JavaScript 之間的交互粘合。
加載 WASM 以及 bind 的過程
mod app;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn run_app() -> Result<(), JsValue> {
yew::start_app::<app::App>();
Ok(())
}
在需要導出 Rust 函數到 JavaScript 中,只需要在函數方法上註釋 #[wasm_bindgen]
即可,接着在 js 文件中導入使用
import {run_app} from "./lib";
run_app();
構建套件
使用 Parcel 是最方便的,開箱即用。既可以直接 import rs,也可以 import wasm。
img
我這裏用了 parcel-plugin-wasm.rs
插件完成 Cargo loader 的工作,和上述 import rs 的方式不同:
import {run_app} from './Cargo.toml';
run_app();
Yew 組件編寫體驗
Yew 框架使用 html!
macro 來生成 HTML
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
App {}
}
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
true
}
fn view(&self) -> Html<Self> {
html! {
<p>{ "Hello world!" }</p>
}
}
}
模板中可以使用 html! { "Hello, World" }
這樣的方式包裹文本或變量,這和 jsx 比較類似。事件綁定、條件、循環也都是類似的,大同小異:
// 點擊事件
html!{
<button onclick=|_| Msg::Click>{ "Click Me!" }</button>
}
// 條件渲染
html! {
<div>
{
if show_link {
html! {
<a href="https://example.com">{"Link"}</a>
}
} else {
html! {}
}
}
</div>
}
// 迭代渲染
html! {
<ul class="item-list">
{ for self.props.items.iter().map(renderItem) }
</ul>
}
效果
Navigate to https://yew-starter.netlify.com/
img
實際上 WASM 沒有大家相信的那麼 “便攜小巧”,WASM 喫掉的體積有 50kb。
總結
其優勢:
-
WebAssembly 在桌面客戶端移植到 Web 不可或缺,Office 就是個很好的例子
-
作爲膠水包存在,如某面包姐姐
https://www.zhihu.com/people/162ccc644cf995643b8a635f912f8c7b
最近就在嘗試 Rust 2 WASM(CPP) 2 Node.js
其疑點:
-
高性能,感覺沒有很突出到必須得這麼做
-
可移植性,要做 Web 的 JVM?
WASM 的生態日趨豐富完善,未來 WASM 在前端必然會大放異彩。不過也無需誇大其地位,可以參考
WebAssembly 的出現是否會取代 JavaScript?www.zhihu.com
這個知乎回答。摘抄官方對其定位的https://link.zhihu.com/?target=https%3A//webassembly.org/docs/faq/
:WebAssembly 旨在作爲 JavaScript 的補充而不是替代。
img
通宵寫文,求 求關注,不勝感激 ⬇️
https://github.com/SASUKE40/yew-startergithub.com
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/j7SYLY6CrnEA32t7WmX3qQ