×

用 Vue 3 + Tauri + Rust 打造的全平台 IM 系统 —— HuLa 项目深度解析

独孤求败 独孤求败 发表于2026-06-12 09:23:37 浏览26 评论0

抢沙发发表评论

HuLa是一个基于 Tauri 2 + Vue 3 + Rust 构建的跨平台即时通讯(IM)系统。它采用 Apache-2.0 开源协议,由 HuLaSpark 社区维护,当前最新版本为 3.0.9。

项目的核心目标是:用一套前端技术栈,实现 Windows、macOS、Linux、iOS、Android 五端覆盖的完整 IM 产品

本文将从项目说明、系统架构、项目结构、数据库设计、设计模式、通信机制、安全机制、性能优化、前端入口、状态管理、Hook 架构、WebRTC 音视频、系统功能、工程化 CI/CD 等维度进行系统性介绍。

图片

一、项目说明

HuLa 不是一个 Demo 或教学项目,而是一个功能完整的 IM 产品,包含私聊、群聊、音视频通话、文件传输、AI 聊天助手、社交动态等全套 IM 能力。配套的独立服务端 HuLa-Server 也完全开源,前后端解耦,支持私有化部署。

技术选型

层级
技术
前端框架
Vue 3.5 + Composition API
类型系统
TypeScript 5.9
构建工具
Vite 7
状态管理
Pinia 3(33 个 store)
UI 组件
Naive UI(桌面)/ Vant 4(移动)
CSS
UnoCSS + SCSS
路由
Vue Router 4
国际化
Vue I18n(zh-CN / en,完成度 98%)
桌面容器
Tauri 2.9
后端语言
Rust 2024 Edition
异步运行时
Tokio
ORM
SeaORM 1.1 + SQLite(SQLCipher 加密)
WebSocket
tokio-tungstenite
HTTP 客户端
reqwest
包管理
pnpm 10+
代码检查
Biome 2.3
测试框架
Vitest 4(已配置,测试文件持续补充中)

图片
图片
图片
图片
图片
图片
图片

二、系统架构

HuLa 采用 Tauri 双进程架构:Rust 原生后端进程 + WebView 前端进程,两者通过 Tauri IPC 桥接。

┌──────────────────────────────────────────────────────────┐
│                      用户设备(五端)                        │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  ┌─────────────────────┐    ┌──────────────────────┐    │
│  │   Vue 3 前端进程     │    │   Rust 后端进程       │    │
│  │   (WebView 渲染)     │◄──►│   (原生系统层)        │    │
│  │                     │ IPC│                      │    │
│  │  - 页面渲染          │    │  - 窗口管理           │    │
│  │  - 用户交互          │    │  - 系统托盘           │    │
│  │  - 组件状态          │    │  - 文件系统           │    │
│  │  - 路由导航          │    │  - 数据库操作         │    │
│  └─────────────────────┘    │  - WebSocket 客户端   │    │
│                             │  - HTTP 请求代理      │    │
│                             │  - 全局快捷键         │    │
│                             │  - 截图功能           │    │
│                             └──────────┬───────────┘    │
│                                        │                │
│                             ┌──────────▼───────────┐    │
│                             │    SQLite 本地数据库   │    │
│                             │   (SQLCipher 加密)    │    │
│                             └──────────────────────┘    │
│                                                          │
└──────────────────────┬───────────────────────────────────┘
                       │ HTTPS / WebSocket
                       ▼
              ┌─────────────────┐
              │  HuLa-Server     │
              │  (独立服务端)     │
              └─────────────────┘

架构要点

  1. 前端 SPA

    Vue 3 单页应用,运行在操作系统原生 WebView 中,不打包 Chromium,安装包仅数 MB。
  2. Rust 后端

    处理所有系统级能力——数据库、网络请求、文件操作、窗口管理、托盘通知等。
  3. IPC 通信

    前端通过 invoke() 调用 Rust 命令,Rust 通过 emit() 向前端推送事件。
  4. 本地数据库

    每个用户独立的 SQLite 数据库文件,使用 SQLCipher 加密,SeaORM 管理数据模型。
  5. WebSocket 客户端

    Rust 层维护与服务端的 WebSocket 长连接,负责消息收发、心跳保活、断线重连。
  6. 多窗口

    不同功能使用独立 WebView 窗口(主窗口、登录窗口、截图窗口、通话窗口、图片查看器等)。
  7. Tauri 插件生态

    使用了 autostart(开机自启)、clipboard-manager(剪贴板)、dialog(文件对话框)、fs(文件系统)、global-shortcut(全局快捷键)、http(HTTP 请求)、log(日志)、notification(系统通知)、os(操作系统信息)、process(进程管理)、shell(Shell 命令)、sql(SQLite 连接)、updater(自动更新)等 13 个官方 Tauri 插件,覆盖桌面/移动端系统能力。

图片

三、项目结构

