- 簡介
- 架構
- Application 和元件
- 簡單入門示例
- 先決條件
- 建立專案
- 編譯庫檔案
- 引用庫檔案
- 執行專案
- 介面互動示例
- 建立專案
- 編譯庫檔案
- 實現應用函式
- 引用庫檔案
- 執行專案
- 參考資料
簡介
Sauron 是一個多功能的 Web 框架和庫,用於構建客戶端和/或伺服器端 Web 應用程式,重點關注人體工程學、簡單性和優雅性。這使您可以編寫儘可能少的程式碼,並更多地關注業務邏輯而不是框架的內部細節。
github:https://github.com/ivanceras/sauron
文件:https://sauron-rs.github.io/
架構
Sauron 遵循模型-檢視-更新架構(也稱為 Elm 架構),它總是分為三個部分:
- 模型 - 應用程式的狀態
- 檢視 - 一種將狀態轉換為 HTML 的方法
- 更新 - 一種根據訊息更新狀態的方法
Application 和元件
為了使模型在 Sauron 程式中執行,它必須實現 Application trait,然後定義下面兩個函式:
- view 函式:該函式告訴程式如何顯示模型。
- update 函式:該函式描述如何根據訊息更新模型狀態。
簡單入門示例
先決條件
確保已安裝所有必備元件:
- rust and cargo:Rust基礎環境和工具。
- wasm-pack:將 rust 程式碼編譯到 webassembly 中,然後放入 ./pkg 目錄中。
- basic-http-server:在本地提供靜態檔案。
執行以下命令安裝wasm-pack:
cargo install wasm-pack
執行以下命令安裝basic-http-server:
cargo install basic-http-server
wasm-pack 預設會使用 wasm-opt 工具進行大小最佳化,而這個工具也是執行時下載安裝的。下載 wasm-opt 使用的是 github 連結,國內環境大機率是下載失敗的,可以參考 如何安裝WASM-OPT? 手動下載 wasm-opt.exe 後放到 .cargo\bin路徑下。
建立專案
建立一個名為 hello 的新專案:
cargo new --lib hello
在 Cargo.toml 中指定這個 crate 需要編譯為 cdylib(動態系統庫):
[lib]
crate-type = ["cdylib"]
執行以下命令,新增sauron作為專案的依賴項。
cargo add sauron
編譯庫檔案
修改 src/lib.rs程式碼,在段落中顯示“hello”文字:
use sauron::{node, wasm_bindgen, Application, Cmd, Node, Program};
struct App;
impl Application<()> for App {
fn view(&self) -> Node<()> {
node! {
<p>
"hello"
</p>
}
}
fn update(&mut self, _msg: ()) -> Cmd<Self, ()> {
Cmd::none()
}
}
//函式應該在載入 wasm 模組時自動啟動,類似於 main 函式
#[wasm_bindgen(start)]
pub fn main() {
Program::mount_to_body(App::new());
}
- view 方法中使用 node! 宏,採用類似 html 的語法來顯示應用程式。
- 為 App 實現 Application 特徵,實現必要的方法來告訴 sauron 應用程式的行為。
- 這裡的 main 函式在載入 wasm 模組時自動啟動,函式可以任意命名,只要配置 start 即可。
執行以下命令進行編譯:
wasm-pack build --release --target=web
編譯時間稍微有點長,wasm-pack 會在專案中建立一個資料夾 ./pkg,裡面包含生成的編譯檔案,只需要關注其中 2 個檔案:
hello.js
hello_bg.wasm
它們的名稱派生自給定的包名稱 <package_name>.js 和 <package_name>_bg.wasm。
引用庫檔案
在專案的根目錄中建立 index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<script type=module>
import init from './pkg/hello.js';
await init().catch(console.error);
</script>
</body>
</html>
- 使用的是 <script type=module>, 從 ./pkg 資料夾中引用了 ./pkg/hello.js 。
- 在後臺,./pkg/hello.js 將負責在後臺載入 ./pkg/hello_bg.wasm。
執行專案
重新編譯webapp,每次對 rust 程式碼進行更改時發出此命令。
wasm-pack build --release --target=web
最後使用 basic-http-server 提供檔案:
basic-http-server
預設情況下,它在埠 4000 中提供頁面,導航到 http://127.0.0.1:4000 以檢視“hello”訊息。
介面互動示例
在瀏覽器中顯示 3 個按鈕,單擊這些按鈕可以增加/減少和重置計數。
建立專案
建立一個名為 counter 的新 rust 庫專案:
cargo new --lib counter
接下來修改 crate 型別為 “cdylib” 庫 ,新增 sauron 依賴,這裡不在贅述。
編譯庫檔案
在 src/lib.rs 中放入此程式碼:
use sauron::prelude::*;
use sauron::node;
struct App {
count: i32,
}
//新增了一個函式 new 來建立以 count 0 開頭的初始狀態 App
impl App {
fn new() -> Self {
App { count: 0 }
}
}
定義應用程式將具有的一組操作:
enum Msg {
Increment,
Decrement,
Reset,
}
為模型 App 實現 Application 特徵:
impl Application<Msg> for App {
fn view(&self) -> Node<Msg> {
node! {
<main>
<input type="button"
value="+"
on_click=|_| {
Msg::Increment
}
/>
<button class="count" on_click=|_|{Msg::Reset} >{text(self.count)}</button>
<input type="button"
value="-"
on_click=|_| {
Msg::Decrement
}
/>
</main>
}
}
fn update(&mut self, msg: Msg) -> Cmd<Self, Msg> {
match msg {
Msg::Increment => self.count += 1,
Msg::Decrement => self.count -= 1,
Msg::Reset => self.count = 0,
}
Cmd::none()
}
}
- view 方法返回型別為 Node<Msg>,這意味著它建立一個 html 節點,其中它的任何成員 html 元素都有一個事件偵聽器,該事件偵聽器可以向程式處理程式發出 Msg 訊息。
- update 方法接受 Msg 作為引數,並根據 Msg 的變體修改模型 App。
實現應用函式
接下來為 wasm Web 應用定義入口點,透過使用 #[wasm_bindgen(start)] 註釋公共函式來完成:
#[wasm_bindgen(start)]
pub fn start() {
Program::mount_to_body(App::new());
}
為了演示純函式互動,這裡再新增一個簡單的加法函式:
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
如果只需要js呼叫Rust的函式,那隻需要新增 wasm_bindgen 依賴即可,參考 使用Rust和WebAssembly整花活兒(一)——快速開始。
引用庫檔案
在專案基本資料夾的 index.html 檔案中連結應用,可以像往常一樣放置樣式:
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<title>Counter</title>
<style type="text/css">
body { font-family: verdana, arial, monospace; }
main {
width:30px;
height: 100px;
margin:auto;
text-align: center;
}
input, .count{
font-size: 40px;
padding: 30px;
margin: 30px;
}
</style>
<script type=module>
import init, { add } from './pkg/counter.js';
await init().catch(console.error);
const result = add(1, 2);
console.log(`the result from rust is: ${result}`);
</script>
</head>
<body>
</body>
</html>
注意上面的 import init, { add } from ,add 函式在使用前需要匯入,否則會呼叫失敗。
執行專案
編譯庫檔案:
wasm-pack build --release --target=web
啟動靜態站點:
basic-http-server
訪問 http://127.0.0.1:4000 檢視效果:
參考資料
- 如何安裝WASM-OPT?
- 國內網路環境下配置 wasm 開發環境
- 使用Rust和WebAssembly整花活兒(一)——快速開始