【Rust】WASM 编译使用方法

最近比较好奇 Rust 编写 Web 前端

假设你已经安装了 Cargo 和 Nodejs

  1. 安装 openssl

    • Ubuntu

      1
      2
      sudo apt install libssl-dev
      sudo apt install pkg-config
    • Windows

      1. 安装 vcpkg

        1
        2
        3
        4
        5
        6
        # 建议安装到用户目录下
        cd $HOME
        # 拉取源代码
        git clone https://github.com/microsoft/vcpkg
        # 运行脚本
        .\vcpkg\bootstrap-vcpkg.bat
      2. 安装 openssl

        1
        2
        3
        4
        5
        6
        # 我们假设你是按上面的命令执行的安装
        cd $HOME
        # 使用命令安装64位openssl
        .\vcpkg\vcpkg install openssl:x64-windows-static
        # 查看安装目录
        ls .\vcpkg\packages
      3. 安装根证书

        1
        2
        3
        4
        5
        6
        7
        8
        # 我们假设你是按上面的命令执行的安装
        cd $HOME
        # 创建用于存放根证书的文件夹
        mkdir .\certs
        # 打开文件夹
        cd .\certs
        # 自动下载
        wget https://curl.se/ca/cacert.pem -o cacert.pem

        若要手动安装,请参考该页面

  2. 安装 wasm-pack

    它会帮助我们把我们的代码编译成 WebAssembly 并制造出正确的 npm 包

    若是参考上面的方法安装的 Windows 版本的Openssl,则需要设置环境变量

    设置 OPENSSL_NO_VENDOR1 是为了告诉 crate 使用预编译的 openssl 库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 设置临时环境变量
    set VCPKG_ROOT=$HOME\vcpkg
    set OPENSSL_NO_VENDOR=1
    set RUSTFLAGS=-Ctarget-feature=+crt-static
    set SSL_CERT_FILE=$HOME\certs\cacert.pem

    # 我在Win11上使用上面的命令设置未生效,特使用以下命令设置永久变量,然后重启终端生效
    setx VCPKG_ROOT $HOME\vcpkg
    setx OPENSSL_NO_VENDOR 1
    setx RUSTFLAGS -Ctarget-feature=+crt-static
    setx SSL_CERT_FILE $HOME\certs\cacert.pem

    然后安装它

    1
    cargo install wasm-pack
  3. 尝试编译一下 Plotters 的 WASM 例子

    这是个跨平台的 Rust 图标库,同样可以运行在浏览器上

    1
    2
    3
    4
    5
    6
    # 拉取代码
    git clone --recurse-submodules https://github.com/plotters-rs/plotters.git

    # 运行 WASM 的例程(务必进到文件夹中去运行脚本)
    cd .\plotters\examples\wasm-demo
    .\start-server.bat

    完成后保持终端运行,然后访问 http://localhost:8080/ 就可以看到页面了

  4. 接下来我们自己创建一个工程实现在网页上绘制动态图表的功能,其实主要就是想看看这个库用了 WASM 有多快

    okk,那我们先创建一个工程用于生成 wasm 的文件

    1
    cargo new --lib chart-wasm

    然后使用 VSCode 打开这个文件夹

    1
    code .\chart-wasm
  5. 编辑 Cargo.toml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [package]
    name = "chart-wasm"
    version = "0.1.0"
    edition = "2021"

    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

    [lib]
    crate-type = ["cdylib"]

    [dependencies]
    wasm-bindgen = "0.2"

    crate-type = ["cdylib"] 用于生成一个动态链接库,特定于平台的,我们这里将生成 .wasm 的动态链接库

  6. 编辑 ./src/lib.rs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 声明使用了外部库 wasm_bindgen
    extern crate wasm_bindgen;

    // 引入 wasm_bindgen::prelude 的所有模块
    use wasm_bindgen::prelude::*;

    // 设置 wasm_bindgen 属性告诉编译器如何引入下面extern里的函数
    #[wasm_bindgen]
    extern "C" {
    // 声明 Javascript 里的 alert 函数,传入类型是字符串
    pub fn alert(s: &str);
    }

    // 设置 wasm_bindgen 属性告诉编译器需要将这个函数导出
    #[wasm_bindgen]
    pub fn rust_alert(name: &str) {
    // 调用上面声明的 alert 函数像浏览器发送一个通知
    // 使用 format 宏可以格式化字符串,这里等于 "Hello, " + name + "!"
    alert(&format!("Hello, {}!", name));
    }
  7. 编译

    1
    2
    3
    4
    # 为 Rust 添加新的编译器
    rustup target add wasm32-unknown-unknown
    # 打包当前库为 WASM
    wasm-pack build --release --target web

    ok,最后打包的文件都在 ./pkg 目录下

    需要说明的是这里我们没有对包的体积进行压缩

  8. 使用它,这里使用的是 webpack(这个方法暂时不能使用)

    1. 创建站点工作目录

      1
      2
      3
      4
      5
      6
      # 离开 Rust 工程
      cd ..
      # 创建站点工程文件夹
      mkdir site
      # 使用 VSCode 打开这个文件夹
      code .\site
    2. 创建一个 package.json 文件,chart-wasm 的路径是 Rust 工程生成的 pkg 目录的路径

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      {
      "scripts": {
      "serve": "webpack-dev-server"
      },
      "dependencies": {
      "chart-wasm": "file:../chart-wasm/pkg"
      },
      "devDependencies": {
      "webpack": "^4.25.1",
      "webpack-cli": "^3.1.2",
      "webpack-dev-server": "^3.1.10"
      }
      }
    3. 创建 webpack.config

      1
      2
      3
      4
      5
      6
      7
      8
      9
      const path = require('path');
      module.exports = {
      entry: "./index.js",
      output: {
      path: path.resolve(__dirname, "dist"),
      filename: "index.js",
      },
      mode: "development"
      };
    4. 然后我们需要创建一个 src/index.js,里面调用了 Rust 工程定义的 rust_alert 函数并传入了个字符串 “Rust

      1
      2
      3
      4
      5
      6
      7
      8
      import init from '../node_modules/chart-wasm/chart_wasm.js';
      import {rust_alert} from '../node_modules/chart-wasm/chart_wasm.js';

      function run() {
      rust_alert("Rust");
      }

      init().then(run)
    5. 然后再创建一个 src/index.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="utf-8">
      <title>wasm example</title>
      </head>
      <body>
      <script type="module" src="./index.js"></script>
      </body>
      </html>
    6. 到此还不能直接运行,因为 webpack 提供的开箱即用的加载器不能识别 wasm,还需要定义一个加载器,打开 webpack.config.js

      module.exports = { 里面再添加

      1
      2
      3
      module: {
      rules: [{ test: /\.wasm$/, use: 'wasm-loader' }],
      },

      另外 webpack5 添加了支持 wasm 的实验性功能

    7. 运行

      1
      2
      3
      4
      5
      6
      # 安装依赖包
      # 这还会将 Rust 工程中的 pkg 文件夹里的内容链接到 node_modules 文件夹中去
      npm install

      # 运行服务器
      npm run serve
    8. 使用浏览器访问 localhost:8080

  9. 在 Vue 中使用它

    1. 使用脚手架创建 vue 工程

      1

【Rust】WASM 编译使用方法

https://biteax.com/d899ec1f.html

作者

石志超

发布于

2022-05-07

更新于

2023-09-27

许可协议