HuLa/
├── src/                          # Vue 3 前端源码
│   ├── main.ts                   # 前端入口
│   ├── App.vue                   # 根组件
│   ├── agreement/                # 用户协议 UI
│   ├── assets/                   # 静态资源
│   ├── common/                   # 公共模块(异常处理等)
│   ├── components/               # Vue 组件
│   │   ├── common/               #   通用组件(14 个)
│   │   │   ├── Screenshot.vue    #   截图组件
│   │   │   ├── ContextMenu.vue   #   右键菜单
│   │   │   ├── VirtualList.vue   #   虚拟列表
│   │   │   ├── InfoPopover.vue   #   用户信息气泡
│   │   │   └── ...
│   │   ├── fileManager/          #   文件管理器组件(5 个)
│   │   ├── rightBox/             #   主聊天区域组件
│   │   │   ├── chatBox/          #     聊天主体(Header/Main/Footer/Sidebar)
│   │   │   ├── renderMessage/    #     消息类型渲染器
│   │   │   │   ├── Text.vue      #     文本消息
│   │   │   │   ├── Image.vue     #     图片消息
│   │   │   │   ├── File.vue      #     文件消息
│   │   │   │   ├── Video.vue     #     视频消息
│   │   │   │   ├── Audio.vue     #     音频消息
│   │   │   │   ├── Emoji.vue     #     表情消息
│   │   │   │   ├── Location.vue  #     位置消息
│   │   │   │   ├── MergeMessage.vue # 合并转发消息
│   │   │   │   └── special/      #     特殊消息(撤回/系统/Bot)
│   │   │   ├── emoticon/         #     表情面板
│   │   │   ├── MsgInput.vue      #     消息输入框
│   │   │   └── VoiceRecorder.vue #     语音录制
│   │   └── windows/              #   窗口操作栏
│   ├── directives/               # 自定义指令(v-resize, v-slide)
│   ├── enums/                    # 类型枚举(RoomTypeEnum 等)
│   ├── hooks/                    # Composition API Hooks
│   │   ├── useWindow.ts          # 窗口管理
│   │   ├── useMitt.ts            # 事件总线
│   │   ├── useGlobalShortcut.ts  # 全局快捷键
│   │   └── ...
│   ├── layout/                   # 布局组件
│   ├── mobile/                   # 移动端专属组件
│   ├── plugins/                  # Vue 插件
│   ├── router/                   # Vue Router 配置
│   ├── services/                 # API 服务层
│   │   ├── webSocketRust.ts      # WebSocket 客户端封装
│   │   ├── i18n.ts               # 国际化服务
│   │   └── tauriCommands.ts      # Tauri 命令封装
│   ├── stores/                   # Pinia 状态管理(33 个 store)
│   ├── strategy/                 # 策略模式实现
│   ├── styles/                   # SCSS 变量、全局样式、UnoCSS 主题
│   ├── typings/                  # TypeScript 类型定义
│   ├── utils/                    # 工具函数
│   ├── views/                    # 页面级组件(26 个顶层入口,44 个组件文件)
│   │   ├── loginWindow/          #   登录窗口
│   │   ├── homeWindow/           #   主窗口
│   │   ├── callWindow/           #   通话窗口
│   │   ├── Capture/              #   截图窗口
│   │   ├── chatHistory/          #   聊天记录
│   │   ├── fileManagerWindow/    #   文件管理器
│   │   ├── imageViewerWindow/    #   图片查看器
│   │   ├── videoViewerWindow/    #   视频查看器
│   │   ├── Notify/               #   消息通知中心
│   │   └── ...
│   └── workers/                  # Web Workers

