前言
不多废话
直言的说,笔者看到这篇文章大佬的文章
【04】Tauri 入门篇 - 集成 WebAssembly - 知乎https://zhuanlan.zhihu.com/p/533025312尝试集成一下WebAssembly,直接开始
正文
准备工作
新建一个项目
安装 vite的rsw插件和rsw
pnpm install -D vite-plugin-rsw
cargo install rsw
配置在vite.config.ts文件中,添加插件
import {ViteRsw} from "vite-plugin-rsw";
plugins: [react(), ViteRsw()],
添加脚本
"scripts": {
"dev": "vite",
"build": "rsw build && tsc && vite build",
"preview": "vite preview",
"tauri": "tauri",
"rsw": "rsw",
"tauri:dev": "tauri dev"
},
初始化rsw项目
pnpm rsw init
pnpm rsw new src-wasm
在根目录下会创建一个rsw.toml文件
项目结构如下
修改rsw.toml的内容
[new] using = "rsw"[[crates]]
name = "src-wasm"
在新的shell中启动监听
pnpm rsw watch
可以看到目录结构
使用默认的方法
可以看到有个默认的方法greet
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("[rsw] Hello, {}!", name));
}
在src/App.tsc文件中
代码如下
import "./App.css";
import init, { greet } from '../src-wasm/pkg/src_wasm'
import {useEffect} from "react";
function App() {
useEffect(() => {
init();
}, [])
function handleClick(){
greet("world")
}
return (
<>
<header className="header">
<h1>Welcome to Tauri + React</h1>
</header>
<main className="container">
<button onClick={handleClick}>确定</button>
</main>
</>
);
}
export default App;
启动项目,点击按钮
没问题
使用invoke
先看看通信函数
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
在大佬的文章中,没有解释怎么和tauri连用。
从官网中可以找到和wasm一起使用的东西
Calling Rust from the Frontend | Taurihttps://v2.tauri.app/develop/calling-rust/#wasm
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)]
async fn invoke_without_args(cmd: &str) -> JsValue;
// invoke with arguments (default)
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
原来是添加的外部扩展。
因此笔者使用有参数的,即
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
如果使用官网的,需要配置全局的Tauri
"app": {
"withGlobalTauri":true,
...
},
既然配置使用async,那还需要其他依赖,在src-warm的Cargo.toml文件中,依赖如下
[dependencies]
wasm-bindgen = "0.2.83"
serde-wasm-bindgen = "0.6.5"
wasm-bindgen-futures = "0.4.50"
serde_json="1.0.140"
修改greet函数,如下
use serde_wasm_bindgen::to_value;
#[wasm_bindgen]
pub async fn greet(name: &str) {
let name = to_value(&serde_json::json!({"name": name})).unwrap();
let res = invoke("greet",name ).await;
alert(res.as_string().unwrap().as_str())
}
在前端调用
async function handleClick(){
await greet("world")
}
结果如下
tauri-wasm
实际上,笔者在github中发现了这个库
p1mo/tauri-wasm: wasm bindings for Tauri v2 API & Pluginshttps://github.com/p1mo/tauri-wasm可以使用,尝试一下
安装依赖
tauri-wasm = { git = "https://github.com/p1mo/tauri-wasm", features = [
"all", # for all api bindings
"plugin-all" # for all plugin bindings. should you do this? no.
] }
使用invoke
就像前端使用invoke一样
前端
import {invoke} from '@tauri/api/core'
导包类似的
use tauri_wasm::api::core::invoke;
看看这个invoke的定义
pub async fn invoke<A: Serialize, R: DeserializeOwned>
(cmd: &str, args: &A) -> crate::Result<R>
args需要实现序列化,R需要实现反序列化。
因此,代码如下
use serde::{Deserialize, Serialize};
use tauri_wasm::api::core::invoke;
use wasm_bindgen::prelude::wasm_bindgen;
use tauri_wasm::js::console;
use tauri_wasm::api::app::{get_name,get_version};
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[derive(Serialize)]
struct Args {
pub name: String,
}
#[derive(Deserialize)]
struct Response {
pub message: String,
}
#[wasm_bindgen]
pub async fn greet(name: &str){
console::log(&format!("Hello, {}!", name));
console::log(&format!("name is {}!", get_name().await.unwrap()));
console::log(&format!("version is {}!", get_version().await.unwrap()));
let args =Args {
name: name.to_string(),
};
let response=invoke("greet", &args).await.unwrap();
let res=serde_json::from_value::<String>(response).unwrap();
alert(res.as_str());
}
总结
可以运行
感觉搞麻烦了。