在 Tauri 项目中,前端部分完全由你自主选择,它只是一个通过 WebView 渲染的普通 Web 应用。这意味着你可以毫无障碍地使用 React、Vue、Svelte、Solid.js 等主流框架,甚至纯 HTML 文件。但要让开发体验顺滑、与 Rust 后端的交互自然,还需要一些“整合技巧”。下面以最常用的 React 和 Vue 为例,说明深度整合的具体做法和注意事项。
1. 通用整合原则
无论选择哪个框架,Tauri 与前端的关系始终遵循一个简单模型:
- 前端跑在 WebView 里,负责 UI 和用户交互;
- Rust 后端跑在主进程,负责系统调用和业务逻辑;
- 两者通过 Tauri 提供的
invoke(前端)和#[tauri::command](后端)进行 IPC 通信。
因此,前端的构建流程、状态管理、路由等都不需要为 Tauri 做特殊改变。你只需要在项目中留一个入口文件(如 index.html),并将构建输出指向 Tauri 配置中的 distDir 即可。
2. 使用 Vite 作为构建工具(推荐)
Vite 与 Tauri 的配合非常理想,原因有二:
- Vite 的开发服务器启动极快,HMR 响应灵敏;
- Tauri 的开发模式可以直接代理到 Vite 的 dev server,无需额外配置。
典型项目结构(以 React 为例):
src-tauri/ # Rust 后端
src/ # 前端源码(React/Vue)
├── App.jsx
└── main.jsx
index.html # Vite 入口
vite.config.js
package.json
在 tauri.conf.json 中需要配置开发服务器的地址:
{
"build": {
"devPath": "http://localhost:5173", // Vite 默认端口
"distDir": "../dist"
}
}
启动开发时,先运行 vite,再运行 tauri dev,前端和后端即可同时热更新。
3. React 整合要点
React 社区常用的 create-react-app 已经逐渐被 Vite 模板取代,推荐用 Vite 创建 React 项目:
npm create vite@latest my-tauri-app -- --template react
关键集成的几个细节:
- IPC 调用封装
在 React 组件中频繁写 invoke('command_name', { args }) 显得散乱,建议创建一个自定义 Hook 或工具函数,将 Rust 命令转化为类型的 Promise 调用。例如:
// src/tauri-api.js
import { invoke } from '@tauri-apps/api/tauri';
export async function readFile(path) {
return await invoke('read_file', { path });
}
然后在组件中直接 const data = await readFile('/path/to/file')。
- 状态更新与 Tauri 事件的结合
Tauri 支持后端向前端推送事件(emit),你可以利用 React 的 useEffect 监听这些事件,并更新组件状态。例如,监听文件保存进度:
import { listen } from '@tauri-apps/api/event';
import { useEffect, useState } from 'react';
function useTauriEvent(eventName) {
const [payload, setPayload] = useState(null);
useEffect(() => {
const unlisten = listen(eventName, (event) => setPayload(event.payload));
return () => { unlisten.then(fn => fn()); };
}, [eventName]);
return payload;
}
- 注意:不要在前端引入 Node.js 模块
React 项目不会运行在 Node 环境里,所以任何依赖 fs、path 等原生模块的库都会报错。遇到这种情况,要么用 Rust 命令实现该功能,要么寻找纯浏览器的替代方案。
4. Vue 整合要点
Vue 3(尤其是 Composition API)与 Tauri 的整合同样顺滑。
- 创建项目:
npm create vite@latest my-tauri-app -- --template vue
- 全局挂载 Tauri API
为了方便在组件中使用,可以在 main.js 中将常用的 Tauri 方法挂载到 Vue 原型上(或者使用 provide/inject):
import { createApp } from 'vue';
import App from './App.vue';
import { invoke, dialog } from '@tauri-apps/api';
const app = createApp(App);
app.config.globalProperties.$tauri = { invoke, dialog };
app.mount('#app');
这样在组件中就能用 this.$tauri.invoke(...) 调用 Rust 命令。
- 响应式处理 IPC 返回值
Vue 的 reactive/ref 天生适合接收来自后端的异步数据。你可以写一个通用的 composable:
// src/composables/useTauriCommand.js
import { ref } from 'vue';
import { invoke } from '@tauri-apps/api';
export function useTauriCommand(command) {
const data = ref(null);
const error = ref(null);
const loading = ref(false);
const execute = async (args = {}) => {
loading.value = true;
error.value = null;
try {
data.value = await invoke(command, args);
} catch (e) {
error.value = e;
} finally {
loading.value = false;
}
};
return { data, error, loading, execute };
}
在组件中使用时非常清晰:
<script setup>
import { onMounted } from 'vue';
import { useTauriCommand } from '../composables/useTauriCommand';
const { data, loading, execute } = useTauriCommand('get_system_info');
onMounted(() => execute());
</script>
- 关于 Vue Router
Tauri 的内置 WebView 对前端路由的支持与普通浏览器一致。如果使用 Vue Router 的 history 模式,注意在 tauri.conf.json 中可能需要调整 devPath 和 distDir,并且打包后应确保所有路由都能回退到 index.html。更简单的办法是使用 hash 模式(createWebHashHistory),这样没有服务器端配置的麻烦。
5. Svelte 与其他框架
Svelte 用户同样可以通过 Vite 创建项目,集成方式与上述类似,核心仍然是使用 @tauri-apps/api 中的 invoke 和 listen。Svelte 的 store 可以很方便地映射 Tauri 事件流:
import { readable } from 'svelte/store';
import { listen } from '@tauri-apps/api/event';
export const progress = readable(0, (set) => {
const unlisten = listen('progress-event', (event) => {
set(event.payload.percent);
});
return () => { unlisten.then(fn => fn()); };
});
Solid.js、Preact 等框架的整合思路完全一致:只要它们能构建出标准的 Web 产物,就能成为 Tauri 的前端。
6. 常见问题与建议
- 前端调试:直接用浏览器打开
http://localhost:5173开发,Tauri 的 Rust 命令在该环境下无法调用(会报错),此时可以封装一个 mock 层,或者只在 Tauri 窗口内测试,两者都能保持开发体验。 - 环境隔离:建议在
package.json中设置"type": "module"或使用 ESM 语法,部分老旧的 CJS 库在 WebView 中可能无法工作。 - 性能:前端不要执行密集计算,交给 Rust 的
tauri::command。IPC 调用有序列化开销,避免高频发送大量数据。如果确实需要高频率数据(如实时图表),可以在 Rust 端聚合后批量推送事件。
总结:Tauri 给了前端开发者完全的自由,它不绑架你使用任何框架,同时提供纯 JavaScript 的 API 与 Rust 通信。深度整合的秘诀就是——把 Tauri 看作一个“调用系统能力”的函数库,而不是一个改变前端构建模式的巨兽。用好 invoke 和事件监听,你就能在任何现代前端框架中写出体验极佳的桌面应用。