├── src-tauri/                    # Rust/Tauri 后端源码
│   ├── src/
│   │   ├── main.rs               # 二进制入口
│   │   ├── lib.rs                # Tauri 库入口,命令注册
│   │   ├── command/              # Tauri invoke 处理器(15 个命令模块)
│   │   │   ├── ai_command.rs     #   AI 聊天流式/取消
│   │   │   ├── message_command.rs#   消息 CRUD(发送/保存/同步/撤回/删除)
│   │   │   ├── message_mark_command.rs # 消息表态(点赞/踩)
│   │   │   ├── chat_history_command.rs # 历史消息查询
│   │   │   ├── contact_command.rs#   联系人操作
│   │   │   ├── room_member_command.rs # 群成员管理
│   │   │   ├── request_command.rs#   登录及 HTTP 请求代理
│   │   │   ├── upload_command.rs #   文件上传(七牛云分片)
│   │   │   ├── database_command.rs#  用户数据库切换
│   │   │   ├── oauth_command.rs  #   OAuth 二维码登录
│   │   │   ├── setting_command.rs#   应用设置 CRUD
│   │   │   ├── user_command.rs   #   用户资料/Token
│   │   │   ├── file_manager_command.rs # 文件管理/消息统计
│   │   │   ├── markdown_command.rs #   Markdown 渲染
│   │   │   └── ...
│   │   ├── websocket/            # WebSocket 客户端
│   │   │   ├── client.rs         #   核心客户端(1194 行)
│   │   │   ├── commands.rs       #   Tauri 命令处理器
│   │   │   ├── message.rs        #   消息类型定义
│   │   │   └── types.rs          #   连接状态/配置类型
│   │   ├── repository/           # 数据访问层
│   │   │   ├── im_message.rs     #   消息仓储
│   │   │   ├── im_contact.rs     #   联系人仓储
│   │   │   ├── im_room_member.rs #   群成员仓储
│   │   │   ├── im_user.rs        #   用户仓储
│   │   │   └── im_config.rs      #   配置仓储
│   │   ├── pojo/                 # 数据对象
│   │   ├── vo/                   # 视图对象
│   │   ├── im_request_client.rs  # HTTP 客户端(220+ 端点)
│   │   ├── configuration.rs      # 应用配置加载
│   │   ├── timeout_config.rs     # 超时配置
│   │   ├── error.rs              # 错误类型
│   │   ├── common/               # 公共初始化/文件元数据
│   │   ├── desktops/             # 桌面端专属(窗口/托盘/事件)
│   │   ├── mobiles/              # 移动端专属(闪屏/角标/键盘)
│   │   └── utils/                # 平台工具(Windows/macOS/Linux)
│   ├── entity/                   # SeaORM 实体定义
│   ├── migration/                # 数据库迁移脚本
│   ├── configuration/            # YAML 配置
│   ├── tray/                     # 系统托盘资源
│   ├── Cargo.toml                # Rust 依赖
│   ├── build.rs                  # Tauri 构建脚本
│   └── tauri.conf.json           # Tauri 应用配置

├── tauri-plugin-hula/            # 自研 Tauri 插件(移动端专用,含 Rust 源码 + iOS/Android 原生代码 + TS 绑定)
├── build/                        # Vite 构建配置工具
├── docs/                         # 项目文档
├── locales/                      # i18n 翻译文件(zh-CN / en)
├── preview/                      # UI 截图(37 张)
├── scripts/                      # 构建/开发脚本
├── package.json                  # Node 依赖及脚本
├── vite.config.ts                # Vite 配置
├── uno.config.ts                 # UnoCSS 配置
└── tsconfig.json                 # TypeScript 配置

图片

四、数据库设计

HuLa 使用 SQLite 作为本地数据库,通过 SQLCipher 加密,由 SeaORM 管理数据模型。采用按用户隔离的数据库策略——每个用户拥有独立的数据库文件,通过 switch_user_database 命令切换。

数据表结构

初始迁移创建 6 张核心表:

1. im_user(用户表)

字段
类型
说明
id
String (PK)
用户唯一标识
user_id
String
业务用户 ID
name
String
昵称
avatar
String
头像 URL
account
String
账号
email
String
邮箱
sex
Integer
性别
token
String
访问令牌
refresh_token
String
刷新令牌
open_id
String
第三方 OAuth 标识
last_opt_time
DateTime
最后操作时间
ip_info
JSON
IP 地理信息
state
Integer
在线状态
create_time / update_time
DateTime
时间戳

2. im_contact(会话/联系人表)

字段
类型
说明
id + login_uid
复合主键
会话 ID + 登录用户 ID
room_id
String
关联房间 ID
contact_type
Integer
会话类型(私聊/群聊)
top
Integer
是否置顶
remark
String
备注名
unread_count
Integer
未读消息数
mute_notification
Integer
免打扰级别(0=正常/1=免打扰/4=已退群)
text
String
最后一条消息预览
active_time
DateTime
最后活跃时间

3. im_room(房间表)

字段
类型
说明
id + login_uid
复合主键
房间 ID + 登录用户 ID
group_id
String
群组 ID
room_name
String
房间名称
remark
String
备注

4. im_room_member(群成员表)

字段
类型
说明
id + login_uid
复合主键
成员 ID + 登录用户 ID
room_id
String
房间 ID
uid
String
成员用户 ID
group_role
Integer
群角色(群主/管理员/普通成员)
active_status
Integer
在线状态
avatar / name
String
头像/昵称

5. im_message(本地消息缓存表)

字段
类型
说明
id + login_uid
复合主键
消息 ID + 登录用户 ID
uid
String
发送者 ID
nickname
String
发送者昵称
room_id
String
房间 ID
send_time
DateTime
发送时间
message_type
Integer
消息类型(文本/图片/文件/视频等)
body
JSON
消息体
send_status
Integer
发送状态(待发/成功/失败)
message_marks
JSON
消息表态数据
time_block
Integer
时间块(用于消息分页)

6. im_config(键值配置表)

字段
类型
说明
id + login_uid
复合主键
配置 ID + 登录用户 ID
config_key
String
配置键
config_value
String
配置值

