Tauri 项目:交互流程与开发指南

18 阅读4分钟

一、项目文件结构

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.vueinvoke("greet", { name }),命令名必须与 Rust 中一致
命令注册src-tauri/src/lib.rs#[tauri::command] fn greet(...) + generate_handler![greet]
权限src-tauri/capabilities/default.json允许使用 core(含 invoke)等能力

三、后续开发:主要操作区域与流程

3.1 加一个「新能力」(新命令)

  1. Rust 端src-tauri/src/lib.rs

    • 写一个新函数,加上 #[tauri::command]
    • tauri::Builder.invoke_handler(tauri::generate_handler![..., 新命令]) 里注册。
  2. 前端

    • 在需要的地方 import { invoke } from "@tauri-apps/api/core",然后 await invoke("新命令名", { 参数 })
  3. 权限(若用到敏感 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(contextBridge 暴露的 API)→ ipcRenderer → 主进程(ipcMain 监听 channel)→ 主进程逻辑

也就是说:Electron 需要你自己用 preload + contextBridge 定义「前端能调什么」,再用 ipcRenderer / ipcMain 在进程间传 channel + 数据。

5.2 Tauri 的对应关系

概念ElectronTauri
前端调「后端」通过 preload 暴露的 API通过 invoke("command", args)
暴露方式contextBridge.exposeInMainWorld无需 preload,直接 invoke 命令名
后端实现ipcMain.on('channel', handler)#[tauri::command] fn xxx()
通信模型自己定 channel 名、自己序列化命令名 + 参数,Tauri 负责序列化/路由

5.3 核心区别总结

  1. Electron

    • 渲染进程不能直接用 require('electron'),所以要 preload + contextBridge 暴露安全 API,再用 ipcRenderer 发 channel,主进程用 ipcMain 收。
    • 流程是你自己设计 channel 和参数格式。
  2. Tauri

    • 前端直接用 invoke("命令名", 参数),不需要 preload,也没有 contextBridge。
    • 「暴露什么」由 Rust 里注册的 commandcapabilities 决定,安全性在框架层就按「白名单命令」设计好了。

所以: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。

文档结束。