集成 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-bindgen | JS 与 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 | 提供开发体验、热更新、自动 link | webpack 或 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 示例”,我可以直接生成代码给你,无需你从零折腾。是否继续?