设计亮点

  • 多数表使用 (id, login_uid) 作为复合主键,支持同一台机器多用户数据隔离。
  • im_message

     表通过 time_block 字段实现消息时间分块,优化历史消息查询性能。
  • 后续迁移脚本逐步补充了 Token 字段、消息表扩展等。
    图片

五、设计模式

HuLa 的前端代码中大量使用了设计模式,这是项目最值得称道的架构决策之一。

5.1 消息策略模式(MessageStrategy)

在 src/strategy/MessageStrategy.ts(1345 行)中,项目实现了一套完整的策略模式来处理不同类型的消息。

核心结构为 AbstractMessageStrategy 抽象基类,定义了 getMsg()buildBody()getMessageType() 等抽象方法。针对每种消息类型,都有独立的策略实现:

策略实现类
处理消息类型
TextMessageStrategyImpl
文本消息
ImageMessageStrategyImpl
图片消息
FileMessageStrategyImpl
文件消息
EmojiMessageStrategyImpl
表情消息
VideoMessageStrategyImpl
视频消息
VoiceMessageStrategyImpl
语音消息
VideoCallMessageStrategyImpl
视频通话消息
AudioCallMessageStrategyImpl
音频通话消息
LocationMessageStrategyImpl
位置消息
UnsupportedMessageStrategyImpl
不支持的消息类型

这种设计的优势在于:新增消息类型时只需添加一个新的策略类,无需修改现有代码。同时每个策略类内部封装了该类型消息的构建、渲染、校验逻辑,职责清晰。

在安全方面,TextMessageStrategyImpl 的 getMsg() 方法在渲染文本前使用 DOMPurify.sanitize() 进行 XSS 防护,确保用户输入不会被注入恶意脚本。

5.2 触发策略模式(TriggerStrategy)

在 src/strategy/TriggerStrategy.ts(129 行)中,项目实现了触发器策略模式,用于处理消息输入框中的特殊字符触发行为:

  • @

    触发 @提及下拉列表,选择群成员或好友
  • /

    触发 AI 模型选择下拉
  • #

    触发话题选择

使用工厂方法 createTriggerStrategyMap() 构建触发器映射表,输入框在检测到对应前缀字符时自动显示对应的下拉面板。这也是策略模式的一个典型应用。

5.3 多提供者上传策略

useUpload.ts(759 行)支持多上传提供者(七牛云、腾讯云等),通过 UploadProviderEnum 枚举和 UploadSceneEnum(聊天、头像、文件等场景)实现场景化的上传路由。不同场景对应不同的上传路径和策略。


六、通信机制

HuLa 的通信分为两层:前端与 Rust 后端的 IPC 通信 和 Rust 后端与远程服务端的网络通信

6.1 前端 ↔ Rust 后端(IPC)

前端通过 Tauri 的 invoke() 调用 Rust 命令,Rust 通过 emit() 向指定窗口推送事件:

// 前端调用 Rust
const result = awaitinvoke('send_message', { roomId, body });

// Rust 向前端推送事件
app.emit("ws-receive-message", data);

前端封装了 RustWebSocketClient 类,统一管理 25+ 种事件的监听与分发,通过 mitt 事件总线将消息推送到各个 Vue 组件。

6.2 Rust 后端 ↔ 远程服务端(网络)

HTTP 层im_request_client.rs):

  • 基于 reqwest::Client 封装,携带 Basic Auth 头 + Token 头。
  • 自动 Token 刷新

    收到 406 响应时自动调用刷新接口并重试(最多 2 次)。
  • SSE 流式请求

    request_stream() 方法支持 text/event-stream,用于 AI 聊天流式输出。
  • 定义了 220+ 个 API 端点,覆盖认证、IM、社交、AI 全领域。

WebSocket 层websocket/client.rs,1194 行):

这是整个项目中最复杂的核心模块之一。WebSocketClient 实现了完整的 WebSocket 客户端:

  • 连接建立

    URL 携带 clientId 和 Token 参数,通过 connect_async() 建立连接。
  • 心跳保活

    定时发送心跳,记录最后 Pong 时间。前台模式连续 3 次失败触发重连,后台模式放宽到 5 次。
  • 指数退避重连

    重连间隔从 1 秒开始指数增长,上限 15 秒,支持无限重试。
  • 待发消息队列

    断线期间发送的消息缓存到队列(最大 100 条),重连后自动补发。
  • 连接互斥

    通过 Arc<Mutex<()>> 防止并发连接。
  • 多 Task 协作

    独立的 Tokio Task 分别处理发送、接收、心跳监控,所有 Task 通过 Handle 追踪,确保清理时不会泄漏。

业务消息路由:Rust 层收到 WebSocket 消息后,按 type 字段分发为不同的 Tauri 事件推送到前端:

