架构

三进程模型、Conveyor IPC、feature flags 与启动流程。

模板围绕 Electron 的安全边界组织:特权 Node 代码留在 main process,preload 只暴露很窄的桥接层,renderer 像一个沙盒中的 React 应用。

三个进程

进程负责不应负责
Main应用生命周期、窗口、菜单、托盘、协议、设置文件、更新服务、原生通知、安全存储、文件对话框、日志、诊断。React UI 和产品页面。
Preload通过 contextBridge 暴露 window.conveyor业务逻辑、宽泛 Node API、随意 IPC。
RendererReact routes、UI state、forms、Supabase client calls、TanStack Query、命令面板、主题与 i18n UI。直接文件系统、shell、ipcRenderer 或不受限制的 Node 访问。

lib/main/app.ts 创建 BrowserWindow 时使用 sandbox: truecontextIsolation: truenodeIntegration: falsewebSecurity: 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 renderer

lib/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_ENABLEDtrueRenderer显示 Supabase auth/account surfaces。当前 renderer 即使如此仍会在挂载前校验 Supabase URL/key。
VITE_AUTO_UPDATE_ENABLEDtrueRenderer显示 update settings 与 Update route。
VITE_BILLING_ENABLEDfalseRenderer启用 Billing page actions、checkout、subscription reads 与 feature gates。
VITE_BILLING_LICENSE_MODEfalseRenderer启用可选 Creem license-key activation UI 与 service calls。
VITE_SHOWCASE_ENABLEDtrueRenderer启用 Showcase routes、sidebar entries、Home demo sections 与 command palette Showcase actions。
MAIN_VITE_SHOWCASE_ENABLED回退到 VITE_SHOWCASE_ENABLED,再回退到 trueMain启用原生 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 与 profileapp/stores/auth-store.tsapp/lib/supabase/*Supabase session 通过 secure-session adapter 持久化,底层由 main-process safeStorage 支持。
权益状态app/stores/subscription-store.ts仅在 billing 启用时读取 subscriptions 表;不会把未知网络状态当作已付费。
服务端数据app/services/*app/lib/query/client.tsService functions 调 Supabase 或 Edge Functions;TanStack Query 负责 UI cache。
UI 偏好app/utils/theme-settings.ts、settings store主题、accent、语言、缩放、代理与更新偏好通过 settings API 流动。

产品数据的替换点应放在 services。组件不应在可以由 service module 承担契约时嵌入 SQL 形状的 Supabase 调用。

启动流程

  1. lib/main/main.ts 启用 Electron sandbox,初始化日志和可选错误上报,并创建 settings store。
  2. 应用注册 soar-electron:// 协议处理器。开发模式传入 Electron binary 和项目路径;打包后注册可执行文件。
  3. initializeApplication() 连接 app services:i18n、secure storage、window state、app intents、updater、tray、notifications、shortcuts、menu、resource protocol、permissions 与 Conveyor handlers。
  4. createPrimaryWindow() 创建沙盒 BrowserWindow,恢复尺寸位置,应用 zoom,阻止危险导航,并加载 dev server 或打包后的 renderer。
  5. app/renderer.tsx 校验 Supabase env,通过 Conveyor bootstrap i18n,挂载 React,并安装 renderer 错误日志。
  6. app/app.tsx 加载 theme/accent 偏好,初始化 auth 和 subscription stores,在配置时跟踪 route analytics,并处理 app intents。
  7. OnboardingGate 读取持久化设置,并在完成前显示首次运行 onboarding。

deep links 与 second-instance launches 会被规范化为类型化 app intents。route allow-list 位于 lib/conveyor/schemas/event-schema.ts,未知 deep-link route 会在 renderer 看到之前被拒绝。

放在哪里

任务放置位置
新增 React route、页面、表单或产品 workflowapp/routesapp/componentsapp/servicesapp/lib/query
读写本地文件、设置、系统 keychain、托盘、菜单、快捷键或通知lib/main 中的 Conveyor handler 后面
向 React 暴露新的 main-process 能力lib/conveyor/schemaslib/conveyor/apilib/conveyor/handlers,然后在 lib/main/main.ts 注册
共享品牌常量、feature flag 或 price-plan mappingshared/
新增服务端计费行为supabase/functions 与 Supabase SQL/RLS

相关页面

On this page