一、项目文件结构
DZMRustTauriBaseProject/
├── index.html # 前端 HTML 入口
├── package.json # 前端依赖与脚本
├── vite.config.ts # Vite 构建配置
├── tsconfig.json
│
├── src/ # 【前端】主要开发区
│ ├── main.ts # Vue 应用挂载
│ ├── App.vue # 根组件 / 主页面
│ ├── assets/ # 静态资源
│ └── vite-env.d.ts
│
├── src-tauri/ # 【后端/桌面壳】主要开发区
│ ├── Cargo.toml # Rust 依赖
│ ├── tauri.conf.json # 窗口、前端地址、构建命令等
│ ├── build.rs # 构建时脚本
│ ├── capabilities/
│ │ └── default.json # 权限:允许前端调用的 API
│ ├── src/
│ │ ├── main.rs # 程序入口,启动 Tauri
│ │ └── lib.rs # 业务逻辑 + 暴露给前端的命令(核心)
│ └── icons/ # 应用图标
│
└── docs/ # 文档(本文件所在目录)
二、前后端交互流程
2.1 整体流程(一次调用)
┌─────────────────────────────────────────────────────────────────────────┐
│ 用户操作(如点击 Greet) │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 前端 (Vue / src/App.vue) │
│ • 调用: invoke("greet", { name: name.value }) │
│ • 使用: @tauri-apps/api/core 的 invoke │
└─────────────────────────────────────────────────────────────────────────┘
│
│ (Tauri 内部:序列化参数 → IPC → 后端)
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 后端 (Rust / src-tauri/src/lib.rs) │
│ • 匹配命令名 "greet" → 执行 fn greet(name: &str) -> String │
│ • 返回值序列化后通过 IPC 回传 │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 前端 (Vue) │
│ • await invoke(...) 得到 Rust 返回的 String │
│ • 写入 greetMsg,界面更新 │
└─────────────────────────────────────────────────────────────────────────┘
2.2 代码对应关系
| 环节 | 位置 | 做什么 |
|---|---|---|
| 前端调用 | src/App.vue | invoke("greet", { name }),命令名必须与 Rust 中一致 |
| 命令注册 | src-tauri/src/lib.rs | #[tauri::command] fn greet(...) + generate_handler![greet] |
| 权限 | src-tauri/capabilities/default.json | 允许使用 core(含 invoke)等能力 |
三、后续开发:主要操作区域与流程
3.1 加一个「新能力」(新命令)
-
Rust 端(
src-tauri/src/lib.rs)- 写一个新函数,加上
#[tauri::command]。 - 在
tauri::Builder的.invoke_handler(tauri::generate_handler![..., 新命令])里注册。
- 写一个新函数,加上
-
前端
- 在需要的地方
import { invoke } from "@tauri-apps/api/core",然后await invoke("新命令名", { 参数 })。
- 在需要的地方
-
权限(若用到敏感 API)
- 在
capabilities/里为对应能力添加 permission(多数纯业务命令用默认即可)。
- 在
3.2 改界面
- 只动
src/:Vue 组件、路由、状态、样式等,和普通 Vue 项目一致。
3.3 改窗口/打包/配置
- 动
src-tauri/tauri.conf.json:窗口大小、标题、前端 devUrl、构建命令等。
3.4 开发时跑起来
- 只跑网页:
npm run dev - 跑桌面客户端(前端 + 壳):
npm run tauri dev
四、交互原理简述
- 前端运行在 Tauri 提供的 WebView 里,和普通网页一样写 Vue/TS。
- 通信:前端不直接访问 Rust,而是通过 Tauri 的 invoke 发「命令名 + 参数」;Tauri 在 Rust 端根据命令名路由到对应的
#[tauri::command]函数,执行完后把返回值通过 IPC 传回前端。 - 安全:前端只能调用你在 Rust 里显式注册的 command,以及 capabilities 里允许的 API;没有「整个 Node/系统」暴露给前端,所以不需要像 Electron 那样用 contextBridge 做一层暴露。
五、和 Electron 在流程上的区别
5.1 Electron 的典型做法
- 主进程:Node 环境,可 require、访问系统。
- 渲染进程:浏览器环境,默认不能直接 require、不能随意调主进程。
- 所以要用 contextBridge + ipcRenderer:
- 主进程里用 preload 脚本,通过
contextBridge.exposeInMainWorld('xxx', { ... })只暴露有限 API 给渲染进程。 - 渲染进程里不直接
require('electron'),而是用挂到window上的对象(例如window.xxx.invoke('channel', data)),内部再转成 ipcRenderer.send / ipcRenderer.invoke 与主进程通信。
- 主进程里用 preload 脚本,通过
- 流程:渲染进程 → preload(contextBridge 暴露的 API)→ ipcRenderer → 主进程(ipcMain 监听 channel)→ 主进程逻辑。
也就是说:Electron 需要你自己用 preload + contextBridge 定义「前端能调什么」,再用 ipcRenderer / ipcMain 在进程间传 channel + 数据。
5.2 Tauri 的对应关系
| 概念 | Electron | Tauri |
|---|---|---|
| 前端调「后端」 | 通过 preload 暴露的 API | 通过 invoke("command", args) |
| 暴露方式 | contextBridge.exposeInMainWorld | 无需 preload,直接 invoke 命令名 |
| 后端实现 | ipcMain.on('channel', handler) | #[tauri::command] fn xxx() |
| 通信模型 | 自己定 channel 名、自己序列化 | 命令名 + 参数,Tauri 负责序列化/路由 |
5.3 核心区别总结
-
Electron
- 渲染进程不能直接用
require('electron'),所以要 preload + contextBridge 暴露安全 API,再用 ipcRenderer 发 channel,主进程用 ipcMain 收。 - 流程是你自己设计 channel 和参数格式。
- 渲染进程不能直接用
-
Tauri
- 前端直接用
invoke("命令名", 参数),不需要 preload,也没有 contextBridge。 - 「暴露什么」由 Rust 里注册的 command 和 capabilities 决定,安全性在框架层就按「白名单命令」设计好了。
- 前端直接用
所以:Electron 的 contextBridge + ipcRenderer 那一套,在 Tauri 里被简化为「前端 invoke 命令名 + Rust 端 command 注册」,不需要你写 preload,也不用手动管 channel 名,只要在 Rust 里加 command、在前端调 invoke 即可。
六、对照小结
- 项目结构:
src/= 前端,src-tauri/= 桌面壳与后端逻辑;后续开发主要就是在这两块加命令和改界面。 - 交互流程:用户操作 → 前端
invoke("命令", 参数)→ Tauri 路由到 Rust#[tauri::command]→ 返回值回前端。 - 和 Electron 的区别:Tauri 用「invoke + command」替代了 Electron 的「contextBridge + ipcRenderer + ipcMain」;前端只调命令名,不碰 preload,也不定义 channel。
文档结束。