WS 消息类型
Tauri 事件
说明
loginQrCode
ws-login-qr-code
二维码登录
loginSuccess
ws-login-success
登录成功
receiveMessage
ws-receive-message
新消息(自动 ACK)
msgRecall
ws-msg-recall
消息撤回
msgMarkItem
ws-msg-mark-item
消息表态
online/offline
ws-online/ws-offline
用户在线/离线
VideoCallRequest
ws-video-call-request
视频通话请求
WEBRTC_SIGNAL
ws-webrtc-signal
WebRTC 信令
tokenExpired
ws-token-expired
Token 过期(多端登录踢出)
feedSendMsg
ws-feed-send-msg
社交动态消息

图片

七、安全机制

HuLa 在安全层面采用了多层次防护策略,不仅仅是本地数据库加密。

7.1 本地数据加密

  • SQLCipher

  • SQLite 数据库使用 SQLCipher 加密,确保聊天记录、用户信息等敏感数据在磁盘上以密文存储。
  • 按用户隔离

    每个用户独立的数据库文件,通过 switch_user_database 命令切换,避免多用户数据串扰。

7.2 XSS 防护

  • 消息渲染层(TextMessageStrategyImpl)使用 DOMPurify.sanitize() 对所有用户输入的文本进行 XSS 过滤,防止恶意脚本注入。
  • Tauri 的 WebView 环境本身提供了 CSP 限制,虽然当前 CSP 设置为 null(依赖应用层防护),但 Tauri 的 IPC 桥接层天然隔离了危险的 Node.js API。

7.3 Token 安全管理

  • TokenManager

    src/utils/TokenManager.ts):独立的 Token 管理类,提供 updateToken() 和 updateTokenSilently() 两种更新策略。
  • 自动刷新

    HTTP 层在收到 406 响应时自动调用刷新接口并重试(最多 2 次),避免用户因 Token 过期被强制登出。
  • 多端登录检测

    WebSocket 层收到 tokenExpired 事件时,说明该账号在其他设备登录,当前设备将被踢出。

7.4 WASM MD5 校验

  • 使用 WebAssembly(digest-wasm)替代 JavaScript 实现 MD5 哈希计算,用于文件去重、完整性校验和上传前的文件指纹生成。WASM 的执行速度远快于纯 JS 实现,尤其在大文件场景下优势明显。

7.5 Tauri 安全能力模型

  • 项目使用 Tauri 的能力(Capability)分离机制:default-capabilitymobile-capabilitydesktop-capability 分别定义不同平台的权限范围。
  • 更新签名验证

    tauri.conf.json 中配置了 Minisign 公钥,所有自动更新包必须通过签名验证才能安装,防止供应链攻击。
  • Asset 协议

    启用 asset:// 协议访问本地文件,scope 设置为 **,允许前端安全地加载本地资源(图片、视频等)而无需通过网络。

7.6 请求队列与优先级控制

  • src/utils/RequestQueue.ts

     实现了带优先级的请求队列,最大并发 5 个请求,队列容量上限 100,防止网络请求洪峰导致系统过载。

八、性能优化

HuLa 在性能层面做了大量针对性优化。

8.1 自定义虚拟列表

项目并未使用第三方虚拟滚动库,而是自主实现了 VirtualList.vue 组件:

  • 幻影滚动条

    通过模拟滚动条高度保持原生滚动体验,同时只渲染可视区域内的 DOM 节点。
  • 向上滚动加载

    支持向上滚动时自动加载历史消息,并精确保存滚动位置。
  • 滚动位置恢复

    消息列表更新后通过 requestAnimationFrame + scrollTop 精确恢复滚动位置,避免跳动。

这对于 IM 应用至关重要——一个长聊可能有数千条消息,如果不使用虚拟列表,DOM 节点数会爆炸式增长,导致页面卡顿甚至崩溃。

8.2 Web Workers

项目使用了两个 Web Worker 将重计算任务移出主线程:

  • fingerprint.worker.ts

    浏览器/设备特征检测(WebGL、Canvas 等),不阻塞 UI 渲染。
  • timer.worker.ts

    定时器管理与心跳检测,替代主线程的 setInterval,避免时间漂移。

8.3 已读消息批量请求

ReadCountQueue.ts(244 行)实现了已读状态的批量上报机制:

  • 使用 Set 去重,将短时间内打开的多个会话的已读请求合并。
  • 10 秒定时轮询,而非每次打开会话立即上报。
  • 支持 AbortController 取消请求,避免页面关闭后无效请求。

8.4 Intersection Observer 懒加载

useIntersectionTaskQueue.ts 使用 Intersection Observer API 实现基于可视区域的懒加载任务调度,仅当消息气泡进入可视区域时才触发渲染和媒体资源加载。

8.5 图片缩略图缓存

thumbnailCache.ts 独立 store 管理图片缩略图缓存,避免大图直接渲染导致的内存暴增。缩略图在本地 SQLite 中持久化,减少重复解码开销。

8.6 Web Vitals 性能监控

