WJ-Yuan / Notes

My Tech Notes
https://wj-yuan.github.io/Notes/
0 stars 0 forks source link

[Note] Rust-Wasm 初始 #16

Open WJ-Yuan opened 11 months ago

WJ-Yuan commented 11 months ago

Rust-Wasm 初识

创建一个 rust-wasm 库

无论是什么工具初始化模板,其核心就是需要装上 wasm-bindgen 这个库。 我们从创建一个空项目 rust 项目开始。

  1. 首先创建一个空项目,需要注意的是我们要采用 --lib 模式创建
cargo new <pkg-name> --lib
  1. 修改下 Cargo.toml,添加依赖项
[package]
name = "rust-wasm-demo"
version = "0.1.0"
edition = "2021"
description = "babby's first wasm package"
license = "MIT/Apache-2.0"

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

[dependencies]
wasm-bindgen = "0.2"
  1. 全局安装下 wasm-pack,window 环境下可以在官网直接下载 exe 文件安装。

  2. lib.rs 添加你的 rust 代码

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet() {
    alert("Hello, World!");
}
  1. 运行 wasm-pack build 打包项目,注意不同的 target 参数对应不同的打包平台
wasm-pack build --target node
  1. 测试后就可以发布你的项目了,发布后直接 npm 下载你的项目,像其他 npm 包一样引用即可

和 webpack 项目混合开发

其实就是在上面的基础上添加了一个 webpack 的前端项目,且在前端项目里我们引用的是打包之后的路径,稍微不一样的是在 webpack 里我们增加了 @wasm-tool/wasm-pack-plugin 的插件用以和 rust 通信,以实现实时更新。且引用我们改为了动态引用。

import('../pkg/index.js').catch(console.error);

一般我们创建模板采用

npm init rust-webpack your-package-name

纯 wasm 文件的引用

有没有想过为什么 wasm-pack 打包出来的包我们可以直接像其他包一样引用呢?

实际我们看 MDN 教程 的时候并非如此。对于纯粹的 .wasm 格式文件,我们参考这个示例 来看。

  1. 首先我们下载一个 wasm 模块

  2. 然后我们创建一个简单的 index.html 文件在存放 wasm 的文件夹下

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Simple template</title>
  </head>
  <body> </body>
</html>
  1. 创建 <script> 块,导入 .wasm 模块

为了在 JavaScript 中使用 WebAssembly,在编译/实例化之前,你首先需要把模块放入内存。比如,通过 XMLHttpRequest 或 Fetch,模块将会被初始化为带类型数组。WebAssembly 还没有和 <script type='module'> 或 ES6 的 import 语句集成,也就是说,当前还没有内置的方式让浏览器为你获取模块。当前唯一的方式就是创建一个包含你的 WebAssembly 模块二进制代码的 ArrayBuffer 并且使用 WebAssembly.instantiate() 编译它。

// 获取 wasm
fetch('simple.wasm')
  // 将 wasm 初始化为数组
  .then((res) => res.arrayBuffer())
  // 实现编译和实例化数组
  // importObject 是指一个将被导入到新创建实例中的对象,它包含的值有函数、WebAssembly.Memory 对象等等。编译的模块中,对于每一个导入的值都要有一个与其匹配的属性与之相对应
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((results) => {
    results.instance.exports.exported_func();
  });
  1. 运行 html 文件,此时我们发现报错,因为我们并没有定义 importObject,现在我们定义它
let importObject = {
  imports: {
    imported_func: (arg) => console.log(arg),
  },
};
  1. 再次运行发现不报错了

那么我们现在就可以再去看上面 rust 项目打包出来的 pkg 文件,我们发现里面有 js 文件已经帮我们处理了一些这样的逻辑