WASM 不是一种编程语言🙂。简而言之,它是一种将用一种编程语言编写的代码转换为浏览器可理解的机器代码(JavaScript)的技术。
WASM (WebAssembly 的缩写)被设计为其他语言的编译目标,允许服务器端代码(如 C 或 C++代码)被编译成 WASM 并在浏览器中执行。
也被称作 web 汇编。
Hello World
1. 安装
cargo install cargo-generate
cargo install wasm-pack
npm install npm@latest -g
2. 初始化项目
cargo generate --git https://github.com/rustwasm/wasm-pack-template
项目命名为 first-wasm
3. 构建项目
项目根目录执行
wasm-pack build
构建完成后会生成 pkg 目录。
4. 生成页面
node 初始化一个前端项目,在根目录执行。
npm init wasm-app www
项目中会出现一个 www 目录,
进入到 www 中,安装 node 依赖
npm install
5. 页面使用我们的代码
- 在 pkg 目录下执行
npm link
pkg 文件夹中会出现 package.json 文件
- 在 www 中执行
npm link first-wasm
- 修改 /www/index.js
import * as wasm from 'first-wasm';
6. 启动
npm run start

如果要修改 alert 显示的内容,修改 rust 代码 lib.rs 中的 greet 方法。
Rust to wasm
上面的例子是使用的 cargo generate 直接生成的模板,
按照 https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm 里的步骤
可以自己一步一步实现 rust 编译为 wasm。
1. install Rust
2. cargo install wasm-pack
3. cargo new --lib hello-wasm
4. lib.rs 中编写 wasm 代码
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
添加依赖
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen="0.2"
5. build
wasm-pack build --target web
现在的目录结构
├── Cargo.lock
├── Cargo.toml
├── index.html
├── pkg
│ ├── hello_wasm.d.ts
│ ├── hello_wasm.js
│ ├── hello_wasm_bg.wasm
│ ├── hello_wasm_bg.wasm.d.ts
│ └── package.json
├── src
│ └── lib.rs
└── target
├── CACHEDIR.TAG
├── release
└── wasm32-unknown-unknown
6. Using the package on the web
编写一个 html 页面,使用 hello_wasm.js
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>hello-wasm example</title>
</head>
<body>
<script type="module">
import init, { greet } from "./pkg/hello_wasm.js";
init().then(() => {
greet("WebAssembly");
});
</script>
</body>
</html>
启动一个 server 服务
python3 -m http.server

至此,一个简单的 wasm 就运行起来了。
7. Making our package available to npm
重新编译
如果想要在 node 中使用 wasm,重新编译代码,使用 bundler 模式
wasm-pack build --target bundler
npm link
Next, let's use npm link to make this package available to other JavaScript packages installed
cd pkg
npm link
We now have an npm package, written in Rust, but compiled to WebAssembly. It's ready for use from JavaScript, and doesn't require the user to have Rust installed; the code included was the WebAssembly code, not the Rust source.
Using the npm package on the web
根目录中创建新的文件夹,site
mkdir site
cd site
npm link hello-wasm
site 文件夹中创建 package.json、webpack.config.js、index.js、index.html
package.json
{
"scripts": {
"serve": "webpack-dev-server"
},
"dependencies": {
"hello-wasm": "^0.1.0"
},
"devDependencies": {
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
}
}
webpack.config.js
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.js",
},
mode: "development",
};
index.js
import("./node_modules/hello-wasm/hello_wasm.js").then((js) => {
js.greet("WebAssembly with npm");
});
index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>hello-wasm example</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
site 的目录结构
├── index.html
├── index.js
├── node_modules
│ └── hello-wasm -> ../../pkg
├── package.json
└── webpack.config.js
在 site 文件夹中执行命令
npm install
npm run serve
出现的问题
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
先执行这条命令,然后在运行
export NODE_OPTIONS=--openssl-legacy-provider
以上就是 Rust 编译为 wasm 的过程。
补充
编译为 web
wasm-pack build --target web
编译为 bundler
wasm-pack build --target bundler
编译为 web,可以在 html 中直接引用。
编译为 bundler、nodejs,可以在 nodejs 中使用。
https://rustwasm.github.io/docs/wasm-pack/commands/build.html

https://xie.infoq.cn/article/0bb5ff2fa5d5d9db492c88a4c
https://llever.com/rustwasm-book/game-of-life/hello-world.zh.html
https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm
