第 9 章 创建第一个 Tauri 应用(create-tauri-app)
本章目标
- 用
create-tauri-app生成一个标准 Tauri 2 + React + TS + Vite + Tailwind 项目。 - 把项目跑起来,看见第一个带按钮的 UI。
- 知道每个生成文件的作用。
一、动手
打开终端:
pnpm create tauri-app@latest
交互式问答(按回车走过默认时注意):
- Project name:
tauri-hello - Identifier:
dev.codecow.hello - Choose which language to use for your frontend: TypeScript / JavaScript
- Choose your package manager: pnpm
- Choose your UI template: React
- Choose your UI flavor: TypeScript
完成后:
cd tauri-hello
pnpm install
pnpm tauri dev
第一次 build 大概 3–10 分钟。结束后看到窗口:Welcome 页面 + 一个输入框 + 一个按钮。
二、生成的目录
tauri-hello/
├── src/ # 前端 (React + Vite 入口)
│ ├── App.tsx # 根组件
│ ├── main.tsx # ReactDOM 挂载
│ ├── assets/
│ ├── App.css
│ └── styles.css
├── src-tauri/ # 后端 (Rust)
│ ├── src/
│ │ ├── main.rs # main 函数
│ │ └── lib.rs # 大部分业务代码(Tauri 2 起的新约定)
│ ├── capabilities/
│ │ └── default.json # 权限声明
│ ├── icons/ # 应用图标
│ ├── tauri.conf.json # Tauri 配置
│ ├── Cargo.toml
│ └── build.rs
├── index.html # 前端 HTML 模板
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
└── vite.config.ts
关键文件逐个看
src-tauri/tauri.conf.json
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "tauri-hello",
"version": "0.1.0",
"identifier": "dev.codecow.hello",
"build": {
"frontendDist": "../dist",
"devUrl": "http://localhost:1420",
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build"
},
"app": {
"windows": [
{ "title": "tauri-hello", "width": 800, "height": 600 }
],
"security": { "csp": null }
},
"bundle": {
"active": true,
"targets": "all",
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/icon.icns", "icons/icon.ico"]
}
}
beforeDevCommand:在tauri dev启动后端之前先跑pnpm dev,启动 Vite dev server。devUrl:Tauri 在 dev 模式去这个地址拉前端。frontendDist:发布模式下使用的前端产物目录。app.windows:启动时创建的窗口。security.csp:Content Security Policy。
src-tauri/src/main.rs
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
tauri_hello_lib::run()
}
极简,把真正的逻辑委托给 lib.rs。这是 Tauri 2 模板的新约定(方便移动端共用代码)。
src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::command] 注册一个命令,invoke_handler 把它挂到 IPC。
src/App.tsx
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
async function greet() {
setGreetMsg(await invoke("greet", { name }));
}
return (
<main className="container">
<h1>Welcome to Tauri!</h1>
<form onSubmit={e => { e.preventDefault(); greet(); }}>
<input value={name} onChange={e => setName(e.currentTarget.value)} placeholder="Enter a name..." />
<button type="submit">Greet</button>
</form>
<p>{greetMsg}</p>
</main>
);
}
export default App;
三、开发流程是什么样
pnpm tauri dev起两个东西:Vite dev server(端口 1420)+ Rust 后端。- 改前端:热更新,保存立刻刷新。
- 改 Rust:重编译整个后端,窗口自动重开。
- 构建产物:
pnpm tauri build,产物在src-tauri/target/release/bundle/。
四、加入 Tailwind
模板默认没有 Tailwind。我们一次性加上:
cd tauri-hello
pnpm add -D tailwindcss@3 postcss autoprefixer
pnpm exec tailwindcss init -p
编辑 tailwind.config.js:
export default {
content: ["./index.html", "./src/**/*.{ts,tsx}"],
darkMode: "class",
theme: { extend: {} },
plugins: [],
};
新建/覆盖 src/index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
html, body, #root { height: 100%; margin: 0; }
body { background: #0a0a0a; color: #e5e7eb; font-family: ui-sans-serif, system-ui; }
src/main.tsx 里 import "./index.css";。
删掉老的 App.css,把 App.tsx 改成:
import { useState } from "react";
import { invoke } from "@tauri-apps/api/core";
export default function App() {
const [name, setName] = useState("");
const [msg, setMsg] = useState("");
return (
<main className="flex flex-col items-center justify-center h-full gap-4">
<h1 className="text-3xl font-semibold">你好,Tauri</h1>
<div className="flex gap-2">
<input
className="bg-zinc-800 rounded px-3 py-1 outline-none"
value={name}
onChange={e => setName(e.target.value)}
placeholder="输入你的名字"
/>
<button
className="bg-brand-500 hover:bg-brand-600 rounded px-4 py-1"
onClick={async () => setMsg(await invoke<string>("greet", { name }))}
>
打招呼
</button>
</div>
{msg && <p className="text-gray-400">{msg}</p>}
</main>
);
}
注意 bg-brand-500 需要我们在 tailwind.config 里加 brand 色(见第 6 章)。
五、常见陷阱
pnpm tauri dev卡在Waiting for your frontend dev server1420 端口被占用或 Vite 启动失败。先
pnpm dev看错误。
Windows 上
error: linker link.exe not found第 2 章的 C++ Build Tools 没装全。
invoke调用报Not allowed by ACLCapabilities 不对。第 13 章详述。
WebView 白屏
常见于 Linux WebKitGTK。查
RUST_LOG=tauri=debug pnpm tauri dev日志。或在 WebView 里按 F12(开发模式默认开 DevTools)。
本章小结
create-tauri-app一键生成项目。- 前端
src/、后端src-tauri/、配置tauri.conf.json。 - 热更新(前端)+ 重编译(Rust)是基本开发节奏。
动手时刻
-
跑通
pnpm tauri dev。 - 加上 Tailwind,把 UI 改成中文。
-
在
lib.rs加一个#[tauri::command] async fn now() -> String返回当前时间字符串,在前端显示。 -
打一个 release 包:
pnpm tauri build,看看 bundle 目录里的安装包。
下一章,工程化目录规范。