ทดลอง Compile Rust เป็น WebAssembly
สืบเนื่องจากช่วงนี้ผมสนใจ WebAssembly เป็นพิเศษ เนื่องจากสนใจ Rust ด้วย และคิดว่ามันก็น่าสนใจ และมักจะเห็นคนพูดถึงสองตัวนี้บ่อยๆ ก็เลยพยายามศึกษาเรื่อยๆ เวลาว่างๆ เอาจริงๆ ก็ยังไม่ค่อยรู้อะไรเท่าไหร่ เน้นอ่าน ลองเล่น เข้าใจบ้าง ไม่เข้าใจบ้าง วันนี้ก็เลยมาเขียนบล็อกบันทึกเอาไว้ซะหน่อย
WebAssembly คืออะไร?
WebAssembly หรือ WASM คือ low level bytecode ที่รันบนเว็บ โดยเขียนได้หลายภาษา (ที่รองรับการ compile เป็น WASM) เช่น C/C++ หรือ Rust ตัว concept WASM คือเป็น binary format ที่สามารถทำงานร่วมกับ JavaScript ได้ และปัจจุบัน WASM ก็รองรับ Browser หลักๆ เกือบหมดแล้ว
เริ่มต้น WebAssembly
เริ่มจาก Getting Started จากเว็บ Official เลย จากนั้น ก็เลือกภาษา Rust ตัว Tutorial ก็จะเป็นของ Mozilla Developer
เราสามารถใช้ Rust และ WebAseembly ร่วมกันได้ แบบ 2 use cases ใหญ่ๆ คือ
- เขียนทั้งแอพด้วย Rust แล้ว compile เป็น WASM
- เขียนด้วย Rust แค่บางส่วน แล้วใช้ร่วมกับ JavaScript frontend ก็ได้
ตัว Rust/Wasm Framework ชื่อ yew เป็นอีกตัวที่ผมสนใจ เพราะดูคล้ายๆ React + Elm อยู่ใน list ที่ว่าจะลองศึกษาดู
Create Project
- ติดตั้ง Rust
เริ่มต้น Install Rust ด้วย rustup - หากไม่เคยติดตั้ง แนะนำ อ่านเพิ่มเติม มาหัดเขียนโปรแกรมด้วยภาษา Rust กันเถอะ
- ติดตั้ง wasm-pack - เป็นตัวช่วยที่ให้เรา build ไฟล์ Rust เป็น WASM รวมถึง build package ที่สามารถไปรันบน Browser ได้เลย
cargo install wasm-pack
- สร้าง folder ใหม่ ชื่อ
hello-wasm
cargo new --lib hello-wasm
จะมีไฟล์ในโฟลเดอร์ hello-wasm
แบบนี้
├── Cargo.toml
└── src
└── lib.rs
1 directory, 2 files
เพิ่ม wasm-bindgen ใน Cargo.toml
และ [lib]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2.80"
แนะนำ Rust Analyzer เป็น VS Code Extension สำหรับเขียนภาษา Rust
- Update
lib.rs
เป็นโค๊ดที่ใช้wasm_bindgen
(ใช้สำหรับเขียน Rust กับ JavaScript เช่น Rust เรียก function JavaScript หรือ JS เรียก Rust ได้)
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
จากโค๊ดนี้เราสามารถเรียก alert()
ที่เป็น JavaScript function จาก Rust ได้
- Compile โปรแกรมดู เพื่อ compile จาก Rust เป็น WebAssembly
wasm-pack build --target web
จะได้ผลลัพธ์ประมาณนี้
[WARN]: ⚠️ origin crate has no README
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: found wasm-opt at "/opt/homebrew/bin/wasm-opt"
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ✨ Done in 5.49s
[INFO]: 📦 Your wasm pkg is ready to publish at /dev/hello-wasm/pkg.
เราจะได้โฟลเดอร์ pkg
ข้างในมี WASM และไฟล์ JavaScript ที่เราสามารถเอาไปใช้บนเว็บได้เลย
WASM on Web
ตัวอย่าง ลองสร้างไฟล์ index.html ง่ายๆ ขึ้นมา
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello WASM</title>
</head>
<body>
<script type="module">
import init, { greet } from './pkg/hello_wasm.js';
init().then(() => {
greet("WebAssembly");
});
</script>
</body>
</html>
ลอง Start server จากไฟล์ index.html
npx serve
จะได้เว็บ http://localhost:3000
หรือใครใช้ Python ก็รัน
python3 -m http.server
จะได้เว็บ http://localhost:8000
เมื่อลองเปิดเว็บ จะเห็น Alert popup ว่า Hello, WebAssembly!
สิ่งที่สังเกต จะเห็นว่า JavaScript เรียก function ชื่อ greet()
ซึ่ง function นี้คือ function ใน lib.rs
ที่เขียนด้วยภาษา Rust เพื่อ alert JavaScript ผ่าน wasm-bindgen
นั่นเอง
สรุป
WASM เป็นอะไรที่น่าสนใจมากสำหรับผม และก็เป็นอะไรที่ค่อนข้างยากเช่นกัน สิ่งที่ผมเรียนรู้ได้ ก็คือพยายามฝึก หัดลอง ทำนู้นทำนี่ แล้วเดี๋ยวมันก็จะเริ่มเข้าใจอะไรมากขึ้นเอง พอจับต้นชนปลายได้ นิดๆหน่อยๆ ก็เป็นอะไรที่น่าสนุกดี แม้ว่าตอนนี้บอกตรงๆ ว่ายังไม่รู้ว่าจะเอามาทำอะไร 🤣
References
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit