初试 vibe coding:Tauri + React + Rust 构建的 windows 本地番茄钟
初试 vibe coding:Tauri + React + Rust 构建的 Windows 本地番茄钟
在桌面应用开发领域,Electron 虽然流行但内存占用高、启动慢。Tauri 的出现提供了一种轻量级替代方案——它利用 Rust 作为后端,前端使用 Web 技术栈,最终打包出的应用体积小、性能好。本文将带你从零开始,构建一个本地运行的番茄钟(Pomodoro Timer),并深入剖析其底层原理。## 为什么选择 Tauri + React + Rust?Tauri 的核心思想是:前端负责 UI 渲染,Rust 后端负责系统级操作。相比 Electron,Tauri 应用不捆绑 Chromium 和 Node.js,而是利用操作系统的 WebView(如 Windows 上的 Edge WebView2),因此安装包可小至 1-2MB。React 提供了声明式的 UI 构建能力,而 Rust 则通过 Tauri 的 IPC(进程间通信)机制暴露系统 API 或自定义命令。番茄钟需要精确计时和系统通知,Rust 后端能保证毫秒级的时钟精度,而前端的 Web Worker 受浏览器调度影响,精度不可靠。## 项目初始化与目录结构首先安装 Tauri CLI 并创建项目:bashnpm create tauri-app@latest pomodoro-tauri -- --template react-tscd pomodoro-taurinpm install初始化后,目录结构如下:pomodoro-tauri/├── src/ # React 前端源码│ ├── App.tsx│ └── main.tsx├── src-tauri/ # Rust 后端│ ├── src/│ │ ├── main.rs # 入口│ │ └── lib.rs # 核心逻辑│ ├── Cargo.toml│ └── tauri.conf.json└── package.json## 核心原理:Rust 后端的精确计时桌面应用的计时器需要跨越 JavaScript 的单线程事件循环。Tauri 的 IPC 机制允许我们通过 invoke 命令调用 Rust 函数,Rust 利用 std::thread 和 tokio 实现真正的并行计时。### Rust 后端实现计时器在 src-tauri/src/lib.rs 中,我们定义一个番茄钟状态机,使用 std::sync::Mutex 保护共享状态:rustuse std::sync::Mutex;use std::time::Duration;use tauri::State;// 番茄钟状态枚举#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]pub enum TimerStatus { Idle, // 空闲 Running, // 运行中 Paused, // 暂停 Finished, // 完成}// 计时器数据结构pub struct PomodoroTimer { pub remaining_seconds: Mutex<u32>, // 剩余秒数 pub status: Mutex<TimerStatus>, // 当前状态 pub work_duration: u32, // 工作时间(秒)}// 初始化计时器:默认25分钟(1500秒)pub fn init_timer() -> PomodoroTimer { PomodoroTimer { remaining_seconds: Mutex::new(1500), status: Mutex::new(TimerStatus::Idle), work_duration: 1500, }}// 启动计时任务(在独立线程中运行)#[tauri::command]fn start_timer(state: State<PomodoroTimer>) -> Result<(), String> { let mut status = state.status.lock().map_err(|e| e.to_string())?; *status = TimerStatus::Running; // 注意:实际生产代码应使用 tokio::spawn 异步任务 // 此处为简化演示,主线程直接循环(实际项目需避免阻塞) Ok(())}// 获取当前剩余时间(供前端轮询)#[tauri::command]fn get_remaining(state: State<PomodoroTimer>) -> Result<u32, String> { let remaining = state.remaining_seconds.lock().map_err(|e| e.to_string())?; Ok(*remaining)}### 关键设计点1. Mutex 锁:多线程访问共享数据时,必须加锁防止数据竞争。2. 命令注册:通过 #[tauri::command] 宏暴露给前端调用。3. 状态传递:使用 State 注入管理状态。## 前端 React 组件与 IPC 调用前端通过 @tauri-apps/api 库调用 Rust 命令。注意:Tauri v2 的 API 路径与 v1 不同,这里使用 v1 版本(兼容性更好)。### 番茄钟主组件tsximport { useState, useEffect } from 'react';import { invoke } from '@tauri-apps/api/tauri'; // 导入 IPC 调用函数function PomodoroTimer() { const [time, setTime] = useState<number>(1500); // 初始25分钟 const [isRunning, setIsRunning] = useState(false); // 轮询获取剩余时间(每500ms更新) useEffect(() => { if (!isRunning) return; const interval = setInterval(async () => { // 调用 Rust 后端命令获取剩余秒数 const remaining: number = await invoke('get_remaining'); setTime(remaining); if (remaining <= 0) { setIsRunning(false); clearInterval(interval); // 触发系统通知 new Notification('番茄钟完成!', { body: '休息一下吧', icon: '/icon.png' }); } }, 500); return () => clearInterval(interval); }, [isRunning]); // 启动/暂停切换 const toggleTimer = async () => { if (isRunning) { await invoke('pause_timer'); // 暂停命令(需在 Rust 中实现) setIsRunning(false); } else { await invoke('start_timer'); // 启动命令 setIsRunning(true); } }; // 格式化时间为 MM:SS const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; return ( <div className="pomodoro-container"> <h1 className="text-4xl font-mono">{formatTime(time)}</h1> <button onClick={toggleTimer} className="timer-button"> {isRunning ? '暂停' : '开始'} </button> </div> );}export default PomodoroTimer;### 原理剖析:IPC 通信机制当前端调用 invoke('get_remaining') 时,Tauri 内部执行以下流程:1. 序列化请求:将命令名和参数序列化为 JSON。2. IPC 通道:通过 WebView 的 window.__TAURI__ 对象传递到 Rust 后端。3. 命令路由:Rust 端解析 JSON,根据命令名匹配到对应的函数。4. 执行与返回:执行函数后,结果通过相同的通道返回给前端 Promise。这种设计避免了前端直接操作系统资源,保证了安全性。同时,Rust 的零成本抽象确保了计时精度。## Windows 特有功能:系统托盘与通知番茄钟适合常驻后台。Tauri 支持系统托盘(Tray)和原生通知。在 tauri.conf.json 中配置系统图标:json{ "tauri": { "bundle": { "icon": ["icons/32x32.png", "icons/128x128.png"] }, "systemTray": { "iconPath": "icons/32x32.png", "menuOnLeftClick": false } }}Rust 端监听托盘事件(需在 main.rs 或 lib.rs 中添加):rustuse tauri::SystemTrayEvent;use tauri::Manager;// 在构建 App 时注册tauri::Builder::default() .system_tray(system_tray) .on_system_tray_event(|app, event| { if let SystemTrayEvent::LeftClick { .. } = event { let window = app.get_window("main").unwrap(); window.show().unwrap(); window.set_focus().unwrap(); } }) .build() .unwrap();## 总结通过这个简单的番茄钟项目,我们实践了 Tauri 应用的完整开发流程。关键收获包括:1. 架构分离:前端负责 UI 交互,Rust 后端处理核心逻辑,通过 IPC 桥接。2. 精确计时:Rust 的线程模型保证了计时精度,避免了 JavaScript 事件循环的干扰。3. 系统集成:Tauri 提供了系统托盘、原生通知等 Windows 特性接口。4. 体积优势:最终打包的 exe 文件仅约 3MB,远小于 Electron 的 100MB+。vibe coding 的核心理念是“感受代码的流动”——当你理解底层原理后,开发会变得流畅自然。你可以进一步扩展这个项目:添加番茄钟统计(Rust 读写本地 SQLite)、自定义工作时间、或集成快捷键(通过 globalShortcut 插件)。Tauri 的生态系统正在快速成长,它将成为桌面应用开发的重要选择。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)