WebVitalsObserver.ts 集成 Web Vitals 指标监控:

  • CLS

    (Cumulative Layout Shift):累计布局偏移,衡量页面稳定性。
  • FCP

    (First Contentful Paint):首次内容绘制,衡量首屏速度。
  • INP

    (Interaction to Next Paint):交互到下次绘制,衡量响应性。
  • LCP

    (Largest Contentful Paint):最大内容绘制,衡量加载速度。
  • TTFB

    (Time to First Byte):首字节时间,衡量网络延迟。

开发模式下还通过 MemoryMonitor.vue 组件实时监控内存占用。


九、前端入口与初始化流程

前端入口src/main.ts):

  1. 初始化 UnoCSS、全局 Reset CSS、TLBS Map。
  2. 调用 initializePlatform() 检测平台能力。
  3. 启动 Web Vitals 性能监控。
  4. 移动端调用 iOS 角标授权。
  5. 导入 WebSocket 适配器(触发 Rust 层 WS 客户端初始化)。
  6. 创建 Vue App,挂载 Router、Pinia、i18n、自定义指令。
  7. 设置全局错误处理器。

根组件src/App.vue):

  • 使用 NaiveProvider 包裹全局消息/通知。
  • 条件渲染锁屏组件或正常路由视图。
  • 开发模式下启动内存监控。
  • 注册完整的 WebSocket 事件监听:登录、消息收发、撤回、表态、在线状态、好友请求、群变更、视频通话(WebRTC)、社交动态、Token 过期。

Rust 入口src-tauri/src/lib.rs):

  1. run()

     函数通过 #[cfg(desktop)] / #[cfg(mobile)] 分发到桌面端或移动端设置。
  2. 桌面端构建 Tauri App,注册插件、窗口事件处理器、所有 invoke 处理器。
  3. common_setup()

     异步初始化:加载配置 → 连接 SQLite → 执行数据库迁移 → 创建 HTTP 客户端 → 注入 AppData 到 Tauri 状态管理。
  4. 创建系统托盘(桌面端)。
  5. 注册登出事件监听。
    图片

十、状态管理(Pinia Stores)

前端使用 Pinia 进行全局状态管理,共 33 个 store

Store
职责
chat.ts
当前聊天会话状态(51KB,核心 store)
user.ts
当前用户资料
contacts.ts
好友/联系人列表
group.ts
群聊管理
sessionUnread.ts
各会话未读数
history.ts
聊天历史
ws.ts
WebSocket 连接状态
setting.ts
用户偏好(主题、锁屏等)
bot.ts
AI 聊天助手状态
emoji.ts
自定义表情管理
file.ts
 / fileDownload.ts
文件状态/下载管理
imageViewer.ts
 / videoViewer.ts
媒体查看器
notice.ts
通知中心
feed.ts
 / feedNotification.ts
社交动态
scanner.ts
二维码扫描
thumbnailCache.ts
图片缩略图缓存
loginHistory.ts
登录历史
initialSync.ts
初始化数据同步
其他辅助状态

核心 chat.ts 管理消息收发、缓存策略、离线同步、多会话协调,是整个前端最复杂的状态模块。

图片

十一、Hook 架构

HuLa 的前端架构核心是 Composition API Hooks。项目 src/hooks/ 目录下有 43 个自定义 Hook,将复杂业务逻辑从组件中完全抽离,实现高复用性和可测试性。

核心业务 Hooks

Hook
行数
职责
useChatMain.ts
1358 行
聊天主面板逻辑:消息加载、滚动控制、新消息推送、历史消息分页
useMsgInput.ts
1373 行
消息输入框:@提及、AI 模型选择、表情插入、文件拖拽、特殊字符触发
useLogin.ts
774 行
登录流程编排:账号密码登录、二维码轮询、OAuth 授权、自动登录
useUpload.ts
770 行
文件上传管理:七牛云分片上传、断点续传、多提供者路由、场景化上传策略
useCommon.ts
939 行
通用逻辑层:消息发送、撤回、回复、转发、下载等共享操作

音视频 Hooks

Hook
行数
职责
useWebRtc.ts
1172 行
WebRTC 点对点连接:ICE 候选交换、媒体流管理、多人通话、信令处理
useAudioPlayback.ts
-
音频播放控制:语音消息播放、暂停、进度跳转
useVoiceRecordRust.ts
-
语音录制:通过 Rust 后端调用系统录音能力
useWaveformRenderer.ts
10427 字节
波形可视化:Canvas 实时渲染音频波形
useVoiceDragControl.ts
8522 字节
语音拖拽控制:拖拽取消发送、拖拽预览

系统与工具 Hooks

Hook
职责
useWindow.ts
多窗口管理:创建、关闭、聚焦、置顶
useGlobalShortcut.ts
全局快捷键注册与分发
useMitt.ts
事件总线封装(基于 mitt)
useNetworkStatus.ts
网络状态监控:在线/离线检测、重连提示
useGeolocation.ts
地理位置获取与发送
useFileUploadQueue.ts
文件上传队列管理
useIntersectionTaskQueue.ts
Intersection Observer 懒加载任务调度
useFixedScale.ts
固定缩放比例变换
useCanvasTool.ts
截图画布工具:矩形/圆形/箭头/文字标注、撤销/重做

