架构
三进程模型、Conveyor IPC、feature flags 与启动流程。
模板围绕 Electron 的安全边界组织:特权 Node 代码留在 main process,preload 只暴露很窄的桥接层,renderer 像一个沙盒中的 React 应用。
三个进程
| 进程 | 负责 | 不应负责 |
|---|---|---|
| Main | 应用生命周期、窗口、菜单、托盘、协议、设置文件、更新服务、原生通知、安全存储、文件对话框、日志、诊断。 | React UI 和产品页面。 |
| Preload | 通过 contextBridge 暴露 window.conveyor。 | 业务逻辑、宽泛 Node API、随意 IPC。 |
| Renderer | React routes、UI state、forms、Supabase client calls、TanStack Query、命令面板、主题与 i18n UI。 | 直接文件系统、shell、ipcRenderer 或不受限制的 Node 访问。 |
lib/main/app.ts 创建 BrowserWindow 时使用 sandbox: true、
contextIsolation: true、nodeIntegration: false、webSecurity: true。
新增产品功能时应保留这个默认姿态。
Conveyor 一屏看懂
renderer 代码调用类型化方法:
const { getSettings, setSettings } = useConveyor('app')
const settings = await getSettings()
await setSettings({ theme: 'dark' })调用路径是:
React component -> window.conveyor.app.setSettings()
-> preload contextBridge
-> ipcMain handler in lib/conveyor/handlers/app-handler.ts
-> Zod-validated args and Zod-validated return value
-> typed result back to the rendererlib/main/shared.ts 包装 ipcMain.handle(),并使用
lib/conveyor/schemas/ 中的 schema 校验请求参数与 handler 返回值。app
intents、update status 等 main-to-renderer 事件也会在分发前校验。
这里没有 codegen 步骤。TypeScript 从 schema map 与导出的 Conveyor API 对象推断 channel 类型。
不要在 app 代码中导入或暴露 ipcRenderer。请新增 Conveyor schema、API method
和 handler,这样进程边界仍保持类型化并在运行时校验。
Feature flags
renderer feature flags 统一在 shared/config.ts 读取。main process 在
lib/main/feature-flags.ts 有自己的 showcase flag,这样原生菜单项能与 renderer
演示层一起消失。
| Flag | 默认值 | 进程 | 效果 |
|---|---|---|---|
VITE_AUTH_ENABLED | true | Renderer | 显示 Supabase auth/account surfaces。当前 renderer 即使如此仍会在挂载前校验 Supabase URL/key。 |
VITE_AUTO_UPDATE_ENABLED | true | Renderer | 显示 update settings 与 Update route。 |
VITE_BILLING_ENABLED | false | Renderer | 启用 Billing page actions、checkout、subscription reads 与 feature gates。 |
VITE_BILLING_LICENSE_MODE | false | Renderer | 启用可选 Creem license-key activation UI 与 service calls。 |
VITE_SHOWCASE_ENABLED | true | Renderer | 启用 Showcase routes、sidebar entries、Home demo sections 与 command palette Showcase actions。 |
MAIN_VITE_SHOWCASE_ENABLED | 回退到 VITE_SHOWCASE_ENABLED,再回退到 true | Main | 启用原生 Template menu items。应与 renderer showcase flag 保持一致。 |
计费目前是最干净的暗开关子系统:billing 关闭时,subscription store 会切到
disabled,并且不读取 Supabase。Showcase 也被 flags 与 [template-demo] 标记隔离。
状态层
| 层级 | 文件 | 说明 |
|---|---|---|
| 持久化桌面设置 | lib/main/settings.ts | 存在 Electron userData 下的版本化 JSON,向前迁移,并通过 Conveyor 读写。 |
| Auth session 与 profile | app/stores/auth-store.ts、app/lib/supabase/* | Supabase session 通过 secure-session adapter 持久化,底层由 main-process safeStorage 支持。 |
| 权益状态 | app/stores/subscription-store.ts | 仅在 billing 启用时读取 subscriptions 表;不会把未知网络状态当作已付费。 |
| 服务端数据 | app/services/*、app/lib/query/client.ts | Service functions 调 Supabase 或 Edge Functions;TanStack Query 负责 UI cache。 |
| UI 偏好 | app/utils/theme-settings.ts、settings store | 主题、accent、语言、缩放、代理与更新偏好通过 settings API 流动。 |
产品数据的替换点应放在 services。组件不应在可以由 service module 承担契约时嵌入 SQL 形状的 Supabase 调用。
启动流程
lib/main/main.ts启用 Electron sandbox,初始化日志和可选错误上报,并创建 settings store。- 应用注册
soar-electron://协议处理器。开发模式传入 Electron binary 和项目路径;打包后注册可执行文件。 initializeApplication()连接 app services:i18n、secure storage、window state、app intents、updater、tray、notifications、shortcuts、menu、resource protocol、permissions 与 Conveyor handlers。createPrimaryWindow()创建沙盒BrowserWindow,恢复尺寸位置,应用 zoom,阻止危险导航,并加载 dev server 或打包后的 renderer。app/renderer.tsx校验 Supabase env,通过 Conveyor bootstrap i18n,挂载 React,并安装 renderer 错误日志。app/app.tsx加载 theme/accent 偏好,初始化 auth 和 subscription stores,在配置时跟踪 route analytics,并处理 app intents。OnboardingGate读取持久化设置,并在完成前显示首次运行 onboarding。
deep links 与 second-instance launches 会被规范化为类型化 app intents。route
allow-list 位于 lib/conveyor/schemas/event-schema.ts,未知 deep-link route
会在 renderer 看到之前被拒绝。
放在哪里
| 任务 | 放置位置 |
|---|---|
| 新增 React route、页面、表单或产品 workflow | app/routes、app/components、app/services、app/lib/query |
| 读写本地文件、设置、系统 keychain、托盘、菜单、快捷键或通知 | lib/main 中的 Conveyor handler 后面 |
| 向 React 暴露新的 main-process 能力 | lib/conveyor/schemas、lib/conveyor/api、lib/conveyor/handlers,然后在 lib/main/main.ts 注册 |
| 共享品牌常量、feature flag 或 price-plan mapping | shared/ |
| 新增服务端计费行为 | supabase/functions 与 Supabase SQL/RLS |
