wasm 初体验

2023/07/13 11:25 上午 posted in  rust

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. 页面使用我们的代码

  1. 在 pkg 目录下执行
npm link

pkg 文件夹中会出现 package.json 文件

  1. 在 www 中执行
npm link first-wasm
  1. 修改 /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

https://rustwasm.github.io/docs/wasm-pack/introduction.html