2.1 三层装配图:前端、桥接与Rust芯


图纸章从纵向切开开始。本节把 Tauri 应用切成三层——前端层、桥接层、Rust 芯层,说明每层住着什么代码、由什么组件驱动,以及分层如何让同一份工程同时服务桌面与移动端。读完本节,2.2 节讲通信时你才知道传送带的两头各拴在哪。

纵向切开:三层的物理位置

以 1.1 节创建的 travel-notes 为参照,三层不是三个进程,而是同一应用里三种职责的分区。运行时视角自上而下:

前端层。 你的 HTML、CSS、JavaScript 跑在系统 WebView 里。开发模式下 WebView 加载的是本地开发服务器(如 Vite 起的热更新服务),构建模式下加载的是打进二进制的静态资源。这一层你拥有完全的自由:任何能产出静态站点的前端栈都适用,前端代码里不出现任何 Tauri 特有 API 也完全成立——那样的应用是"只显示不能摸",但确实能跑。

桥接层。 这一层的居民是 tauri 库本体:命令路由表、事件总线、权限执行器、窗口管理器。它的任务只有一个——把 WebView 世界里的函数调用,翻译成 Rust 世界里的函数执行,再把结果翻译回去。所有跨语言通信都被压缩成两种原语:命令(前端发起、有来有回)与事件(双向、广播或定向)。第 6 章会看到,权限检查也驻扎在这一层,每个跨层调用都要过闸。

Rust 芯层。 你的命令函数、受管状态、插件注册、生命周期钩子都在这里。底层还有两个帮 Tauri 干重活的零件值得一提:tao 负责窗口与输入——创建原生窗口、处理尺寸与多显示器、托盘与菜单,在各平台上对接各自的原生窗口系统;wry 负责把三种系统 WebView 封装成统一接口——创建 WebView 实例、注入脚本、注册自定义协议。tauri 库站在两者之上,加上 IPC 与安全层,才成为"应用容器"。

图 2-1:三层装配图与各层居民

图 2-1:三层装配图与各层居民

为什么分层:一次跨端的追问

如果不分层会怎样?想象把窗口创建、页面渲染、IPC、权限检查全写死在一个进程的单文件里——它只能跑在桌面上,因为"窗口"这个概念被你焊死在了某一种窗口系统上。Tauri 的分层正是为了解开这个焊点:

  • tao/wry 抽象掉平台:同一套窗口与 WebView 接口,底下桌面接 Windows、macOS、Linux 的原生 API,移动端接各自的组件系统;
  • 桥接层抽象掉传输:命令调用在桌面走 WebView 的消息通道,在移动端走对应的桥,前端代码感知不到差别;
  • 你的代码只面对抽象:命令是普通函数,事件是普通的发布订阅,全程不写平台判断(个别平台特性除外,用条件编译标注)。

这就是 Tauri 2 能把移动端"长"出来的架构原因:不是重写了一个移动框架,而是分层让"平台相关"被压缩在 tao、wry 与少数条件编译块里。

分层的工程代价:序列化边界

分层不是免费的。前端与芯之间只有 JSON 序列化这一条正规通道,于是三条约束要刻进习惯:

大 payload 别过桥。 给前端返回一个几十 MB 的文件内容,序列化加传输的延迟和内存峰值都难看。正确姿势是芯拿着数据、把路径或资源句柄给前端,用资源协议按需取(3.3、5.3 节有实操)。

高频小调用要攒批。 每秒几百次 invoke,每次几个字节,序列化开销本身不大,但跨层调度会把 CPU 打高。改为芯侧攒批、事件定时推送,是第 8 章性能优化的标准动作。

类型要在两头各写一遍。 前端 TypeScript 与 Rust 结构体是两套类型系统,字段命名还要经过驼峰转换的关口。工程上的解法是单一真源:用工具从 Rust 结构体生成 TS 类型,或反过来,避免手写两遍后改一边漏一边。

三个架构追问:把分层想到底

追问一:前端崩了会怎样?芯崩了会怎样? 前端崩(页面脚本异常、渲染进程出错)通常表现为白屏或功能失效,芯还活着,重载页面即可恢复;芯崩则整个进程退出,窗口直接消失。这个不对称决定了容错投入的方向:关键数据的状态与落盘逻辑放芯侧保护(5.2 的受管状态),前端的异常边界负责兜住界面错误并给用户重载入口,而不是假装错误不存在。

追问二:为什么 Tauri 不做一个"内置迷你浏览器"来消除平台差异? 那正是 Electron 的路线——差异消失了,但内核体积、更新负担、内存账单全部回来。Tauri 的选择是把差异当作工程问题去管理(基线、渐进增强、分端微调),换取资源账单的量级优势。两条路线没有对错,但选择哪条,就接受哪条的全部后果,这在 1.3 的对比矩阵里已经算过一遍。

追问三:桥接层会不会成为性能瓶颈? 会,前提是你把大量数据或高频调用压上去。桥接层的吞吐对常规业务绰绰有余(配置读写、列表增删、表单提交都不在话下),瓶颈出现在大文件、高频流式数据这类边界场景——应对手段(传路径不传内容、攒批节流)都是绕开瓶颈而非硬穿瓶颈。把桥当"物流通道"而不是"传送机",设计的分寸就有了。

亲眼看一次分层

图纸读一遍不如拆开看一遍。跑起 travel-notes 后做三个观察,三层的存在感就具体了。**观察一:数进程。**打开系统任务管理器,找到 travel-notes 相关的条目——主进程是那个 Rust 二进制本体;每个 WebView 有自己的渲染进程;可能还有 GPU 辅助进程。多开一个窗口(4.4 的多窗口)再看一眼:渲染进程多了一个,主进程没有。进程结构是理解"壳崩与芯崩"(见本章追问)的物理基础。

**观察二:摸桥。**在 WebView 的开发者工具控制台里直接敲一次桥上调用(以官方注入的全局对象为例,能列出授权集合内的可用接口),然后到芯侧的命令函数里放一行打印——前端一触发、终端立刻跟上,这条一秒内的呼应就是桥的实体。再故意调一个未授权的命令名,观察桥返回的拒绝信息:权限闸门(第 6 章)的工作方式在控制台里就能预演。

**观察三:看资源从哪来。**开发者工具的 Network 面板里,看首页资源的请求协议与来源——开发模式下是本地开发服务器的地址,构建产物模式下是自定义协议的虚拟源(8.1 详解)。同一份前端代码,两种加载来源对应 2.1 开头那句"开发加载什么、生产加载什么"的分岔。

三个观察合计不超过十分钟,却把"分层"从名词变成了可指认的东西:进程边界是壳与芯的分界,控制台到终端的那次呼应是桥,Network 面板的来源切换是装配前后端产物的两种形态。后面章节凡是讲到"跨层",都可以回到这三个观察点验证。

本节要点回顾

  • 三层分区:前端层跑在 WebView,桥接层是 tauri 库(路由、事件、权限、窗口管理),芯层是你的 Rust 代码;
  • 两个底层零件:tao 管窗口与输入,wry 统一三平台 WebView 接口;
  • 两种通信原语:命令(请求响应)与事件(发布订阅),权限闸门驻扎在桥接层;
  • 分层的红利是跨端——平台差异被压缩在底层抽象与条件编译里;
  • 分层的税是序列化边界:大 payload 不过桥、高频调用要攒批、类型两头各一份。

层认全了,下一节抽出炉子里最忙的那条传送带:跟着一次 invoke 从按下按钮走到 Rust 返回值,逐站验票。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U