首页 / Tauri 2 入门教程 / 原生 HTML-CSS-JS 前端

Tauri 2 入门教程

原生 HTML-CSS-JS 前端

本教程共 48 篇 · 第 15 篇 · 更新于 2026-08-09 · 约 6 分钟阅读

Tauri原生前端HTMLWebView

本节目标:学完能用一个最朴素的 HTML 文件作为 Tauri 前端跑起来,并理解 Tauri 在开发模式和发布模式下分别是怎么加载这些静态文件的。

Tauri 有个很友好的特性:它对前端框架「一视同仁」。你用 Vue、React 可以,用原生 HTML/CSS/JS 也可以——因为对 Tauri 来说,前端就是一堆静态文件(HTML、CSS、JS,可能还有 WASM),它自己扮演的是一个「静态网站服务器」的角色,把这些文件喂给 WebView 渲染。所以如果你的需求很简单,完全不必引入任何框架,直接用原生三件套最省事。本章就带你认识这种最轻量的前端形态。

为什么选原生前端

不是每个桌面程序都需要复杂的界面。如果你要做的是一个小工具——比如一个本地 Markdown 预览器、一个内部用的配置面板、一个系统托盘配合的小窗口——原生 HTML/CSS/JS 就足够。它的好处很实在:没有框架依赖、没有打包后的庞杂代码、构建产物最小、心智负担最低。

代价也好理解:没有组件化、没有响应式状态管理,界面复杂了之后你得自己手写大量 DOM 操作。所以一句话总结适用场景——「轻量、简单、一个人快速搞定」的界面,用原生;「交互多、页面大、要长期维护」的界面,再考虑框架。

前端项目的目录长什么样

一个用原生前端的最小 Tauri 项目,目录结构大致是这样:

my-app/
├── index.html            # 入口页面(必须)
├── styles.css            # 你的样式
├── app.js                # 你的脚本
└── src-tauri/            # Rust 后端(与前端平级)
    ├── Cargo.toml
    ├── tauri.conf.json
    └── src/
        └── lib.rs

Tauri 加载前端时,会去找 index.html 作为入口,就像浏览器打开一个网站时默认读 index.html 一样。你写的 styles.cssapp.js 都通过普通的 <link><script> 标签被它引用,没有任何特殊之处。

<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="styles.css" />
    <title>我的小工具</title>
  </head>
  <body>
    <h1>你好,Tauri</h1>
    <button id="btn">点我调用 Rust</button>
    <p id="out"></p>
    <script type="module" src="app.js"></script>
  </body>
</html>

Tauri 怎么找到并加载这些文件

关键在 tauri.conf.jsonbuild 配置块。它告诉 Tauri 两件事:开发时去哪serve 文件、发布时去哪打包文件。

{
  "build": {
    "beforeDevCommand": "npx vite --port 5173",
    "beforeBuildCommand": "npx vite build",
    "devUrl": "http://localhost:5173",
    "frontendDist": "../dist"
  }
}

逐字段解释:

  • devUrl:开发模式下,Tauri 直接打开这个网址。它可以是任意静态服务器地址,比如 http://localhost:5173
  • beforeDevCommand:敲 tauri dev 时,Tauri 会先自动执行这条命令把开发服务器起起来,再打开 devUrl。原生前端最简单的做法是用 npx vitenpx serve 起一个静态服务。
  • frontendDist:发布模式下,Tauri 会把这个目录里的「构建产物」一起打包进安装包。注意路径是相对 tauri.conf.json 所在目录(src-tauri/)的,所以常见写法是 ../dist../out
  • beforeBuildCommand:敲 tauri build 时,Tauri 先执行它来生成 frontendDist 里的内容。
Tip

原生前端甚至可以「零构建」:如果你只有一个 index.html 加几个静态文件,不需要 Vite,直接用 npx serve 之类的静态服务器,再把 frontendDist 直接指到你的源码目录也行。但更规范的做法还是用一个能产出优化后静态文件的工具,保持开发、发布两条路径一致。

开发模式与发布模式加载的区别

同一个 index.html,Tauri 在两种模式下加载方式不同,理解这点能少踩很多坑。

开发模式(tauri dev):Tauri 不碰你的文件,而是打开 devUrl 指向的开发服务器。好处是改了 HTML/JS 能热更新,前端那边怎么调试都行。这时 WebView 其实是在访问一个本地 HTTP 服务。

发布模式(tauri build):Tauri 把 frontendDist 里的文件编译进 Rust 二进制里,通过内部的 asset 协议加载(地址形如 tauri://localhost/index.html)。也就是说,最终用户机器上没有一个正在运行的 Web 服务器,文件是被「嵌」在程序里的。这就是为什么你分发时只需要一个安装包,而不用附带一整个网站目录。

在原生前端里调用 Rust

原生 JS 调用 Rust 命令,和用框架时一模一样,核心还是那句 invoke。因为原生页面通常用 <script type="module"> 直接写 ES 模块,你可以这样:

// app.js
import { invoke } from '@tauri-apps/api/core';

document.querySelector('#btn').addEventListener('click', async () => {
    const reply = await invoke('greet', { name: '小明' });
    document.querySelector('#out').textContent = reply;
});

这里的 greet 命令,后端(src-tauri/src/lib.rs)的定义和上一章讲过的一模一样。只要你装了 @tauri-apps/api 包,就能这样 import 使用。

如果你连这个 npm 包都不想装,也可以走全局对象的方式(需要在 tauri.conf.json 里开 app.withGlobalTauri: true):

// app.js(无需 import,直接用全局对象)
window.__TAURI__.core.invoke('greet', { name: '小明' }).then((reply) => {
    document.querySelector('#out').textContent = reply;
});
Warning

原生前端最容易犯的错,是直接在浏览器里双击打开 index.html 测试。那样 WebView 不在 Tauri 环境里,invoke 会失败,因为 tauri:// 协议和 Rust 后端都不存在。正确做法永远是用 tauri dev 启动,让 Tauri 真正把页面跑在它的 WebView 中。

小结

原生 HTML/CSS/JS 前端是 Tauri 最轻量的用法:Tauri 当静态服务器,你提供 index.html 入口,开发时由 devUrl 指向的开发服务器喂页面,发布时由 frontendDist 把文件嵌进安装包。调用 Rust 依旧靠 invoke。当你确认界面「小而简单」时,这条路线最干净。

下一章我们把前端升级成更工程化的 Vue 3,你会看到:底层机制完全没变,变的是前端的组织方式和那句 invoke 所在的文件。