ç¼è¯ Rust 为 WebAssembly
å¦æä½ åäºä¸äº Rust 代ç ï¼ä½ å¯ä»¥æå®ç¼è¯æ WebAssemblyï¼è¿ä»½æç¨å°å¸¦ä½ ç¼è¯ Rust 项ç®ä¸º wasm å¹¶å¨ä¸ä¸ªç°åç web åºç¨ä¸ä½¿ç¨å®ã
Rust å WebAssembly ç¨ä¾
Rust å WebAssembly æä¸¤å¤§ä¸»è¦ç¨ä¾ï¼
- æå»ºå®æ´åºç¨ââæ´ä¸ª Web åºç¨é½åºäº Rust å¼åï¼
- æå»ºåºç¨çç»æé¨åââå¨ç°åç JavaScript å端ä¸ä½¿ç¨ Rustã
ç®åï¼Rust å¢éæ£ä¸æ³¨äºç¬¬äºç§ç¨ä¾ï¼å æ¤æä»¬ä¹å°çéä»ç»å®ã对äºç¬¬ä¸ç§ç¨ä¾ï¼å¯ä»¥åé
yew è¿ç±»é¡¹ç®ã
卿¬æç¨ä¸ï¼æä»¬å°ä½¿ç¨ Rust ç npm å
æå»ºå·¥å
· wasm-pack æ¥æå»ºä¸ä¸ª npm å
ãè¿ä¸ªå
åªå
å« WebAssembly å JavaScript 代ç ï¼ä»¥ä¾¿å
çç¨æ·æ éå®è£
Rust å°±è½ä½¿ç¨ãä»ä»¬çè³ä¸éè¦ç¥éè¿éå
å« WebAssemblyï¼
å®è£ Rust ç¯å¢
让æä»¬ççå®è£ Rust ç¯å¢çææå¿ è¦æ¥éª¤ã
å®è£ Rust
åå¾ Install Rust 页é¢å¹¶è·éæç¤ºå®è£
Rustãè¿éä¼å®è£
ä¸ä¸ªå为ârustupâçå·¥å
·ï¼è¿ä¸ªå·¥å
·è½è®©ä½ 管çå¤ä¸ªä¸åçæ¬ç Rustãé»è®¤æ
åµä¸ï¼å®ä¼å®è£
ç¨äºæ¯å¸¸ Rust å¼åç stable çæ¬ Rust ReleaseãRustup ä¼å®è£
Rust çç¼è¯å¨ rustcãRust çå
管çå·¥å
· cargoãRust çæ ååº rust-std 以åä¸äºæç¨çææ¡£ rust-docsã
夿³¨ï¼éè¦æ³¨æï¼å¨å®è£
宿åï¼ä½ éè¦æ cargo ç bin ç®å½æ·»å å°ä½ ç³»ç»ç PATHãä¸è¬æ¥è¯´å®ä¼èªå¨æ·»å ï¼ä½éè¦ä½ éå¯ç»ç«¯åæä¼çæã
wasm-pack
è¦æå»ºæä»¬çå
ï¼æä»¬éè¦ä¸ä¸ªé¢å¤å·¥å
· wasm-packãå®ä¼å¸®å©æä»¬ææä»¬ç代ç ç¼è¯æ WebAssembly å¹¶å¶é åºæ£ç¡®ç npm å
ã使ç¨ä¸é¢çå½ä»¤å¯ä»¥ä¸è½½å¹¶å®è£
å®ï¼
cargo install wasm-pack
å®è£ Node.js å¹¶è·å npm è´¦æ·
å¨è¿ä¸ªä¾å䏿们å°ä¼æå»ºä¸ä¸ª npm å ï¼å æ¤ä½ éè¦ç¡®ä¿å®è£ Node.js å npm å·²ç»å®è£ ãå¦å¤ï¼æä»¬å°ä¼æå åå¸å° npm ä¸ï¼å æ¤ä½ è¿éè¦ä¸ä¸ª npm è´¦å·ãå®ä»¬æ¯å è´¹çãåå¸è¿ä¸ªå 并䏿¯å¿ é¡»çï¼ä½æ¯åå¸å®é常ç®åï¼å æ¤å¨æ¬ä¾ä¸æä»¬é»è®¤ä½ ä¼åå¸è¿ä¸ªå ã
å¨ Get npm! é¡µé¢æç §è¯´æä¸è½½å¹¶å®è£ Node.js å npmãå¨éæ©çæ¬æ¶ï¼éæ©ä¸ä¸ªä½ 忬¢ççæ¬ï¼æ¬ä¾ä¸éå®ç¹å®çæ¬ã
å¨ npm signup page 注å npm è´¦æ·ï¼å¹¶å¡«åè¡¨æ ¼ã
æ¥ä¸æ¥ï¼å¨å½ä»¤è¡ä¸è¿è¡ npm adduser:
> npm adduser
Username: yournpmusername
Password:
Email: (this IS public) you@example.com
ä½ éè¦å®åä½ çç¨æ·åï¼å¯ç åé®ç®±ã妿æåäºï¼ä½ å°ä¼çå°ï¼
Logged in as yournpmusername on https://registry.npmjs.org/.
å¦æå¹¶æªæ£å¸¸è¿è¡ï¼è¯·èç³» npm è§£å³ã
æå»ºæä»¬ç WebAssembly npm å
ä¸äºä¿±å¤ï¼æ¥å建ä¸ä¸ªæ°ç Rust å å§ãæå¼ä½ ç¨æ¥åæ¾ä½ ç§äººé¡¹ç®çç®å½ï¼åè¿äºäºï¼
$ cargo new --lib hello-wasm
Created library `hello-wasm` project
è¿éä¼å¨å为 hello-wasm çåç®å½éå建ä¸ä¸ªæ°çåºï¼é颿ä¸ä¸æ¥ä¹åä½ æéè¦çä¸åï¼
+-- Cargo.toml
+-- src
+-- lib.rs
é¦å
ï¼æä»¬æä¸ä¸ª Cargo.toml æä»¶ï¼è¿æ¯æä»¬é
ç½®æå»ºçæ¹å¼ãå¦æä½ ç¨è¿ Bundler ç Gemfile æè
npm ç package.jsonï¼ä½ åºè¯¥ä¼æå°å¾çæãCargo çç¨æ³åå®ä»¬ç±»ä¼¼ã
æ¥ä¸æ¥ï¼Cargo å¨ src/lib.rs çæäºä¸äº Rust 代ç ï¼
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
æä»¬å®å ¨ä¸éè¦ä½¿ç¨è¿äºæµè¯ä»£ç ï¼æä»¥ç»§ç»å§ï¼æä»¬å æå®ã
æ¥åç¹ Rust 代ç å§ï¼
让æä»¬å¨ src/lib.rs åä¸äºä»£ç æ¿æ¢æåæ¥çï¼
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
è¿å°±æ¯æä»¬è¿ä¸ª Rust 项ç®çå 容ã宿ä¸ä¸ªä¸»è¦é¨åï¼è®©æä»¬æé¡ºåºæ¥è®²ãè¿éå°ä¼ç»åºä¸ä¸ªç¼ºå°é¨åç»èçé«çº§è¯´æï¼å¦ææ³è¦äºè§£æ´å¤ Rust ç¥è¯ï¼è¯·æ¥çå¨çº¿ä¹¦ç± The Rust Programming Languageã
ä½¿ç¨ wasm-bindgen å¨ Rust ä¸ JavaScript ä¹é´éä¿¡
第ä¸é¨åçèµ·æ¥åè¿æ ·ï¼
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
第ä¸è¡å°±åå¨è¯´âå Rustï¼æä»¬å¨ç¨ä¸ä¸ªå«å wasm_bindgen çåºâãå¨ Rust å½ä¸ï¼åºè¢«ç§°ä¸ºâcratesâï¼å 为æä»¬ä½¿ç¨çæ¯ä¸ä¸ªå¤é¨åºï¼æä»¥æ "extern"ã
æç½äºåï¼ Cargo ships crates.
第ä¸è¡å
æ¬äºä¸ä¸ªå°åºä¸ç代ç å¼å
¥å°ä½ ç代ç ä¸ç使ç¨å½ä»¤ãå¨è¿ä¸ªæ
åµä¸ï¼å°ä¼å¼å
¥ wasm_bindgen::prelude çå
¨é¨æ¨¡åãæä»¬å°å¨ä¸ä¸èä¸ä½¿ç¨è¿äºå
容ã
卿们å¼å§ä¸ä¸èä¹åï¼æä»¬å°è®²ä¸è®² wasm-bindgenã
wasm-pack 使ç¨å¦ä¸ä¸ªå·¥å
· wasm-bindgen æ¥æä¾ JavaScript å Rust ç±»åä¹é´çæ¡¥æ¢ãå®å
许 JavaScript 使ç¨å符串è°ç¨ Rust APIï¼æè°ç¨ Rust 彿°æ¥æè· JavaScript å¼å¸¸ã
æä»¬å°å¨æä»¬çå
ä¸ä½¿ç¨ wasm-bindgen çåè½ãäºå®ä¸ï¼è¿æ¯ä¸ä¸èçå
容ï¼
å¨ Rust ä¸è°ç¨æ¥èª JavaScript çå¤é¨å½æ°
æ¥ä¸æ¥çé¨åçèµ·æ¥åè¿æ ·ï¼
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
å¨ #[] ä¸çå
容å«å "屿§"ï¼å¹¶ä»¥æç§æ¹å¼æ¹åä¸é¢çè¯å¥ãå¨è¿ç§æ
åµä¸ï¼ä¸é¢çè¯å¥æ¯ä¸ä¸ª externï¼å®å°åè¯ Rust that æä»¬æ³è°ç¨ä¸äºå¤é¨å®ä¹ç彿°ãè¿ä¸ªå±æ§åè¯æä»¬ "wasm-bindgen ç¥éå¦ä½æ¾å°è¿äºå½æ°"ã
第ä¸è¡æ¯ç¨ Rust åç彿°ç¾åãå®åè¯æä»¬ "alert 彿°æ¥åä¸ä¸ªå«å s çå符串ä½ä¸ºåæ°ã"
ä½ å¯è½ä¼çæè¿ä¸ªå½æ°æ¯ä»ä¹ï¼ä½ ççæå¯è½æ¯æ£ç¡®çï¼è¿æ¯ the alert function provided by JavaScriptï¼æä»¬å°å¨ä¸ä¸èä¸è°ç¨è¿ä¸ªå½æ°ã
å½ä½ æ³è°ç¨æ°ç JavaScript 彿°æ¶ï¼ä½ å¯ä»¥å¨è¿éåä»ä»¬ï¼wasm-bindgen å°è´è´£ä¸ºä½ 设置ä¸åãå¹¶éä¸åé½å¾å°æ¯æï¼ä½æä»¬æ£å¨åªåï¼å¦æç¼ºå°æäºå
容ï¼è¯· file bugs ã
ç¼åè½å¤å¨ JavaScript ä¸è°ç¨ç Rust 彿°
æåä¸é¨åæ¯è¿æ ·çï¼
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
æä»¬åçå°äº #[wasm_bindgen] 屿§ãå¨è¿éï¼å®å¹¶éå®ä¹ä¸ä¸ª extern åï¼èæ¯ fnï¼è¿ä»£è¡¨æä»¬å¸æè½å¤å¨ JavaScript ä¸ä½¿ç¨è¿ä¸ª Rust 彿°ãè¿å extern æ£ç¸åï¼æä»¬å¹¶éå¼å
¥å½æ°ï¼èæ¯è¦æå½æ°ç»å¤é¨ä¸ç使ç¨ã
è¿ä¸ªå½æ°çå忝 greetï¼å®éè¦ä¸ä¸ªåæ°ï¼ä¸ä¸ªå符串ï¼åä½ &strï¼ãå®è°ç¨äºæä»¬åé¢å¨ extern åä¸å¼å
¥ç alert 彿°ãå®ä¼ éäºä¸ä¸ªè®©æä»¬ä¸²èå符串ç format! å®çè°ç¨ã
format! å¨è¿éæä¸¤ä¸ªåæ°ï¼ä¸ä¸ªæ ¼å¼åå符串åä¸ä¸ªè¦å¡«å
¥çåéãæ ¼å¼ååç¬¦ä¸²æ¯ "Hello, {}!" é¨åãå®å¯ä»¥å
å«ä¸ä¸ªæå¤ä¸ª {}ï¼åéå°ä¼è¢«å¡«å
¥å
¶ä¸ãä¼ éçå鿝 nameï¼ä¹å°±æ¯è¿ä¸ªå½æ°çåæ°ãæä»¥å½æä»¬è°ç¨ greet("Steve")æ¶æä»¬å°±è½çå° "Hello, Steve!"ã
ä¸è¿°åç¬¦ä¸²è¢«ä¼ éå°äº alert()ï¼æä»¥å½æä»¬è°ç¨è¿ä¸ªå½æ°æ¶ï¼æä»¬åºè¯¥è½çå°ä¸ä¸ªæ¶æ¯æ¡å¼¹åºï¼å
¶ä¸çå
容为âHello, Steve!âã
æä»¬çåºåå®äºï¼æ¯æ¶åæå»ºå®äºã
ææä»¬ç代ç ç¼è¯å° WebAssembly
为äºè½å¤æ£ç¡®çç¼è¯æä»¬ç代ç ï¼é¦å
æä»¬éè¦é
ç½® Cargo.tomlãæå¼è¿ä¸ªæä»¶ï¼å°å
容æ¹ä¸ºå¦ä¸æç¤ºï¼
[package]
name = "hello-wasm"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A sample project with wasm-pack"
license = "MIT/Apache-2.0"
repository = "https://github.com/yourgithubusername/hello-wasm"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
ä½ éè¦æ¹ä¸ºèªå·±çä»åºï¼åæ¶ Cargo éè¦éè¿ git æ¥å®å authors é¨åã
æéè¦çæ¯æ·»å åºä¸çé¨åã第ä¸ä¸ªé¨å â [lib] â åè¯ Rust 为æä»¬çå
建ç«ä¸ä¸ª cdylib çæ¬ï¼å¨æ¬æç¨ä¸æä»¬ä¸ä¼è®²è§£å®çå«ä¹ãæå
³æ´å¤ä¿¡æ¯ï¼è¯·åé
Cargo å Rust Linkage ææ¡£ã
第äºä¸ªé¨åæ¯ [dependencies] é¨åãå¨è¿éæä»¬åè¯ Cargo æä»¬éè¦ä¾èµåªä¸ªçæ¬ç wasm-bindgen ï¼å¨è¿ä¸ªä¾åä¸ï¼å®æ¯ 0.2.z çæ¬ç (䏿¯ 0.3.0 æè
å
¶ä»çæ¬)ã
æå»ºå
ç°å¨æä»¬å·²ç»å®æäºææé 置项ï¼å¼å§æå»ºå§ï¼å¨å½ä»¤è¡è¾å ¥ä»¥ä¸å½ä»¤ï¼
wasm-pack build --scope mynpmusername
è¿ä¸ªå½ä»¤å°åä¸ç³»åäºæ
(è¿ä¼è±ä¸äºæ¶é´ï¼ç¹å«æ¯å½ä½ ç¬¬ä¸æ¬¡è¿è¡ wasm-pack)ãæ³äºè§£è¯¦ç»æ
åµï¼æ¥çè¿ç¯å¨ Mozilla Hacks ä¸çæç« ãç®åæ¥è¯´ï¼wasm-pack build å°å以ä¸å ä»¶äºï¼
- å°ä½ ç Rust 代ç ç¼è¯æ WebAssemblyã
- å¨ç¼è¯å¥½ç WebAssembly 代ç åºç¡ä¸è¿è¡
wasm-bindgenï¼çæä¸ä¸ª JavaScript æä»¶å° WebAssembly æä»¶å è£ æä¸ä¸ªæ¨¡å以便 npm è½å¤è¯å«å®ã - å建ä¸ä¸ª
pkgæä»¶å¤¹å¹¶å° JavaScript æä»¶åçæç WebAssembly 代ç ç§»å°å ¶ä¸ã - 读åä½ ç
Cargo.tomlå¹¶çæç¸åºçpackage.jsonã - å¤å¶ä½ ç
README.md(妿æçè¯) 尿件夹ä¸ã
æåçç»æï¼ä½ å¨ pkg æä»¶å¤¹ä¸æäºä¸ä¸ª npm å
ã
对代ç ä½ç§¯çä¸äºè¯´æ
å¦æä½ æ£æ¥çæç WebAssembly æä»¶ä½ç§¯ï¼å®å¯è½æå ç¾ kBãæä»¬æ²¡æè®© Rust å»å缩çæç代ç ï¼ä»è大大åå°çæå çä½ç§¯ãè¿åæ¬æ¬¡æç¨ä¸»é¢æ å ³ï¼ä½å¦æä½ æ³äºè§£æ´å¤ï¼æ¥ç Rust WebAssembly å·¥ä½ç»ææ¡£ä¸å ³äº åå° .wasm ä½ç§¯ ç说æã
ææä»¬çå åå¸å° npm
ææä»¬çæ°å åå¸å° npm registry:
cd pkg
npm publish --access=public
æä»¬ç°å¨æäºä¸ä¸ª npm å ï¼ä½¿ç¨ Rust ç¼åï¼ä½å·²ç»è¢«ç¼è¯ä¸º WebAssembly äºãç°å¨è¿ä¸ªå å·²ç»å¯ä»¥è¢« JavaScript 使ç¨äºï¼èä¸ä½¿ç¨å®å®å ¨ä¸éè¦ç¨æ·å®è£ Rustï¼å ä¸çä»£ç æ¯ WebAssembly 代ç ï¼è䏿¯ Rust æºç ï¼
å¨ç½ç«ä¸ä½¿ç¨æä»¬çå
让æä»¬å»ºç«ä¸ä¸ªä½¿ç¨æä»¬å
çç½ç«ï¼äººä»¬éè¿åç§æå
å·¥å
·ä½¿ç¨ npm å
ï¼å¨æ¬æç¨ä¸ï¼æä»¬å°ä½¿ç¨ webpackã宿¯å
¶ä»æäºæå
å·¥å
·ç¨å¾®å¤æä¸ç¹ï¼ä½å±ç¤ºäºæ´å®é
çç¨æ³ã
让æä»¬ç¦»å¼pkgç®å½ï¼å¹¶å建ä¸ä¸ªæ°ç®å½siteï¼å°è¯ä»¥ä¸æä½ï¼
cd ../..
mkdir site
cd site
å建ä¸ä¸ªæ°æä»¶ package.jsonï¼ç¶åè¾å
¥å¦ä¸ä»£ç ï¼
{
"scripts": {
"serve": "webpack-dev-server"
},
"dependencies": {
"@mynpmusername/hello-wasm": "^0.1.0"
},
"devDependencies": {
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
}
}
请注æï¼ä½ éè¦å¨ä¾èµé¡¹é¨åç @ ä¹åå¡«åèªå·±çç¨æ·åã
æ¥ä¸æ¥ï¼æä»¬éè¦é
ç½® Webpackãå建 webpack.config.js å¹¶è¾å
¥ï¼
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
mode: "development",
};
ç°å¨æä»¬éè¦ä¸ä¸ª HTML æä»¶ãå建ä¸ä¸ªindex.htmlå¹¶åå
¥å¦ä¸å
容ï¼
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>hello-wasm example</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
æåï¼ä» HTML æä»¶ä¸å¼ç¨index.jsï¼
const js = import("./node_modules/@yournpmusername/hello-wasm/hello_wasm.js");
js.then((js) => {
js.greet("WebAssembly");
});
请注æï¼ä½ éè¦å次填åä½ ç npm ç¨æ·åã
è¿å°ä»node_modulesæä»¶å¤¹å¯¼å
¥æä»¬ç模åãè¿ä¸æ¯æä½³åæ³ï¼ä½è¿éåªåä¸ä¸ªæ¼ç¤ºï¼å æ¤ææ¶å°±è¿æ ·ç¨ãå è½½åï¼å®å°ä»è¯¥æ¨¡åè°ç¨greet彿°ï¼å¹¶ä¼ å
¥å符串âWebAssemblyâåæ°ãæ³¨æè¿éçä¸å»æ²¡æä»ä¹ç¹å«çï¼ä½æ¯æä»¬æ£å¨è°ç¨ Rust 代ç ï¼å°± JavaScript ä»£ç æç¥ï¼è¿åªæ¯ä¸ä¸ªæ®é模åã
æä»¬å·²ç»å®æäºææçæä»¶ï¼è®©æä»¬è¯ä¸ä¸ï¼
npm install
npm run serve
è¿å°å¯å¨ä¸ä¸ª Web æå¡å¨ãè®¿é® http://localhost:8080ï¼ä½ åºè¯¥ä¼å¨å±å¹ä¸çå°ä¸ä¸ªå
容为 Hello, WebAssembly! çè¦åæ¡ãæä»¬å·²ç»æåå°ä» JavaScript è°ç¨äº Rustï¼å¹¶ä» Rust è°ç¨äº JavaScriptã
ç»è®º
æ¬æç¨å°æ¤ç»æãå¸æä½ è§å¾å®æç¨ã
å¨è¿ä¸ªé¢åï¼æå¾å¤å·¥ä½æ£å¨æ¨è¿å½ä¸ãå¦æä½ å¸æå®å徿´å¥½ï¼å¯ä»¥åé Rust Webassembly å·¥ä½ç»ã