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 也完全开源,前后端解耦,支持私有化部署。
技术选型:
二、系统架构
HuLa 采用 Tauri 双进程架构:Rust 原生后端进程 + WebView 前端进程,两者通过 Tauri IPC 桥接。
┌──────────────────────────────────────────────────────────┐
│ 用户设备(五端) │
├──────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ ┌──────────────────────┐ │
│ │ Vue 3 前端进程 │ │ Rust 后端进程 │ │
│ │ (WebView 渲染) │◄──►│ (原生系统层) │ │
│ │ │ IPC│ │ │
│ │ - 页面渲染 │ │ - 窗口管理 │ │
│ │ - 用户交互 │ │ - 系统托盘 │ │
│ │ - 组件状态 │ │ - 文件系统 │ │
│ │ - 路由导航 │ │ - 数据库操作 │ │
│ └─────────────────────┘ │ - WebSocket 客户端 │ │
│ │ - HTTP 请求代理 │ │
│ │ - 全局快捷键 │ │
│ │ - 截图功能 │ │
│ └──────────┬───────────┘ │
│ │ │
│ ┌──────────▼───────────┐ │
│ │ SQLite 本地数据库 │ │
│ │ (SQLCipher 加密) │ │
│ └──────────────────────┘ │
│ │
└──────────────────────┬───────────────────────────────────┘
│ HTTPS / WebSocket
▼
┌─────────────────┐
│ HuLa-Server │
│ (独立服务端) │
└─────────────────┘
架构要点:
前端 SPA
Vue 3 单页应用,运行在操作系统原生 WebView 中,不打包 Chromium,安装包仅数 MB。 Rust 后端
处理所有系统级能力——数据库、网络请求、文件操作、窗口管理、托盘通知等。 IPC 通信
前端通过 invoke()调用 Rust 命令,Rust 通过emit()向前端推送事件。本地数据库
每个用户独立的 SQLite 数据库文件,使用 SQLCipher 加密,SeaORM 管理数据模型。 WebSocket 客户端
Rust 层维护与服务端的 WebSocket 长连接,负责消息收发、心跳保活、断线重连。 多窗口
不同功能使用独立 WebView 窗口(主窗口、登录窗口、截图窗口、通话窗口、图片查看器等)。 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(用户表)
2. im_contact(会话/联系人表)
3. im_room(房间表)
4. im_room_member(群成员表)
5. im_message(本地消息缓存表)
6. im_config(键值配置表)
设计亮点:
多数表使用 (id, login_uid)作为复合主键,支持同一台机器多用户数据隔离。im_message表通过 time_block字段实现消息时间分块,优化历史消息查询性能。后续迁移脚本逐步补充了 Token 字段、消息表扩展等。
五、设计模式
HuLa 的前端代码中大量使用了设计模式,这是项目最值得称道的架构决策之一。
5.1 消息策略模式(MessageStrategy)
在 src/strategy/MessageStrategy.ts(1345 行)中,项目实现了一套完整的策略模式来处理不同类型的消息。
核心结构为 AbstractMessageStrategy 抽象基类,定义了 getMsg()、buildBody()、getMessageType() 等抽象方法。针对每种消息类型,都有独立的策略实现:
这种设计的优势在于:新增消息类型时只需添加一个新的策略类,无需修改现有代码。同时每个策略类内部封装了该类型消息的构建、渲染、校验逻辑,职责清晰。
在安全方面,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 事件推送到前端:
七、安全机制
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-capability、mobile-capability、desktop-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):
初始化 UnoCSS、全局 Reset CSS、TLBS Map。 调用 initializePlatform()检测平台能力。启动 Web Vitals 性能监控。 移动端调用 iOS 角标授权。 导入 WebSocket 适配器(触发 Rust 层 WS 客户端初始化)。 创建 Vue App,挂载 Router、Pinia、i18n、自定义指令。 设置全局错误处理器。
根组件(src/App.vue):
使用 NaiveProvider包裹全局消息/通知。条件渲染锁屏组件或正常路由视图。 开发模式下启动内存监控。 注册完整的 WebSocket 事件监听:登录、消息收发、撤回、表态、在线状态、好友请求、群变更、视频通话(WebRTC)、社交动态、Token 过期。
Rust 入口(src-tauri/src/lib.rs):
run()函数通过 #[cfg(desktop)]/#[cfg(mobile)]分发到桌面端或移动端设置。桌面端构建 Tauri App,注册插件、窗口事件处理器、所有 invoke 处理器。 common_setup()异步初始化:加载配置 → 连接 SQLite → 执行数据库迁移 → 创建 HTTP 客户端 → 注入 AppData到 Tauri 状态管理。创建系统托盘(桌面端)。 注册登出事件监听。
十、状态管理(Pinia Stores)
前端使用 Pinia 进行全局状态管理,共 33 个 store:
chat.ts | |
user.ts | |
contacts.ts | |
group.ts | |
sessionUnread.ts | |
history.ts | |
ws.ts | |
setting.ts | |
bot.ts | |
emoji.ts | |
file.tsfileDownload.ts | |
imageViewer.tsvideoViewer.ts | |
notice.ts | |
feed.tsfeedNotification.ts | |
scanner.ts | |
thumbnailCache.ts | |
loginHistory.ts | |
initialSync.ts | |
核心 chat.ts 管理消息收发、缓存策略、离线同步、多会话协调,是整个前端最复杂的状态模块。
十一、Hook 架构
HuLa 的前端架构核心是 Composition API Hooks。项目 src/hooks/ 目录下有 43 个自定义 Hook,将复杂业务逻辑从组件中完全抽离,实现高复用性和可测试性。
核心业务 Hooks
useChatMain.ts | ||
useMsgInput.ts | ||
useLogin.ts | ||
useUpload.ts | ||
useCommon.ts |
音视频 Hooks
useWebRtc.ts | ||
useAudioPlayback.ts | ||
useVoiceRecordRust.ts | ||
useWaveformRenderer.ts | ||
useVoiceDragControl.ts |
系统与工具 Hooks
useWindow.ts | |
useGlobalShortcut.ts | |
useMitt.ts | |
useNetworkStatus.ts | |
useGeolocation.ts | |
useFileUploadQueue.ts | |
useIntersectionTaskQueue.ts | |
useFixedScale.ts | |
useCanvasTool.ts |
Hook 设计原则
单一职责
每个 Hook 只处理一个领域的逻辑,如 useWebRtc.ts专注 WebRTC,useMsgInput.ts专注输入。组合优于继承
Hook 之间通过返回值组合使用,如 useChatMain内部组合了useCommon的消息发送能力。与 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提供独立的屏幕共享窗口,通过getDisplayMediaAPI 捕获桌面画面。语音录制
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 | |
codeql.yml | |
dependency-review.yml | |
rust-clippy.yml | |
debug-build.yml | |
greetings.yml | |
label.yml |
14.4 构建脚本
scripts/ 目录下包含多个构建辅助脚本:
interactive-build-inquirer.js(10624 字节):交互式构建配置向导,支持选择目标平台、构建模式等。 check-dependencies.js(8606 字节):依赖校验脚本,确保环境满足 Node.js ^20.19.0 或 >=22.12.0、pnpm >= 10 的要求。 link-skills.jsClaude 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 在技术架构上做出了几个值得关注的选择:
Tauri 替代 Electron
用操作系统原生 WebView 替代打包 Chromium,安装包从百 MB 级降至数 MB 级,内存占用降低 80%+。 Rust 处理系统级能力
数据库、网络、文件、窗口管理全部由 Rust 处理,前端只负责 UI 渲染和交互。 完善的 WebSocket 客户端
心跳保活、指数退避重连、待发消息队列、前后态感知,是一个生产级实时通信实现。 多窗口架构
不同功能使用独立 WebView 窗口,互不干扰。
前后端完全开源
配套 HuLa-Server 独立服务端,支持企业私有化部署。
对于想学习 Tauri 开发、研究 Vue 3 大型应用架构、或者需要一个可私有部署 IM 方案的开发者来说,这是一个值得深入研读的项目。