跳到主要内容

集成 WebAssembly

🧠 一句话理解 WebAssembly

WebAssembly(WASM)= 在前端运行 C/C++/Rust 写的“模块” 它比 JS 快、能做更复杂的计算、可调用本地库,是 JS 的“外挂引擎”。

领域用法
🔐 加密/解密自定义 AES、RSA、DH、签名验证等逻辑移到 WASM
🎨 图像处理像素处理、滤镜、压缩(如:图片压缩、OpenCV)
📈 压缩/编解码JSON 压缩、音视频数据预处理(如 FFmpeg-WASM)
🧮 数学计算AI 模型推理、小型 WASM 推理引擎
🗂 PDF 渲染用 WASM 渲染大 PDF、文档查看(如 pdf.js + pdf-wasm
🧬 大文件处理浏览器中分块处理大文件,替代 Node
📦 跨语言模块复用把已有 Rust/C/C++ 逻辑编译成 Web 可用模块

📦 工具链推荐

工具用途
wasm-pack编译 WASM 包
wasm-bindgenJS 与 Rust 通信桥
vite-plugin-wasm自动加载 WASM 模块(Vue/Vite 项目推荐)
wasm-opt压缩优化 .wasm 体积

你选择的方案优势

优势描述
🧩 模块化Rust 项目以 npm 包方式发布(如 @mywasm/foo),前端直接 import
♻️ 热更新使用 vite-plugin-rsw + rsw watch,支持代码修改自动编译、前端热更新
🧱 结构清晰支持多 crate、多 wasm 项目统一构建
💡 配置统一所有 wasm 包管理集中在 rsw.toml 文件中
✅ 支持 Tauri完美兼容 vite + tauri,前端可以直接用 wasm 功能

📦 快速搭建

非常棒,你现在正在参考 vite-plugin-rsw + rsw 的方式,把 WebAssembly(Rust 编译)模块集成到 Tauri + 前端项目中。这是目前 最现代化、支持热更新、组织清晰 的 WebAssembly 集成方案,非常适合你当前项目!

1. 安装依赖

pnpm add -D vite-plugin-rsw
cargo install rsw
cargo install wasm-pack
➜  tauri-app (Add/WebAssembly) pnpm add -D vite-plugin-rsw                    ✭
cargo install rsw
cargo install wasm-pack
Already up to date
Progress: resolved 109, reused 55, downloaded 0, added 0, done
Done in 407ms using pnpm v10.11.1
Updating crates.io index
Ignored package `rsw v0.8.0` is already installed, use --force to override
Updating crates.io index
Ignored package `wasm-pack v0.13.1` is already installed, use --force to override

2. 修改 vite.config.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { ViteRsw } from "vite-plugin-rsw";
import path from "path";

export default defineConfig({
plugins: [vue(), ViteRsw()],
resolve: {
alias: {
"@mywasm/foo": path.resolve(__dirname, "@mywasm/foo/pkg"),
},
},
});

3. 添加脚本到 package.json

{
"scripts": {
"dev": "vite",
"build": "rsw build && tsc && vite build",
"preview": "vite preview",
# 新增
"tauri": "tauri",
"rsw": "rsw"
}
}

4. 初始化 rsw 项目结构

pnpm rsw init
➜  tauri-app (Add/WebAssembly) rsw init                                       ✭

[⚙️ rsw.toml] rsw.toml created successfully

生成:

[tauri-app]
│ # 新增结构
├─ rsw.toml # ✅ rsw 配置文件
├─ .watchignore # ✅ rsw watch 忽略文件

5. 新建 wasm crate

pnpm rsw new @mywasm/foo
➜  tauri-app (Add/WebAssembly) pnpm rsw new @mywasm/foo                     ✭ ✱


[INFO]: ⬇️ Installing cargo-generate...
🐑 Generating a new rustwasm project with name 'foo'...
🔧 Destination: /Users/soaringmini/Blog/Tauri/tauri-app/@mywasm/foo ...
🔧 project-name: foo ...
🔧 Generating template ...
🔧 Moving generated files into: `/Users/soaringmini/Blog/Tauri/tauri-app/@mywasm/foo`...
Initializing a fresh Git repository
✨ Done! New project created /Users/soaringmini/Blog/Tauri/tauri-app/@mywasm/foo
[INFO]: 🐑 Generated new project at /foo
[🦀 rsw::crate] @mywasm/foo created successfully, please add the following code to `rsw.toml`

[[crates]]
name = "@mywasm/foo"

这会生成目录结构:

[tauri-app]
│ # 新增结构
├─ [@mywasm] # ✅ 组织名称(npm org)
│ ├─ [foo] # ✅ @mywasm/foo - wasm 包名
├─ Cargo.toml
└─ src/lib.rs
│ └─ [bar] # ✅ @mywasm/bar - wasm 包名
├─ [.rsw] # ✅ rsw 临时文件夹

6. 在 rsw.toml 中注册 wasm 包

name = "rsw"
version = "0.1.0"

#! time interval for file changes to trigger wasm-pack build, default `50` milliseconds
interval = 50

#! link
#! npm link @see https://docs.npmjs.com/cli/v8/commands/npm-link
#! yarn link @see https://classic.yarnpkg.com/en/docs/cli/link
#! pnpm link @see https://pnpm.io/cli/link
#! The link command will only be executed if `[[crates]] link = true`
#! cli: `npm` | `yarn` | `pnpm`, default is `npm`
cli = "pnpm"

[new]
using = "rsw"

[[crates]]
name = "@mywasm/foo"
link = true

[crates.watch]
run = true

7. 编写 Rust 逻辑

// @mywasm/foo/src/lib.rs
mod utils;

use wasm_bindgen::prelude::*;

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

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
web_sys::console::log_1(&"Hello from Rust!".into());
format!("Hello, {}! You've been greeted from Rust!", name)
}

