作为一名经验丰富的 Electron 开发者,当你第一次接触 Tauri 时,可能会感到有些不适应。本文将帮助你快速理解 Tauri 2.0 的核心概念,并通过实际案例完成从 Electron 到 Tauri 的思维转换。

架构对比

Electron 的架构

在 Electron 中,我们习惯了以下架构:

Electron 应用
├── 主进程 (Main Process)
│   ├── 窗口管理
│   ├── 系统API调用
│   └── IPC 通信
└── 渲染进程 (Renderer Process)
    ├── 前端界面
    ├── 渲染逻辑
    └── IPC 通信

主要特点:

  1. 基于 Chromium 和 Node.js
  2. 主进程和渲染进程分离
  3. 通过 IPC 进行进程间通信
  4. 直接使用 Node.js API

Tauri 2.0 的架构

Tauri 采用了不同的架构方式:

Tauri 应用
├── 核心进程 (Rust Core)
│   ├── 窗口管理
│   ├── 系统API调用
│   └── 命令系统
└── 前端界面 (WebView)
    ├── 界面渲染
    ├── 业务逻辑
    └── Tauri API

主要特点:

  1. 基于系统 WebView
  2. Rust 核心进程
  3. 统一的命令系统
  4. 更安全的权限控制

开发环境搭建

前置依赖

# Electron 项目通常只需要
npm install -g electron

# Tauri 项目需要安装
# 1. Rust 环境
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 2. 系统依赖(以 Ubuntu 为例)
sudo apt update
sudo apt install libwebkit2gtk-4.0-dev \
    build-essential \
    curl \
    wget \
    libssl-dev \
    libgtk-3-dev \
    libayatana-appindicator3-dev \
    librsvg2-dev

项目初始化

# Electron 项目初始化
npm init
npm install electron --save-dev

# Tauri 项目初始化
npm create tauri-app
# 或者使用 yarn
yarn create tauri-app

项目结构对比

Electron 项目结构

my-electron-app/
├── package.json
├── main.js
├── preload.js
└── src/
    ├── index.html
    ├── renderer.js
    └── styles.css

Tauri 项目结构

my-tauri-app/
├── package.json
├── src/                # 前端代码
│   ├── App.tsx
│   └── styles.css
├── src-tauri/         # Rust 代码
│   ├── Cargo.toml     # Rust 依赖配置
│   ├── tauri.conf.json # Tauri 配置
│   └── src/
│       └── main.rs    # 核心进程代码
└── index.html

Hello World 对比实现

Electron 版本

// main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
})
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Hello Electron</title>
</head>
<body>
  <h1>Hello Electron!</h1>
</body>
</html>

Tauri 2.0 版本

// src-tauri/src/main.rs
fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}
// src/App.tsx
import { invoke } from '@tauri-apps/api/tauri'
import { useState } from 'react'

function App() {
  const [greeting, setGreeting] = useState('')

  async function greet() {
    setGreeting(await invoke('greet', { name: 'Tauri' }))
  }

  return (
    <div>
      <h1>{greeting || 'Hello Tauri!'}</h1>
      <button onClick={greet}>Greet</button>
    </div>
  )
}

export default App

开发调试体验

Electron 调试

  1. 主进程调试

    {
      "scripts": {
     "start": "electron .",
     "debug": "electron --inspect=5858 ."
      }
    }
  2. 渲染进程调试
  3. 使用 Chrome DevTools
  4. 快捷键:Ctrl+Shift+I (Windows/Linux) 或 Cmd+Option+I (macOS)

Tauri 调试

  1. 前端调试

    # 启动开发服务器
    npm run dev
  2. Rust 代码调试

    // .vscode/launch.json
    {
      "version": "0.2.0",
      "configurations": [
     {
       "type": "lldb",
       "request": "launch",
       "name": "Tauri Development Debug",
       "cargo": {
         "args": ["build", "--manifest-path=./src-tauri/Cargo.toml"]
       },
       "cwd": "${workspaceFolder}"
     }
      ]
    }

常见功能对比

1. 窗口创建

Electron:

const { BrowserWindow } = require('electron')

const win = new BrowserWindow({
  width: 800,
  height: 600
})

Tauri:

use tauri::Window;

#[tauri::command]
async fn create_window(app_handle: tauri::AppHandle) {
    tauri::WindowBuilder::new(
        &app_handle,
        "new_window",
        tauri::WindowUrl::App("index.html".into())
    )
    .title("New Window")
    .inner_size(800.0, 600.0)
    .build()
    .unwrap();
}

2. IPC 通信

Electron:

// 主进程
ipcMain.handle('get-data', async (event, arg) => {
  return 'data'
})

// 渲染进程
const result = await ipcRenderer.invoke('get-data')

Tauri:

// Rust
#[tauri::command]
fn get_data() -> String {
    "data".into()
}

// TypeScript
import { invoke } from '@tauri-apps/api/tauri'
const result = await invoke('get_data')

3. 文件操作

Electron:

const fs = require('fs')
fs.readFileSync('file.txt', 'utf8')

Tauri:

// Rust
use std::fs;
#[tauri::command]
fn read_file() -> String {
    fs::read_to_string("file.txt").unwrap()
}

// TypeScript
import { invoke } from '@tauri-apps/api/tauri'
const content = await invoke('read_file')

性能对比

以下是一个简单的内存占用对比:

应用类型空应用内存占用
Electron~100MB
Tauri~20MB

主要优势:

  1. 更小的安装包体积
  2. 更低的内存占用
  3. 更快的启动速度
  4. 更好的系统集成

开发建议

  1. 渐进式迁移

    • 先熟悉 Tauri 的基本概念
    • 从小功能开始迁移
    • 保持代码结构清晰
  2. 充分利用 Rust 优势

    • 性能密集型操作放在 Rust 端
    • 使用 Rust 的并发特性
    • 注意内存安全
  3. 前端代码复用

    • UI 代码可以大部分复用
    • 抽象化平台相关的 API
    • 使用适配器模式
  4. 安全性考虑

    • 使用 Tauri 的权限系统
    • 谨慎开放系统 API
    • 做好输入验证

常见问题解决

  1. Node.js API 替代方案

    // Electron
    const path = require('path')
    path.join(__dirname, 'file')
    
    // Tauri
    import { join } from '@tauri-apps/api/path'
    await join('file')
  2. 进程通信模式转换

    // Electron
    ipcRenderer.send('message')
    
    // Tauri
    await invoke('message')
  3. 系统托盘实现

    // Tauri
    use tauri::{SystemTray, SystemTrayMenu};
    
    let tray = SystemTray::new().with_menu(
        SystemTrayMenu::new()
    );

下一步学习建议

  1. 深入学习 Rust 基础知识
  2. 熟悉 Tauri 的权限系统
  3. 了解 WebView 的限制和优化
  4. 实践 Rust 插件开发

小结

  1. Tauri 2.0 的优势:

    • 更小的体积
    • 更好的性能
    • 更安全的架构
    • 更现代的技术栈
  2. 转换要点:

    • 理解架构差异
    • 掌握新的 API
    • 适应开发模式
    • 注重性能优化
  3. 建议:

    • 循序渐进
    • 保持耐心
    • 多看文档
    • 多做实验

下一篇文章,我们将深入探讨 Tauri 2.0 的窗口管理和系统集成功能,帮助你更好地理解和使用这些核心特性。

如果觉得这篇文章对你有帮助,别忘了点个赞 👍


远洋录
3 声望0 粉丝

🚀 独立开发者 | 技术出海实践者