Hook 设计原则

  1. 单一职责

    每个 Hook 只处理一个领域的逻辑,如 useWebRtc.ts 专注 WebRTC,useMsgInput.ts 专注输入。
  2. 组合优于继承

    Hook 之间通过返回值组合使用,如 useChatMain 内部组合了 useCommon 的消息发送能力。
  3. 与 Pinia 解耦

    Hook 通过 storeToRefs 读取 Pinia 状态,但自身不持有 store 实例,保证可测试性。

十二、WebRTC 音视频通话

HuLa 的音视频通话基于 WebRTC 技术实现,由 useWebRtc.ts(1172 行)主导。

技术架构

┌──────────────────────────────────────────┐
│           前端 Vue 组件层                   │
│  callWindow.vue / VideoCall.vue           │
├──────────────────────────────────────────┤
│         useWebRtc.ts (Hook)               │
│  - PeerConnection 管理                    │
│  - ICE Candidate 交换                     │
│  - MediaStream 处理(音视频轨)            │
│  - 多人通话支持(SFU 模式)                │
├──────────────────────────────────────────┤
│     WebSocket 信令层(Rust 转发)           │
│  VideoCallRequest → ws-video-call-request │
│  WEBRTC_SIGNAL → ws-webrtc-signal         │
└──────────────────────────────────────────┘

核心功能

  • 一对一通话

    点对点 WebRTC 连接,ICE 候选通过 WebSocket 信令交换。
  • 多人通话

    支持 SFU(Selective Forwarding Unit)模式,多参与者通过服务端转发媒体流。
  • 信令转发

    Rust 层不直接参与 WebRTC 连接,而是作为信令中转站,将 VideoCallRequest 和 WEBRTC_SIGNAL 事件转发给目标用户。
  • 通话 UI

    独立的 callWindow 窗口,包含通话控制按钮(麦克风静音、摄像头关闭、挂断、屏幕共享)、通话计时器、对方头像和名称。
  • 屏幕共享

    SharedScreen.vue 提供独立的屏幕共享窗口,通过 getDisplayMedia API 捕获桌面画面。
  • 语音录制

    VoiceRecorder.vue(10081 字节)支持语音消息录制,通过 Rust 后端调用系统录音 API,录制过程中 Canvas 实时渲染波形图,支持拖拽取消发送。

十三、系统功能模块

13.1 用户认证

  • 账号密码登录、二维码扫码登录
  • GitHub / Gitee / GitCode OAuth 第三方登录
  • 多设备登录管理、自动登录(3 秒延迟 + 可取消)
  • Rust 层独立 OAuth Server 处理二维码登录流程

13.2 消息通信

  • 一对一私聊、群组聊天
  • 12 种消息类型渲染:文本、图片、文件、视频、音频、表情、位置、语音通话、视频通话、合并转发、公告、系统消息
  • 消息撤回、@提醒、回复、已读状态
  • 消息点赞/表态
  • 消息转发、链接预览
  • 历史消息按时间分块查询

13.3 社交管理

  • 好友添加/搜索/删除、在线状态显示
  • 群组创建与管理(成员管理、群公告)
  • 备注昵称、屏蔽/拉黑/免打扰
  • 位置发送、二维码扫码进群
  • 社交动态(Feed)发布与互动

13.4 系统功能

  • 多窗口管理

    主窗口、登录窗口、截图窗口、通话窗口、图片查看器、视频查看器、文件管理器、消息通知中心等独立窗口
  • 截图功能

    桌面端截图组件(近 49KB)
  • 语音/视频通话

    基于 WebRTC,Rust 层处理信令转发
  • 文件上传

    七牛云分片上传,支持断点续传
  • 自动更新

    双源更新机制(toolsetlink.com 主源 + Gitee Releases 备用)
  • 全局快捷键

  • 系统托盘通知

13.5 AI 集成

  • 内置 AI 聊天助手,与普通消息在同一对话流
  • 流式输出支持(SSE)
  • 停止回复功能
  • 支持多平台 AI 接入:对话、图片生成(Midjourney)、视频、音频、音乐生成、知识库 RAG、思维导图、工作流、AI 写作

13.6 界面与体验

  • 深色/浅色主题切换、跟随系统主题
  • 自定义皮肤
  • 国际化(中英文,完成度 98%)
  • Vue Virtual Scroller 处理超长聊天列表性能
    图片

十四、工程化与 CI/CD

HuLa 的工程化水平按企业级标准执行,从代码规范到自动发版形成完整闭环。