加入 wasm-bindgen + web-sys 依赖到 Cargo.toml

8. 在前端使用

<script setup lang="ts">
import { ref, onMounted } from "vue";
import init, { greet } from "@mywasm/foo";

const greetMsg = ref("");
const name = ref("");

onMounted(async () => {
await init();
});

async function onClick() {
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
greetMsg.value = greet(name.value);
}
</script>

9. 开发启动方式

开两个终端:

# 终端1:watch Rust wasm 模块变化
pnpm rsw:watch

# 终端2:启动 Vite 前端
pnpm dev
# 或 tauri 模式
pnpm tauri dev

推荐项目结构

[tauri-app] # 项目名称
│ # 新增结构
├─ [@mywasm] # ✅ 组织名称(npm org)
│ ├─ [foo] # ✅ @mywasm/foo - wasm 包名
│ └─ [bar] # ✅ @mywasm/bar - wasm 包名
├─ [.rsw] # ✅ rsw 临时文件夹
├─ rsw.toml # ✅ rsw 配置文件
├─ .watchignore # ✅ rsw watch 忽略文件
│┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
│ # 原结构
├─ [node_modules] # 前端依赖
├─ [src] # 前端程序源
├─ [src-tauri] # Tauri 程序源
│ ├─ [icons] # 应用程序图标
│ ├─ [src] # Tauri App 程序源,例如系统菜单,托盘,插件配置等
│ ├─ [target] # 构建的产物会被放入此文件夹中,target 目录的结构取决于是否使用 --target 标志为特定的平台构建
│ ├─ build.rs # Tauri 构建应用
│ ├─ Cargo.lock # 包含了依赖的精确描述信息,类似于 yarn.lock 或 package-lock.json
│ ├─ Cargo.toml # Tauri (Rust) 项目清单
│ └─ tauri.conf.json # 自定义 Tauri 应用程序的配置文件,例如应用程序窗口尺寸,应用名称,权限等
├─ index.html # 项目主界面
├─ package.json # 前端项目清单
├─ tsconfig.json # typescript 配置文件
├─ vite.config.ts # vite 配置文件
├─ yarn.lock # 前端依赖的精确描述信息
└─ ... # 其他

tauri-app/
├── @mywasm/ # 多个 wasm crate 放这里
│ ├── foo/
│ └── bar/
├── .rsw/ # 临时编译文件夹
├── rsw.toml # RSW 主配置
├── src/ # 前端 Vue 项目
├── src-tauri/ # Tauri Rust 后端
├── vite.config.ts # 启用 vite-plugin-rsw
├── package.json
└── ...

📦 解释

🎯 @mywasm/foo/pkg

@mywasm/foo/pkg/
├── foo.js <-- JS glue
├── foo_bg.wasm <-- wasm 本体
├── package.json <-- 指定了 "main": "foo.js"

如果没有,请执行:

pnpm rsw build
➜  tauri-app (Add/WebAssembly) pnpm rsw build                                 ✭


