各位观众老爷们,大家好!今天咱们来聊聊一个非常有意思的技术——JavaScript的Tauri。这玩意儿啊,能让你用熟悉的JavaScript撸前端,再用Rust写个硬核的后端,最后打包成一个桌面应用。是不是听起来就很带劲?
废话不多说,咱们直接上干货。
开场白:为什么是Tauri?
先说说为啥要用Tauri。现在桌面应用开发的选择很多,Electron很流行,但是Electron最大的问题是体积太大,而且性能也没那么好。Tauri就聪明多了,它用Rust做后端,Rust的性能那是杠杠的,编译出来的体积也小。前端呢,还是用你熟悉的HTML、CSS、JavaScript。相当于Electron的瘦身加强版。
第一部分:Tauri架构剖析
Tauri本质上是一个用Rust编写的框架,它利用系统WebView(比如Windows上的WebView2,macOS上的WebKit)来渲染前端。这就像搭积木,Rust后端提供动力和控制,WebView负责显示界面。
Tauri的核心组件:
- Tauri Core (Rust): 这是Tauri的大脑,负责处理窗口管理、事件循环、系统调用等等。
- WebView (系统自带): Tauri不自带浏览器内核,直接用系统自带的,大大减小了体积。
- Front-end (HTML/CSS/JavaScript): 你熟悉的前端技术,负责构建用户界面。
- Tauri API (Rust & JavaScript): Rust后端暴露出来的API,前端JavaScript可以通过它来调用系统功能。
第二部分:环境搭建与项目初始化
首先,确保你的电脑上装了Rust。没装的话,去Rust官网装一个,记得配置好环境变量。
然后,安装Tauri CLI:
cargo install tauri-cli
安装完之后,就可以创建Tauri项目了:
cargo create-tauri-app my-tauri-app
这个命令会问你几个问题,比如项目名称、UI框架等等。你可以根据自己的喜好选择。 如果你喜欢用React,那就选React。如果你喜欢Vue,那就选Vue。如果你想用Vanilla JS,那就选none。
创建成功后,进入项目目录:
cd my-tauri-app
项目结构大概是这样:
my-tauri-app/
├── .cargo/ # Rust相关的配置
├── .gitignore
├── Cargo.toml # Rust项目的配置文件
├── src-tauri/ # Tauri后端代码
│ ├── Cargo.toml # Tauri后端的配置文件
│ ├── src/ # Rust源代码
│ │ └── main.rs # 主函数
│ └── tauri.conf.json # Tauri配置文件
├── src/ # 前端代码
│ ├── index.html
│ ├── style.css
│ └── script.js
└── target/ # 编译输出目录
第三部分:前端代码编写
src/
目录就是放前端代码的地方。你可以用任何你喜欢的UI框架,比如React、Vue、Svelte等等。
咱们先来个简单的例子,在src/index.html
里写一个按钮,点击按钮的时候,在页面上显示一句话。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Tauri App</title>
</head>
<body>
<h1>Hello, Tauri!</h1>
<button id="myButton">Click me!</button>
<p id="message"></p>
<script>
const button = document.getElementById('myButton');
const message = document.getElementById('message');
button.addEventListener('click', () => {
message.textContent = 'Tauri is awesome!';
});
</script>
</body>
</html>
这段代码很简单,就是一个按钮和一个段落。点击按钮的时候,段落的内容会变成 "Tauri is awesome!"。
第四部分:后端代码编写
src-tauri/src/main.rs
是Tauri后端的入口文件。咱们可以在这里定义一些Rust函数,然后通过Tauri API暴露给前端调用。
比如,咱们写一个函数,接收前端传来的字符串,然后把字符串转换成大写,再返回给前端。
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use tauri::{command, State};
use std::sync::Mutex;
// 定义一个状态,用于在多个命令之间共享数据
struct MyState {
count: Mutex<i32>,
}
#[command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[command]
fn to_uppercase(input: String) -> String {
input.to_uppercase()
}
#[command]
fn increment_count(state: State<'_, MyState>) -> i32 {
let mut count = state.count.lock().unwrap();
*count += 1;
*count
}
fn main() {
tauri::Builder::default()
.manage(MyState { count: Mutex::new(0) }) // 初始化状态
.invoke_handler(tauri::generate_handler![greet, to_uppercase, increment_count])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
这段代码定义了两个函数:greet
和to_uppercase
。greet
函数接收一个字符串,然后返回一个问候语。to_uppercase
函数接收一个字符串,然后把字符串转换成大写。
注意#[command]
这个宏,它告诉Tauri这个函数可以被前端调用。
还有一点,Tauri支持状态管理,允许在多个命令之间共享数据。上面的代码中,我们定义了一个MyState
结构体,包含一个count
字段,用来记录计数。increment_count
函数可以增加计数器的值。
第五部分:前后端交互
现在,咱们需要在前端调用Rust函数。Tauri提供了一个invoke
函数,可以用来调用Rust函数。
修改src/script.js
,添加以下代码:
const button = document.getElementById('myButton');
const message = document.getElementById('message');
button.addEventListener('click', async () => {
// 调用Rust函数 greet
const greeting = await window.__TAURI__.invoke('greet', { name: 'World' });
message.textContent = greeting;
// 调用 Rust 函数 to_uppercase
const uppercaseText = await window.__TAURI__.invoke('to_uppercase', { input: 'hello tauri' });
console.log(uppercaseText);
// 调用 Rust 函数 increment_count
const count = await window.__TAURI__.invoke('increment_count');
console.log('Count:', count);
});
这段代码在点击按钮的时候,会调用Rust的greet
函数,然后把返回的问候语显示在页面上。同时也会调用 to_uppercase
和 increment_count
函数,并将结果打印到控制台。
注意window.__TAURI__.invoke
这个函数,它是Tauri提供的,用来调用Rust函数。第一个参数是函数名,第二个参数是传递给函数的参数。
第六部分:构建与运行
一切准备就绪,就可以构建和运行Tauri应用了。
cargo tauri build
这个命令会编译Rust后端代码,然后把前端代码打包进去,生成一个可执行文件。
构建完成后,可以在target/release/
目录下找到可执行文件。
直接运行这个可执行文件,就可以看到你的Tauri应用了。
或者,你也可以用以下命令来运行开发模式:
cargo tauri dev
这个命令会启动一个开发服务器,可以实时预览你的修改。
第七部分:Tauri API详解
Tauri提供了丰富的API,可以用来访问系统功能。
常用的API:
- Window API: 窗口管理,比如创建窗口、关闭窗口、最大化窗口、最小化窗口等等。
- Dialog API: 弹出对话框,比如打开文件对话框、保存文件对话框、消息对话框等等。
- Notification API: 发送系统通知。
- Shell API: 执行系统命令。
- FS API: 文件系统操作,比如读取文件、写入文件、创建目录、删除文件等等。
- HTTP API: 发送HTTP请求。
- Global Shortcut API: 注册全局快捷键。
- Clipboard API: 剪贴板操作。
举个例子,咱们用Dialog API打开一个文件选择对话框。
首先,在src-tauri/src/main.rs
里添加以下代码:
use tauri::api::dialog::FileDialogBuilder;
#[command]
async fn open_file_dialog() -> Option<String> {
let file_path = FileDialogBuilder::new().pick_file().await;
file_path
}
这个函数会打开一个文件选择对话框,然后返回选择的文件路径。
然后,在src/script.js
里添加以下代码:
const button = document.getElementById('myButton');
const message = document.getElementById('message');
button.addEventListener('click', async () => {
const filePath = await window.__TAURI__.invoke('open_file_dialog');
if (filePath) {
message.textContent = `Selected file: ${filePath}`;
} else {
message.textContent = 'No file selected.';
}
});
这段代码在点击按钮的时候,会调用Rust的open_file_dialog
函数,然后把选择的文件路径显示在页面上。
第八部分:Tauri 安全性
Tauri非常注重安全性。Tauri应用默认情况下是沙盒化的,只能访问有限的系统资源。
Tauri使用权限系统来控制应用可以访问的系统功能。你需要在tauri.conf.json
文件中声明应用需要的权限。
例如,如果你想让应用可以访问文件系统,需要在tauri.conf.json
文件中添加以下配置:
{
"tauri": {
"security": {
"csp": null
},
"allowlist": {
"fs": {
"all": true,
"scope": ["$APP/*"] // 允许访问应用程序目录下的所有文件
}
}
}
}
这个配置允许应用访问应用程序目录下的所有文件。
第九部分:Tauri vs Electron
特性 | Tauri | Electron |
---|---|---|
后端 | Rust | Node.js |
前端 | HTML/CSS/JavaScript (系统 WebView) | HTML/CSS/JavaScript (Chromium) |
应用体积 | 小 | 大 |
性能 | 高 | 相对较低 |
安全性 | 高 (权限控制) | 相对较低 (需自行处理) |
资源占用 | 低 | 高 |
开发难度 | 稍高 (需要 Rust 知识) | 较低 (JavaScript 开发者友好) |
跨平台支持 | 支持 (主流平台) | 支持 (主流平台) |
总结:Tauri的优势与不足
优势:
- 体积小: 使用系统 WebView,无需打包 Chromium,应用体积大大减小。
- 性能高: Rust 后端提供卓越的性能。
- 安全: 严格的权限控制,保障应用安全。
- 资源占用低: Rust 和系统 WebView 降低了资源占用。
不足:
- 学习曲线: 需要掌握 Rust 知识。
- 生态: 相比 Electron,Tauri 的生态还不够完善。
- 调试: Rust 代码调试相对复杂。
尾声:Tauri的未来展望
Tauri是一个很有潜力的技术,它结合了Rust的性能和JavaScript的灵活性,为桌面应用开发提供了一个新的选择。虽然目前Tauri的生态还不够完善,但是随着越来越多的开发者加入,相信Tauri的未来会更加美好。
好了,今天的分享就到这里。希望大家有所收获。如果有什么问题,欢迎提问。咱们下期再见!