14.1 代码规范

  • Biome 2.3

    替代 ESLint + Prettier 的组合方案,同时负责代码检查(lint)和格式化(format)。Biome 基于 Rust 实现,速度比 ESLint 快数倍。
  • Husky + lint-staged

    Git pre-commit 钩子,提交前自动执行 lint:staged,阻止不合格代码入库。
  • Conventional Commits

    通过 pnpm commit(基于 cz-git)引导规范化提交消息,格式为 <type>(<scope>): <description>

14.2 依赖与发版

  • Renovate

    自动检测依赖更新并创建 PR,保持项目依赖版本最新。
  • Release-it

    自动化发版流程,自动更新版本号、生成 CHANGELOG、创建 Git Tag、推送到 GitHub Releases。

14.3 GitHub Actions 工作流

项目在 .github/workflows/ 下配置了 7 个 CI/CD 工作流:

工作流
职责
release.yml
多平台自动发版:macOS ARM/Intel、Ubuntu、Windows,Tauri 签名、UpgradeLink 集成、增量/全量构建检测
codeql.yml
GitHub CodeQL 安全分析,检测 SQL 注入、XSS 等漏洞
dependency-review.yml
依赖安全审查,阻止含已知漏洞的依赖进入主分支
rust-clippy.yml
Rust Clippy 静态分析,检查 Rust 代码质量和最佳实践
debug-build.yml
调试构建测试,确保代码可编译
greetings.yml
新人欢迎自动化,首次贡献时发送欢迎消息
label.yml
PR 自动标签,根据变更文件自动添加分类标签

14.4 构建脚本

scripts/ 目录下包含多个构建辅助脚本:

  • interactive-build-inquirer.js

    (10624 字节):交互式构建配置向导,支持选择目标平台、构建模式等。
  • check-dependencies.js

    (8606 字节):依赖校验脚本,确保环境满足 Node.js ^20.19.0 或 >=22.12.0、pnpm >= 10 的要求。
  • link-skills.js

    Claude Code 技能链接脚本。

14.5 平台条件构建

  • 构建系统根据 TAURI_ENV_PLATFORM 环境变量动态加载 PC 或移动端组件目录。
  • UnoCSS 配置在不同平台解析不同的样式文件,移动端和桌面端样式分离。
  • 移动端专属代码(src/mobile/)和桌面端代码通过条件编译和运行时检测隔离。

14.6 自定义 Tauri 插件

tauri-plugin-hula/ 是团队自研的 Tauri 插件,包含:

  • Rust 源码

    核心插件逻辑,暴露给前端使用。
  • iOS 原生代码

    (Swift):ios/Sources/ 和 ios/Tests/,包含 Swift Package Manager 配置和测试。
  • Android 原生代码

    (Kotlin):android/src/,通过 JNI 桥接 Android 原生 API。
  • TypeScript 绑定

    guest-js/ 目录,为前端提供类型安全的 JS API。
  • 权限定义

    permissions/ 目录,定义插件的能力范围。

这种"前端 JS + 后端 Rust + 移动端原生代码"的全栈插件架构,在开源 IM 项目中非常罕见。

14.7 社区规范

  • CONTRIBUTING.md

    完整的贡献指南,涵盖 Fork/Clone/Branch/PR 工作流。
  • CODE_OF_CONDUCT.md

    社区行为准则。
  • GitHub Issue/PR 模板

    结构化的问题和 Pull Request 模板,降低沟通成本。
  • CHANGELOG.md

    维护版本变更日志。
  • FUNDING.yml

    赞助者体系配置。

十五、快速上手

# 克隆项目
git clone https://github.com/HuLaSpark/HuLa.git
cd HuLa

# 安装依赖
pnpm install

# 启动开发模式
pnpm run tauri:dev

环境要求:Node.js ^20.19.0 或 >=22.12.0,pnpm >= 10,Rust 工具链。

项目地址

  • GitHub:https://github.com/HuLaSpark/HuLa
  • Gitee 镜像:https://gitee.com/HuLaSpark/HuLa
  • 官网:https://hulaspark.com
  • 配套服务端:https://github.com/HuLaSpark/HuLa-Server

十六、总结

HuLa 在技术架构上做出了几个值得关注的选择:

  1. Tauri 替代 Electron

    用操作系统原生 WebView 替代打包 Chromium,安装包从百 MB 级降至数 MB 级,内存占用降低 80%+。
  2. Rust 处理系统级能力

    数据库、网络、文件、窗口管理全部由 Rust 处理,前端只负责 UI 渲染和交互。
  3. 完善的 WebSocket 客户端

    心跳保活、指数退避重连、待发消息队列、前后态感知,是一个生产级实时通信实现。
  4. 多窗口架构

    不同功能使用独立 WebView 窗口,互不干扰。
  1. 前后端完全开源

    配套 HuLa-Server 独立服务端,支持企业私有化部署。

对于想学习 Tauri 开发、研究 Vue 3 大型应用架构、或者需要一个可私有部署 IM 方案的开发者来说,这是一个值得深入研读的项目。


群贤毕至

访客