> tauri-app@0.1.0 rsw /Users/soaringmini/Blog/Tauri/tauri-app
> rsw build

[rsw::INFO] 🚧 wasm-pack build @mywasm/foo --out-dir pkg --target web --release --scope mywasm
[INFO]: 🎯 Checking for the Wasm target...
[INFO]: 🌀 Compiling to Wasm...
Compiling foo v0.1.0 (/Users/soaringmini/Blog/Tauri/tauri-app/@mywasm/foo)
Finished `release` profile [optimized] target(s) in 0.58s
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ✨ Done in 1.05s
[INFO]: 📦 Your wasm pkg is ready to publish at @mywasm/foo/pkg.

[✨ rsw::build] @mywasm/foo "0.1.0"
 ERR_PNPM_NO_GLOBAL_BIN_DIR  Unable to find the global bin directory

Run "pnpm setup" to create it automatically, or set the global-bin-dir setting, or the PNPM_HOME env variable. The global bin directory should be in the PATH.
[🔗 rsw::link] pnpm link @mywasm/foo

◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻

或者

pnpm rsw watch
➜  tauri-app (Add/WebAssembly) pnpm rsw watch                                 ✭

> tauri-app@0.1.0 rsw /Users/soaringmini/Blog/Tauri/tauri-app
> rsw watch

[rsw::INFO] 🚧 wasm-pack build @mywasm/foo --out-dir pkg --target web --dev --scope mywasm
[INFO]: 🎯 Checking for the Wasm target...
[INFO]: 🌀 Compiling to Wasm...
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ✨ Done in 0.21s
[INFO]: 📦 Your wasm pkg is ready to publish at @mywasm/foo/pkg.

[👀 rsw::watch] @mywasm/foo "0.1.0"
 ERR_PNPM_NO_GLOBAL_BIN_DIR  Unable to find the global bin directory

Run "pnpm setup" to create it automatically, or set the global-bin-dir setting, or the PNPM_HOME env variable. The global bin directory should be in the PATH.
[🔗 rsw::link] pnpm link @mywasm/foo

◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻

[🦀 rsw::watch] @mywasm/foo

◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻◼◻

确保 pkg/ 是最新构建出来的。

你可以在 @mywasm/foo/package.json 这样写:

{
"name": "@mywasm/foo",
"version": "0.1.0",
"main": "./pkg/foo.js",
"types": "./pkg/foo.d.ts"
}

这是个非常好的问题,咱们来解释清楚:

🎯 wasm-pack

简而言之:

rsw 是一个辅助工具,底层仍然依赖 wasm-pack 来编译 Rust 到 WebAssembly。

🧠 类比理解:

工具作用类比
wasm-pack把 Rust 编译成 wasm 并生成 npm 包编译器(gcc、tsc 等)
rsw提供开发体验、热更新、自动 linkwebpack 或 vite 插件工具

🔧 依赖关系简图:

你执行:pnpm rsw build

└── rsw 调用 wasm-pack build
└── 编译 .wasm、生成 .js、写入 pkg 目录

📦 rsw 的作用:

  • 自动管理多个 wasm crate
  • 支持 rsw.toml 配置和 npm link
  • 实现开发阶段的 watch + vite HMR
  • 不重复造 wasm-pack 的轮子,而是 包装它

✅ 所以你必须这样安装一次:

cargo install wasm-pack

并确保它在你的 $PATH 里:

wasm-pack --version
# 输出应该是 wasm-pack 0.x.x

❗ 如果没有安装 wasm-pack 会报的典型错误:

[⚙️ rsw::env] wasm-pack https://github.com/rustwasm/wasm-pack
Cannot find wasm-pack in your PATH. Please make sure wasm-pack is installed.

💡 你接下来可以做什么?

目标实现方式
用 Rust 实现 AES-GCM、Base64、DH 密钥交换放在 @mywasm/crypto 模块中导出
图像处理 / Markdown 解析 / Hash可封装为 @mywasm/utils 模块
高性能消息搜索(离线)自定义 Rust 搜索模块,前端调用
接入 C/C++ 库(通过 Rust FFI)先集成 Rust crate,再打包为 wasm 模块

是否需要我帮你生成:

  • 🛠 一份 @mywasm/crypto 示例 wasm 包(含 AES 示例)
  • 📦 基于 rsw 的完整项目初始化模板
  • 📁 多 crate 的合理结构示例

你只需要说一句 “我要一个 xxx 示例”,我可以直接生成代码给你,无需你从零折腾。是否继续?