架构总览与演进背景
v1 架构:纯 Native macOS 应用
Raycast v1 本质上是一个用 Swift 基于 AppKit 构建的原生 macOS 应用。这一技术选择反映了团队在产品早期的明确偏好:深度控制每一个交互细节。
AppKit 的深度定制
Raycast 团队在 v1 中几乎完全不使用标准 UI 组件:
“We almost never reached for standard UI components. They weren’t built for the kind of keyboard-first, power-user workflows we cared about, so we built our own.”
(我们几乎从不使用标准 UI 组件。它们不是为键盘优先的极客用户工作流设计的,所以我们自己构建了一套。)
具体实施层面,这意味着:
- 每一行列表、每一个快捷键、每一个默认行为都由团队自行实现
- 没有依赖 SwiftUI(尽管它与 Raycast 同时成熟),因为性能和控制的门槛始终未达到
- SwiftUI 仅在每年的 Wrapped 功能中使用,与主应用完全隔离
扩展子系统:Web 技术早期尝试
Raycast 的扩展生态采用了完全不同的技术栈:
- React + TypeScript + Node.js 构成的声明式 UI 系统将 UI 描述以声明式方式传递给 Native 应用渲染
- 这一架构设计时就考虑了可移植性——扩展从不假设自己运行在 macOS 上
- 这个预见性的设计使得 2024 年可以将大量扩展带到 Windows 平台
Notes 功能:Web 技术的成功试水
Raycast Notes 是应用中首个使用 WebView 的重要功能:
- 编辑器是一个挂载在 Native 窗口 WebView 中的 React 应用
- 验证了 “纯 Web 技术构建功能而不破坏应用整体体验” 的可行性
- 被 macOS 和 iOS 的每日大量活跃用户所证明
重构动因:从启动器到生产力平台
时机选择:Windows 支持与架构老化
2023 年底,团队开始认真考虑将 Raycast 带到 Windows。这并非突如其来的想法:
“It was always the plan, from day one, but in the early days we wanted to focus on a single platform and nail the experience there before even considering expanding.”
(从第一天起这就是计划,但早期我们想先专注于单一平台,把体验做到极致,然后再考虑扩展。)
然而此时的 Raycast 已经从一个简单的启动器成长为包含 AI Chat、Notes、扩展、同步、文件搜索等功能的生产力平台。原有架构开始显现出根本性限制:
| 限制维度 | 具体表现 |
|---|---|
| 编译时间 | 逐渐上升,影响开发效率 |
| AppKit 的限制 | 频繁干扰新功能的实现 |
| 人才稀缺 | 掌握深度 Native macOS 开发的人才越来越难找 |
用团队的话说:“Even if Windows wasn’t on the table, we’d have needed to rethink most of this.”(即使不考虑 Windows,我们也需要重新思考大部分架构。)
项目代号:X-Ray
任何大规模重构项目都需要一个代号。Raycast 团队将此项目命名为 “X-Ray”,代表 “cross-platform Raycast”(跨平台 Raycast)。
v2 架构:Four-Runtime 混合模型
Raycast 2.0 采用了一种独特的四层架构,每个组件都由最适合该任务的技术构建:
flowchart TB
subgraph "Host Apps"
A1[Swift + AppKit<br/>macOS Host]
A2[C# + .NET 8 + WPF<br/>Windows Host]
end
subgraph "Shared Layers"
B[Web Frontend<br/>React + TypeScript]
C[Node Backend<br/>Business Logic]
D[Rust Core<br/>Performance Critical]
end
A1 -->|Loads| B
A2 -->|Loads| B
B <-->|IPC| C
C <-->|Shared Lib| D
style A1 fill:#c6e0ff
style A2 fill:#c6e0ff
style B fill:#ffe6cc
style C fill:#d4edda
style D fill:#f8d7da
1. Host App(平台特定外壳)
每个平台有自己的原生应用:
macOS 版本:
- 语言:Swift
- 框架:AppKit
- 职责:窗口管理、全局快捷键监听、菜单栏/托盘配置、加载 Web 前端到 WKWebView
- 额外角色:监督 Node 后端进程
Windows 版本:
- 语言:C#
- 框架:.NET 8 + WPF
- 职责与 macOS 版本对称
- WebView:WebView2(基于 Chromium)
2. Web Frontend(共享 UI 层)
- 单一代码库:一个 React + TypeScript 项目同时服务于两个平台
- 多入口点:为不同窗口(Launcher、AI Chat、Notes、Settings 等)构建独立的 entry points
- 100% 代码共享:两个操作系统使用完全相同的 UI 代码库
3. Node Backend(共享业务逻辑层)
- 单长生命期进程:持续运行的 Node 进程承载应用的核心业务逻辑
- 职责范围:
- 数据库访问
- 扩展运行时(运行用户安装的 JavaScript 扩展)
- 其他长驻服务
- 跨平台价值:Node 是 Mac 和 Windows 共享的层,功能开发只需进行一次
4. Rust Core(性能关键层)
Rust 被用于性能或跨平台能力比开发便利性更重要的场景:
| 组件 | 用途 |
|---|---|
| 数据层 | 与 iOS 应用共享的数据模型 |
| 云同步引擎 | 与服务器端共享 schema |
| 文件索引器 | 自定义实现的文件搜索,用于在数秒内扫描整个硬盘 |
层间通信机制
四个 Runtime 之间需要高效通信。Raycast 采用混合方案:
flowchart LR
A[WebView] <-->|Platform Message Handlers| B[Host App]
B <-->|Stdio Transport| C[Node Backend]
C <-->|Library Call| D[Rust Core]
style A fill:#ffe6cc
style B fill:#c6e0ff
style C fill:#d4edda
style D fill:#f8d7da
通信方式选择:
- WebView ↔ Host App:平台特定的 message handlers(WKWebView/WWebView2 原生支持)
- Host App ↔ Node Backend:通过 stdio 传输(stdin/stdout 管道)
- Node Backend ↔ Rust Core:直接的库调用(通过 FFI 或 native addon)
类型安全保证:
“To make this safe to work with, interfaces are declared in one place and typed clients are generated for every side.”
(为了确保类型安全,接口在一个地方声明,然后为每个 Runtime 生成带类型的客户端。)
这意味着跨语言调用在编译时即可获得类型检查,避免运行时类型错误。
开发工作分布
实际开发中,团队的工作重心分布如下:
| 层级 | 人员投入 | 工作内容 |
|---|---|---|
| Web Frontend + Node Backend | 大多数团队成员 | 功能开发主战场 |
| Native Shell | 专职 Native 工程师 | 仅在需要暴露新的 OS API 或优化 Native 体验时介入 |
“Once the boundaries between the four parts are set, most product work doesn’t have to cross them.”
(一旦四个部分之间的边界设定好,大部分产品工作无需跨越这些边界。)
架构演进的核心逻辑
从 v1 到 v2 的架构变迁体现了一套清晰的技术决策框架:
flowchart TD
A[v1: Swift Native<br/>高质量但开发慢] --> B{Windows 支持?}
B -->|Yes| C[必须跨平台]
B -->|No| D[人才稀缺<br/>限制发展]
C --> E[评估方案: Electron/Tauri/Flutter/Qt]
D --> E
E --> F[Electron: 生态最好<br/>但控制力不足]
E --> G[Tauri: 太年轻<br/>风险过高]
E --> H[Flutter/Qt: 控制力不够<br/>或生态不成熟]
F --> I[选择: Custom Hybrid<br/>Swift/C# + WebView]
G --> I
H --> I
I --> J[v2: Four-Runtime<br/>平衡控制与效率]
这一架构的核心设计原则是:“A native app that uses web for its UI.”(一个使用 Web 作为 UI 的 Native 应用)——与常见的 “a web app with native hooks” 定位截然相反。这个定位上的巨大差异直接决定了团队在技术实现上的优先级取舍。