3.2 项目结构详解

原文链接: Project Structure

3.2 项目结构详解

一个 Tauri 工程通常由两部分组成:

  1. 前端工程:负责页面,通常是普通的 Web 项目;
  2. Rust 工程:通常放在 src-tauri/ 目录,负责后端与原生能力。

默认目录树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.
├── package.json          # 前端依赖与脚本
├── index.html            # Web 页面入口
├── src/                  # 前端源码
│   └── main.js
├── src-tauri/            # Rust 后端工程
│   ├── Cargo.toml        # Rust crate 清单
│   ├── Cargo.lock        # Rust 依赖锁定文件,建议提交
│   ├── build.rs          # Tauri 构建脚本
│   ├── tauri.conf.json   # Tauri 总配置文件
│   ├── src/
│   │   ├── main.rs       # 桌面入口
│   │   └── lib.rs        # 真正要改写的 Rust 代码
│   ├── icons/            # 应用图标
│   └── capabilities/     # 权限能力文件

前端部分是“静态网站”

Tauri 的开发与构建方式很像“托管一个静态网站”:

  • 开发时:前端框架启动一个 dev server,Tauri 窗口加载 devUrl;
  • 发布时:先把前端构建成 dist 等静态目录,再由 Rust 把它们打进安装包。

所以前端工程不需要特殊改造,只要最终能产出 HTML/CSS/JS 静态资源即可。

src-tauri 是普通 Cargo 工程

src-tauri/ 是一个标准的 Rust Cargo 工程,只是多了几个 Tauri 约定文件。

Cargo.toml

它声明了 Rust 依赖。模板里最关键的是 tauri 和 tauri-build:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[package]
name = "my-tauri-app"
version = "0.1.0"
edition = "2021"

[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

其中 [lib] 里的 name = "app_lib" 正是 main.rs 中 app_lib::run() 所指向的库名。

build.rs

它调用 tauri_build::build(),让 Tauri 在编译期处理配置、图标、权限 schema 等:

1
2
3
fn main() {
    tauri_build::build()
}

main.rs 与 lib.rs 的分工

模板同时提供两个 Rust 文件,这常让新手困惑。官方这样设计的原因很简单:移动端不能直接运行一个桌面可执行文件,而是把一个 Rust 库加载进 Android/iOS 原生壳。

src-tauri/src/main.rs:

1
2
3
4
5
6
// 防止 Windows 发布版多弹出一个控制台窗口,请勿删除!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

fn main() {
  app_lib::run();
}

src-tauri/src/lib.rs:

1
2
3
4
5
6
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
  tauri::Builder::default()
    .run(tauri::generate_context!())
    .expect("运行 Tauri 应用时出错");
}

规则可以概括成一句:

桌面端由 main.rs 调用 lib.rs 的 run();移动端也调用同一个 run()。日常开发请改 lib.rs,不要动 main.rs。

不同版本的脚手架还可能给 lib.rs 增加日志插件等初始化代码(例如 tauri-plugin-log)。那部分属于调试增强,不影响上面这个“入口分流”的理解。

注意:上面 main.rs 调用的是 app_lib,这个名字来自 Cargo.toml 中 [lib] name = "app_lib" 的配置。

tauri.conf.json

这是 Tauri 的“总开关”,包含应用标识、窗口、构建脚本、打包格式等。后面 4.4 配置文件 会专门讲解。

capabilities/default.json

模板默认生成一个权限文件,例如:

1
2
3
4
5
6
7
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "启用默认权限",
  "windows": ["main"],
  "permissions": ["core:default"]
}

它告诉 Tauri:“名为 main 的窗口可以使用哪些核心能力。”这是 Tauri 安全模型的关键,见 4.5 权限与安全。

icons/

tauri icon 命令会从一张源图片生成各平台需要的图标:

1
npm run tauri icon ./app-icon.png

如果要生成 Android/iOS 工程

本章还没有看到 gen/ 目录,因为移动壳工程需要显式初始化:

1
2
npm run tauri android init
npm run tauri ios init

初始化后 src-tauri/ 下会出现 gen/android/ 与 gen/apple/,详见 5.4 Android 构建与工程目录 和 5.5 iOS 构建与工程目录。

纯 Rust 工程

如果不想要 JavaScript 前端,可以只保留 src-tauri/,把它作为顶层 Rust 工程或 Cargo workspace 的一员。

下一步

你已经能读懂模板结构。接下来在 3.3 开发循环与第一个改动 中修改页面与 Rust 代码,感受热更新。