如果你在十年前打开一个桌面应用的源码,大概率只会看到一套单一语言的工程:C++、Java、C# 或 Objective-C。那个时代的桌面软件有一个很明确的特征:
UI 和系统能力写在同一个技术栈里。
Win32 程序、Java Swing、Qt、WPF,本质都是"单栈架构"。开发者用一门语言同时完成:
-
界面绘制
-
系统调用
-
数据管理
-
业务逻辑
这种模式的问题在于:UI 开发效率低、跨平台困难、生态封闭。
Web 技术的入侵:Electron 时代
当浏览器成为最强的 UI 引擎之后,一个想法自然出现:
既然 Web 可以画出复杂界面,为什么不直接用它做桌面 UI?
于是 Electron 诞生了。
Electron 的核心思想非常简单:
-
用 Chromium 渲染 UI
-
用 Node.js 访问系统能力
-
把 Web App 包成桌面程序
这一步改变了软件工程的分层结构:
桌面壳
└── Chromium
└── Web App
开发体验变得极其舒适,但代价是体积和资源占用。
Tauri 的出现:重新思考分层
Tauri 是对 Electron 的一次工程性反思。
它问了一个关键问题:
是否真的需要内置整个浏览器?
现代操作系统已经自带 WebView 引擎。Tauri 的选择是:
-
使用系统 WebView 渲染 UI
-
用 Rust 写原生后端
-
用轻量桥接层连接两者
于是架构变成:
Web 前端
↕
Rust 原生后端
↕
操作系统
这就是你看到那套目录结构的根本原因。
为什么会出现"双 src"目录
现在回到你截图里的项目。
你看到的不是一个工程,而是:
两个独立工程被放进了同一个仓库。
第一部分:前端工程
这一层是一个标准的 Web 项目:
src/
index.html
main.ts
style.css
node_modules/
package.json
它的职责非常纯粹:
-
绘制 UI
-
处理交互
-
管理状态
从浏览器的角度看,这和普通 Web App 没区别。
第二部分:Rust 原生工程
在 src-tauri 目录下,你看到的是一个完整的 Rust crate:
src-tauri/
src/main.rs
Cargo.toml
tauri.conf.json
这部分负责:
-
创建桌面窗口
-
访问本地文件系统
-
调用系统 API
-
管理安全权限
-
执行高性能任务
这不是"附属文件",而是一套真正的原生后端。
为什么不合并成一个目录
因为它们在本质上是:
两种语言、两套编译系统、两种运行时。
前端用 npm / Vite 构建。
Rust 用 Cargo 编译。
把它们强行混在一起反而会破坏工程边界。
所以 Tauri 的设计选择是:
并排放置,而不是嵌套融合。
看起来像"src 里面还有 src",实际上是:
Web src + Rust src
这是一种刻意保持清晰边界的工程结构。
Tauri 应用在运行时发生了什么
当你执行开发命令时,背后其实启动了一个小型编排系统。
第一步,前端构建工具启动开发服务器,实时编译 TypeScript 和 CSS。
第二步,Rust 编译原生后端。
第三步,Tauri 创建桌面窗口。
第四步,窗口加载前端页面。
第五步,JS 和 Rust 通过桥接层通信。
这套流程把 Web 开发体验和原生能力融合在一起。
这种架构代表的软件工程趋势
这不是 Tauri 独有的现象,而是一个更大的趋势:
分层专业化。
现代软件越来越倾向于:
-
UI 用高生产力语言
-
性能核心用系统级语言
-
用协议连接两者
这和云计算里的前后端分离、微服务架构属于同一思想谱系。
工程上的好处
这种分层带来几个直接优势。
UI 开发速度接近 Web 水平。
原生能力保持高性能和安全性。
跨平台成本显著降低。
代码职责边界清晰。
从团队协作的角度看,这允许:
-
前端工程师专注 UI
-
系统工程师专注底层能力
为什么这个目录"看起来怪"
因为它挑战了很多人的默认认知:
一个应用 = 一个工程
Tauri 的现实是:
一个应用 = 多个协作工程
当你用这个视角看目录结构时,一切都会变得合理:
app/
├── frontend/
└── native-backend/
Tauri 只是把名字换成了:
src
src-tauri
本质是同一个模式。
这对未来开发意味着什么
这种结构其实在预示一个更大的方向:
应用正在变成多运行时系统。
你已经可以看到类似模式在很多领域出现:
-
Web + WASM
-
Python + Rust
-
JS + C++
-
AI 模型 + 控制逻辑
软件工程正在从单语言世界走向多语言协作。
Tauri 只是桌面领域的一个代表。
结语
你看到的目录并不是混乱,而是现代工程设计的一种刻意表达。
它把一个桌面应用拆解为:
-
Web UI 层
-
原生能力层
-
桥接通信层
这种拆分让每一层都可以用最适合的工具实现。
当你接受"一个项目可以包含多个独立工程"这个观念之后,这种结构会变得非常自然,甚至优雅。

