【04】Tauri 入门篇 - 集成 WebAssembly
Tags: tauri, rust, web, desktop
Published: 2022-08-01 09:37:20

---
title: 【04】Tauri 入门篇 - 集成 WebAssembly
published: true
description: 打造属于自己的下一代跨端应用
tags: tauri, rust, web, desktop
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntysfz398o4euuxpthn6.png
# Use a ratio of 100:42 for best results.
---

> 仓库：[lencx/OhMyBox](https://github.com/lencx/OhMyBox)
> 如果文章对你有所帮助，可以 [star](https://github.com/lencx/OhMyBox) 此项目，或转发给更多有需要的人。大家的支持也会给我更大的写作动力，感恩。

---

## 安装依赖

[vite-plugin-rsw](https://github.com/rwasm/vite-plugin-rsw) - 基于 vite 实现的 webAssembly 插件，支持热更新，友好的报错提示

```bash
yarn add -D vite-plugin-rsw
```

[rsw-rs](https://github.com/rwasm/rsw-rs) - 一个 CLI 工具，用于增强 [wasm-pack](https://github.com/rustwasm/wasm-pack) 的功能，如支持 watch 模式，多 crate 同时 build，watch，自动执行 `npm link` 等 

```bash
cargo install rsw
```

## 使用说明

### 1. 编辑 vite.config.js

```js
import { defineConfig } from 'vite'
import ViteRsw from 'vite-plugin-rsw'; // ✅ 新增

export default defineConfig({
  plugins: [
    ViteRsw(), // ✅ 新增
  ],
})
```

### 2. 编辑 package.json

```json
{
  "scripts": {
    "dev": "vite",
    "build": "rsw build && tsc && vite build",
    "preview": "vite preview",
    "tauri": "tauri",
    "rsw": "rsw"
  }
}
```

### 3. 运行 rsw

#### 1). 初始化 rsw 配置

生成 `rsw.toml`，了解更多 [rsw.toml 配置信息](https://github.com/rwasm/rsw-rs#rswtoml)

```bash
yarn rsw init
```

<img width="400" alt="rsw-init" src="https://user-images.githubusercontent.com/16164244/175357566-2e0a9d06-d66f-4f5a-abf7-2a0ced072c45.png" />


#### 2). 新建 wasm 项目

内置三种模式，可以通过编辑 `rsw.toml` > `[new]` > `using` 来切换

```bash
yarn rsw new @mywasm/foo
```

<img width="700" alt="rsw-new" src="https://user-images.githubusercontent.com/16164244/175358509-66e811f5-8c6e-4b77-94b6-3d1f46f6bce9.png" />


在 `rsw.toml` > `[[crates]]` 中新增 `@mywasm/foo`

```toml
#! link 类型: `npm` | `yarn` | `pnpm`, 默认是 `npm`
cli = "npm"

[new]
#! 使用: `wasm-pack` | `rsw` | `user`, 默认 `wasm-pack`
#! 1. wasm-pack: `rsw new <name> --template <template> --mode <normal|noinstall|force>`
#! 2. rsw: `rsw new <name>`, 内置模板
#! 3. user: `rsw new <name>`，如果 `dir`未配置, 则使用 `wasm-pack new <name>`初始化 wasm 项目
using = "rsw"
#! 当 `using = "user"` 时，`dir` 才会生效
#! 如果 `using = "wasm-pack"` 或 `using = "rsw"`，则忽略
#! 复制此目录下的所有文件到初始化的 wasm 项目中
dir = "my-template"

[[crates]]
#! npm 包，@mywasm 为 npm 组织，foo 是该组织下的包名
name = "@mywasm/foo"
#! 是否执行 link， link 类型通过 `cli` 配置
link = true

[[crates]]
#! npm 包，@mywasm 为 npm 组织，bar 是该组织下的包名
name = "@mywasm/bar"
#! 是否执行 link， link 类型通过 `cli` 配置
link = true
```

## 开发模式

> 监听 rust 文件变更，自动执行构建，并通知到浏览器（热更新）

1. 执行以下命令，不要退出：
    ```bash
    yarn rsw watch
    ```

2. 新开一个命令行窗口，执行 a 或 b：
    ```bash
    # a. 在浏览器环境
    yarn dev

    # b. 在 tauri 环境
    yarn tauri dev
    ```

![004-rsw-watch](https://user-images.githubusercontent.com/16164244/175360956-e533c31e-b038-4fdd-8783-d689b98c01ae.png)

## 使用

> 在项目中使用 wasm

```jsx
// App.jsx
import { useEffect } from 'react'
import init, { greet } from '@mywasm/foo'

function App() {
  useEffect(() => {
    // ✅  初始化，加载 wasm 文件
    init();
  }, [])

  return (
    <div className="App">
        {/* ✅ 调用 greet 方法，必须保证 init 方法执行完成之后，才可以调用，否则会报错 */}
        <button onClick={() => greet()}>click me</button>
    </div>
  )
}

export default App
```

## 构建

> 编译生产环境下的 wasm 文件（代码优化）

1. 构建 wasm
    ```bash
    yarn rsw build
    ```
2. 构建项目
    ```bash
    yarn build
    ```

![004-rsw-build](https://user-images.githubusercontent.com/16164244/175363889-b649c352-0fc2-4010-a535-abc85c6d55af.png)


## 项目结构

rsw 对项目结构并无特别要求，但是为了保持统一及维护性，推荐以下结构。

- `@mywasm`: wasm 包的组织名称（推荐使用，但非必需），rust 编译为 wasm，会以 npm 包的形式提供给前端使用。使用组织的好处就是方便管理，防止包名冲突
- `.rsw` - rsw 运行时生成的临时文件夹
- `rsw.toml` - rsw 配置文件 
- `.watchignore` - rsw watch 监听文件变更时需要忽略的文件，忽略规则与 [.gitignore](https://git-scm.com/docs/gitignore) 类似

```bash
[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 # 前端依赖的精确描述信息
└─ ... # 其他
```