tauri-expert
Expert skill for Tauri (v2) development, Rust backend, IPC, and security / Panduan ahli untuk pengembangan Tauri v2, Rust backend, IPC, dan keamanan.
SKILL.mdskills/tauri-expert/SKILL.md
GitHubTauri Expert (Tauri 2.12+ Desktop & Mobile Architecture)
<a name="english"></a>
English
Orchestration & Integration
Connects and orchestrates with relevant domain skills:
rust-programming-expert— Writing memory-safe, asynchronous Rust commands, Tokio tasks, and state backends.senior-frontend— Building lightweight React 19 / Vite UI frontends for Tauri.design-system-architect— Desktop UI design systems, custom window titlebars, and native OS theming.ui-ux-pro-max— Desktop window ergonomics, system tray menus, and native keyboard shortcuts.visual-ui-auditor— Multimodal vision auditing of rendered desktop window frames and dialogs.anti-slop— Anti-slop desktop UI craft, zero fake browser window frames and zero placeholder commands.production-ready-hardener— Auditing binary sizes, code signing, and release pipeline hardening.desktop-electron-expert&browser-extension-mv3-pro— Migrating legacy Electron apps to Tauri v2 and bridging native desktop binaries with Manifest V3 browser companion extensions.
Description
Production-grade guidance for building cross-platform desktop (Windows 10/11, macOS, Linux) and mobile (iOS 16+, Android 10+) applications using Tauri 2.x (specifically v2.12+). Covers Rust 1.90+ MSRV requirements, tauri::ipc::Channel<T> for ordered bidirectional streaming, on_permission_request programmatic security gates, App-Bound Domain navigation limiting, portable application directory overrides (appDirectoriesOverride), Rust-side convert_file_src, and the fine-grained Capabilities & Permissions system.
Instructions & Best Practices
1. Architecture & Streaming IPC (tauri::ipc::Channel)
- Use
#[tauri::command]for discrete request-response commands. - For streaming long-running jobs (AI token generation, file download progress, database indexing), use
tauri::ipc::Channel<T>passed as a command argument:- Channels deliver messages strictly in order directly to the caller.
- Keeps the global event bus (
emit/listen) uncluttered and avoids global memory leaks.
- For raw binary streams without JSON serialization overhead, send
tauri::ipc::InvokeResponseBody::Raw(Vec<u8>).
2. Native Webview Security Gates (Tauri 2.12+)
- Permission Request Handler (
on_permission_request): Intercept native webview permission requests (Camera, Microphone, Geolocation, Notifications) in Rust usingWebviewWindowBuilder::on_permission_requestorWebviewBuilder::on_permission_request. Evaluate app state before granting or denying. - App-Bound Domains: Lock webview navigation strictly to trusted external domains using
limit_navigations_to_app_bound_domainsin Rust orlimitNavigationsToAppBoundDomainsintauri.conf.json. - Context Isolation & Capabilities: Never expose unrestricted system APIs. Define least-privilege capability files in
src-tauri/capabilities/*.json.
3. State Management & Concurrency
- Store global application state in the Rust backend using
tauri::State<T>. - Use
tokio::sync::Mutexorstd::sync::RwLockfor mutable state. - Initialize managed state during application setup:
tauri::Builder::default().manage(AppState::new()).
4. Portable Application Support (appDirectoriesOverride)
- In Tauri 2.12+, configure
app > appDirectoriesOverrideintauri.conf.jsonor mutateContext::config_mutat runtime to direct app data, configs, and cache relative to the executable ($EXE_DIR). This enables portable zero-installer distribution. - Use
app_handle.path()resolver APIs instead of hardcoded paths across platforms.
5. Plugin Ecosystem & Native Integration
- Rely on official Tauri plugins (
@tauri-apps/plugin-fs,@tauri-apps/plugin-store,@tauri-apps/plugin-dialog,@tauri-apps/plugin-notification). - For app exit, use the core-level
exitfrom@tauri-apps/api/appbacked by permissioncore:app:allow-exitwithout requiring third-party process plugins.
Trigger Conditions
Activate this skill when:
- Building, debugging, or refactoring desktop or mobile applications with Tauri v2.
- Implementing streaming IPC pipelines with
tauri::ipc::Channel. - Configuring webview permissions, App-Bound domains, or capabilities (
src-tauri/capabilities/). - Setting up portable application directories or cross-platform builds.
Implementation Examples
1. Rust Backend Command & Streaming Handler (src-tauri/src/lib.rs)
use serde::{Deserialize, Serialize};
use tauri::{
ipc::Channel,
Manager, WebviewUrl, WebviewWindowBuilder,
};
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProgressPayload {
pub step: u32,
pub total: u32,
pub message: String,
}
#[derive(Serialize, Deserialize)]
pub struct MetricsPayload {
pub cpu_usage: f32,
pub memory_used_mb: u64,
}
#[tauri::command]
pub async fn fetch_system_metrics() -> Result<MetricsPayload, String> {
Ok(MetricsPayload {
cpu_usage: 12.4,
memory_used_mb: 2048,
})
}
// Tauri v2.12+ Streaming IPC Channel pattern
#[tauri::command]
pub async fn start_streaming_task(
task_name: String,
on_progress: Channel<ProgressPayload>,
) -> Result<String, String> {
let total_steps = 5;
for step in 1..=total_steps {
tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
let payload = ProgressPayload {
step,
total: total_steps,
message: format!("Processing {} (step {}/{})", task_name, step, total_steps),
};
on_progress.send(payload).map_err(|err| err.to_string())?;
}
Ok(format!("Task '{}' completed successfully", task_name))
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// Tauri 2.12+ Window creation with Permission Request Handler
let main_window = WebviewWindowBuilder::new(
app,
"main",
WebviewUrl::App("index.html".into()),
)
.title("Sovereign Tauri Desktop")
.inner_size(1024.0, 768.0)
.on_permission_request(|_webview, request| {
println!("Webview requested permission: {:?}", request.permission());
tauri::webview::PermissionState::Granted
})
.build()?;
#[cfg(debug_assertions)]
main_window.open_devtools();
Ok(())
})
.invoke_handler(tauri::generate_handler![
fetch_system_metrics,
start_streaming_task
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
2. Frontend TypeScript Invocation with Channel (src/lib/streaming.ts)
import { Channel, invoke } from '@tauri-apps/api/core';
export interface ProgressPayload {
step: number;
total: number;
message: string;
}
export interface MetricsPayload {
cpu_usage: number;
memory_used_mb: number;
}
export async function getSystemMetrics(): Promise<MetricsPayload> {
return await invoke<MetricsPayload>('fetch_system_metrics');
}
// Tauri v2.12+ Typed Channel streaming consumption
export async function runStreamingTask(
taskName: string,
onProgressUpdate: (progress: ProgressPayload) => void
): Promise<string> {
const channel = new Channel<ProgressPayload>();
channel.onmessage = (payload) => {
onProgressUpdate(payload);
};
return await invoke<string>('start_streaming_task', {
taskName,
onProgress: channel,
});
}
3. Tauri v2 Granular Capability Definition (src-tauri/capabilities/default.json)
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Default capability envelope for main application window",
"windows": ["main"],
"permissions": [
"core:default",
"core:app:allow-exit",
"core:window:allow-set-title",
"core:window:allow-set-fullscreen"
]
}
<a name="bahasa-indonesia"></a>
Bahasa Indonesia
Integrasi Orkestrasi
Terhubung dan mengorkestrasi skill domain yang relevan:
rust-programming-expert— Penulisan perintah Rust asinkron yang aman memori, task Tokio, dan backend state.senior-frontend— Pembuatan frontend UI React 19 / Vite yang ringan untuk Tauri.design-system-architect— Sistem desain UI desktop, titlebar jendela kustom, dan theming OS native.ui-ux-pro-max— Ergonomi antarmuka desktop, menu system tray, dan pintasan keyboard native.visual-ui-auditor— Audit visual multimodal untuk bingkai jendela desktop dan dialog yang dirender.anti-slop— Penegakan UI desktop anti-slop, nol bingkai browser palsu, dan nol perintah placeholder.production-ready-hardener— Audit ukuran biner, code signing, dan pipeline rilis siap produksi.
Deskripsi
Panduan produksi untuk membangun aplikasi desktop (Windows 10/11, macOS, Linux) dan mobile (iOS 16+, Android 10+) berperforma tinggi menggunakan Tauri 2.x (terutama v2.12+). Mencakup standar MSRV Rust 1.90+, tauri::ipc::Channel<T> untuk streaming bidirectional terurut, on_permission_request untuk gerbang keamanan native, pembatasan navigasi App-Bound Domains, override direktori aplikasi portabel (appDirectoriesOverride), konversi file lokal di sisi Rust via convert_file_src, serta sistem Capabilities & Permissions.
Instruksi & Praktik Terbaik
1. Arsitektur & Streaming IPC (tauri::ipc::Channel)
- Gunakan
#[tauri::command]untuk pola permintaan-respons standar (request-response). - Untuk tugas jangka panjang yang membutuhkan streaming progres (seperti unduhan file, inferensi AI token per token, atau indeks database), gunakan
tauri::ipc::Channel<T>yang dilewatkan sebagai parameter command:- Channel menjamin urutan pesan langsung ke pemanggil spesifik.
- Menghindari penumpukan listener pada event bus global (
emit/listen) yang rawan kebocoran memori.
- Untuk streaming data biner mentah tanpa overhead serialisasi JSON, gunakan
tauri::ipc::InvokeResponseBody::Raw(Vec<u8>).
2. Gerbang Keamanan Webview Native (Tauri 2.12+)
- Permission Request Handler (
on_permission_request): Tangani permintaan izin webview native (Kamera, Mikrofon, Lokasi, Notifikasi) langsung di Rust menggunakanWebviewWindowBuilder::on_permission_request. Evaluasi status aplikasi sebelum memberikan izin (Granted) atau menolak (Denied). - App-Bound Domains: Kunci navigasi webview agar hanya mengakses domain tepercaya melalui
limit_navigations_to_app_bound_domainsdi Rust ataulimitNavigationsToAppBoundDomainsditauri.conf.json. - Isolasi Konteks & Capabilities: Jangan pernah mengekspos API sistem tanpa batas. Tentukan kapabilitas berbasis hak istimewa terkecil (least-privilege) di
src-tauri/capabilities/*.json.
3. Manajemen State & Konkurensi
- Simpan state global aplikasi di backend Rust menggunakan
tauri::State<T>. - Gunakan
tokio::sync::Mutexataustd::sync::RwLockuntuk state yang dapat berubah (mutable state). - Daftarkan state saat inisialisasi aplikasi:
tauri::Builder::default().manage(AppState::new()).
4. Aplikasi Portabel & Override Direktori (appDirectoriesOverride)
- Pada Tauri 2.12+, gunakan konfigurasi
app > appDirectoriesOverrideditauri.conf.jsonatau ubahContext::config_mutsaat runtime agar data aplikasi, konfigurasi, dan cache disimpan relatif terhadap direktori biner eksekusi ($EXE_DIR). Pola ini memungkinkan distribusi aplikasi portabel tanpa installer. - Gunakan resolver
app_handle.path()alih-alih jalur sistem operasi yang ditulis statis (hardcoded).
5. Ekosistem Plugin & Integrasi Native
- Manfaatkan plugin resmi Tauri (
@tauri-apps/plugin-fs,@tauri-apps/plugin-store,@tauri-apps/plugin-dialog,@tauri-apps/plugin-notification). - Untuk keluar dari aplikasi, gunakan fungsi bawaan
exitdari@tauri-apps/api/appyang didukung oleh izincore:app:allow-exittanpa perlu plugin pihak ketiga.
Kondisi Pemicu
Aktif saat:
- Membangun, men-debug, atau merefaktor aplikasi desktop atau mobile dengan Tauri v2.
- Mengimplementasikan pipeline streaming IPC dengan
tauri::ipc::Channel. - Mengonfigurasi perizinan webview, App-Bound domains, atau file kapabilitas (
src-tauri/capabilities/). - Menyiapkan direktori aplikasi portabel atau kompilasi lintas platform.
Contoh Implementasi
1. Definisi Command & Streaming Handler Rust (src-tauri/src/lib.rs)
use serde::{Deserialize, Serialize};
use tauri::{
ipc::Channel,
Manager, WebviewUrl, WebviewWindowBuilder,
};
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProgressPayload {
pub step: u32,
pub total: u32,
pub message: String,
}
#[derive(Serialize, Deserialize)]
pub struct MetricsPayload {
pub cpu_usage: f32,
pub memory_used_mb: u64,
}
#[tauri::command]
pub async fn fetch_system_metrics() -> Result<MetricsPayload, String> {
Ok(MetricsPayload {
cpu_usage: 12.4,
memory_used_mb: 2048,
})
}
// Pola Streaming IPC Channel Tauri v2.12+
#[tauri::command]
pub async fn start_streaming_task(
task_name: String,
on_progress: Channel<ProgressPayload>,
) -> Result<String, String> {
let total_steps = 5;
for step in 1..=total_steps {
tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
let payload = ProgressPayload {
step,
total: total_steps,
message: format!("Memproses {} (tahap {}/{})", task_name, step, total_steps),
};
on_progress.send(payload).map_err(|err| err.to_string())?;
}
Ok(format!("Tugas '{}' selesai dengan sukses", task_name))
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// Inisialisasi jendela Tauri 2.12+ dengan Permission Request Handler
let main_window = WebviewWindowBuilder::new(
app,
"main",
WebviewUrl::App("index.html".into()),
)
.title("Sovereign Tauri Desktop")
.inner_size(1024.0, 768.0)
.on_permission_request(|_webview, request| {
println!("Izin webview diminta: {:?}", request.permission());
tauri::webview::PermissionState::Granted
})
.build()?;
#[cfg(debug_assertions)]
main_window.open_devtools();
Ok(())
})
.invoke_handler(tauri::generate_handler![
fetch_system_metrics,
start_streaming_task
])
.run(tauri::generate_context!())
.expect("terjadi kesalahan saat menjalankan aplikasi tauri");
}
2. Pemanggilan Frontend TypeScript dengan Channel (src/lib/streaming.ts)
import { Channel, invoke } from '@tauri-apps/api/core';
export interface ProgressPayload {
step: number;
total: number;
message: string;
}
export interface MetricsPayload {
cpu_usage: number;
memory_used_mb: number;
}
export async function getSystemMetrics(): Promise<MetricsPayload> {
return await invoke<MetricsPayload>('fetch_system_metrics');
}
// Konsumsi streaming Channel terketik pada Tauri v2.12+
export async function runStreamingTask(
taskName: string,
onProgressUpdate: (progress: ProgressPayload) => void
): Promise<string> {
const channel = new Channel<ProgressPayload>();
channel.onmessage = (payload) => {
onProgressUpdate(payload);
};
return await invoke<string>('start_streaming_task', {
taskName,
onProgress: channel,
});
}
3. Definisi Kapabilitas Rinci Tauri v2 (src-tauri/capabilities/default.json)
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Ambang kapabilitas default untuk jendela aplikasi utama",
"windows": ["main"],
"permissions": [
"core:default",
"core:app:allow-exit",
"core:window:allow-set-title",
"core:window:allow-set-fullscreen"
]
}