Skip to main content

渲染进程设计

渲染进程负责所有 UI 渲染和用户交互,使用 React 18 + TypeScript 构建。入口文件为 packages/renderer/src/app/App.tsx

Context Provider 层级

App 组件定义了严格的 Provider 嵌套顺序。外层 Provider 可被内层 Provider 和组件访问:

graph TB
LP[LocaleProvider — i18n 国际化]
TP[ThemeProvider — 主题/壁纸]
CDP[ConfirmDialogProvider — 全局确认弹窗]
AP[AuthProvider — 认证状态]
SDP[SettingsDataProvider — 设置数据]
EP[ElfiProvider — Elfi 助手]
WSP[WebSearchProvider — 搜索]
ChatDP[ChatDataProvider — 聊天数据缓存]
CBP[ChatBackendProvider — WebSocket 后端]
UCP[UnifiedChatProvider — 统一聊天 API]
HPP[HtmlPreviewProvider — HTML 预览]
DPP[DevPreviewProvider — 开发预览]
PR[ProtectedRoute — 路由守卫]
HR[HashRouter — 前端路由]
CTP[ChatTabsProvider — 多标签管理]
AR[AppRoutes — 路由定义]
AC[AppContent — 主内容]

LP --> TP --> CDP --> AP --> SDP --> EP --> WSP --> ChatDP --> CBP --> UCP --> HPP --> DPP --> PR --> HR --> CTP --> AR --> AC
{/* App.tsx 中的实际嵌套结构 */}
function App() {
return (
<LocaleProvider>
<ThemeProvider>
<ConfirmDialogProvider>
<AuthProvider>
<SettingsDataProvider>
<ElfiProvider>
<WebSearchProvider>
<ChatDataProvider>
<ChatBackendProvider>
<UnifiedChatProvider>
<HtmlPreviewProvider>
<DevPreviewProvider>
<ProtectedRoute>
<HashRouter>
<ChatTabsProvider>
<AppRoutes>
<AppContent />
</AppRoutes>
</ChatTabsProvider>
</HashRouter>
</ProtectedRoute>
</DevPreviewProvider>
</HtmlPreviewProvider>
</UnifiedChatProvider>
</ChatBackendProvider>
</ChatDataProvider>
</WebSearchProvider>
</ElfiProvider>
</SettingsDataProvider>
</AuthProvider>
</ConfirmDialogProvider>
</ThemeProvider>
</LocaleProvider>
);
}

Zustand Store

高频更新的聊天状态使用 Zustand 管理,避免 Context 引起的不必要重渲染。

chatStore

核心聊天状态存储,使用 subscribeWithSelector 中间件实现精确订阅:

{/* 简化的 chatStore 状态接口 */}
interface ChatState {
// 会话
sessions: Session[];
sessionsLoading: boolean;
sessionsError: Error | null;

// 助手
assistants: ChatAssistant[];
assistantsLoading: boolean;

// 提供商
providers: LLMProvider[];
providersLoading: boolean;

// 消息缓存 (按 sessionId 索引)
messageCache: Map<string, Message[]>;

// 流式状态
streamingState: StreamingState;

// 分支信息
branchInfo: Map<string, BranchInfo>;

// Actions
fetchSessions(): Promise<void>;
fetchAssistants(): Promise<void>;
fetchProviders(): Promise<void>;
loadMessages(sessionId: string): Promise<void>;
setStreamingState(state: Partial<StreamingState>): void;
switchBranch(messageId: string, index: number): void;
}
{/* 使用 selector 精确订阅,避免无关重渲染 */}
const sessions = useChatStore(state => state.sessions);
const isStreaming = useChatStore(state => state.streamingState.isStreaming);
Store文件职责
chatStoreshared/state/chatStore.ts会话、消息、流式状态、分支
settingsStoreshared/state/settingsStore.ts设置状态
useChatStoreSyncshared/state/useChatStoreSync.tsChatDataContext → chatStore 同步

React Context 详解

23+ 个 Context,每个承担独立职责:

Context文件职责核心状态/方法
LocaleContextshared/state/LocaleContext.tsxi18n 国际化 (en/zh/ja)useTranslation(), setLocale()
themeStoreshared/state/themeStore.ts(宿主 app/ThemeHost.tsx主题模式、壁纸、自定义 CSSmode, resolvedMode, userTheme, customCss
ConfirmDialogHostshared/state/ConfirmDialogHost.tsx全局确认弹窗confirm(options)
authStoreshared/state/authStore.ts认证状态user, isAuthenticated, login(), logout()
SettingsDataHostapp/SettingsDataHost.tsx设置数据读写settings, updateSetting()
ElfiContextfeatures/elfi/state/ElfiContext.tsxElfi 智能助手isOpen, messages, sendMessage()
webSearchStoreshared/state/webSearchStore.ts(宿主 app/WebSearchHost.tsx网络搜索search(), results
chatStoreshared/state/chatStore.ts聊天数据缓存 + 统一聊天 API(原 ChatDataContext / UnifiedChatContext 已迁入此处)sessions, messages, sendMessage(), regenerate(), editMessage()
htmlPreviewStoreshared/state/htmlPreviewStore.ts(宿主 app/HtmlPreviewHost.tsxHTML 内容预览showPreview(), previewContent
devPreviewStoreshared/state/devPreviewStore.ts(宿主 app/DevPreviewHost.tsx开发模式预览isDevMode, devData
ChatTabsContextfeatures/chat/state/ChatTabsContext.tsx多标签聊天管理tabs, activeTabId, createTab(), closeTab()
AgentContextfeatures/agents/state/AgentContext.tsxAgent 状态agents, selectedAgent
subagentStoreshared/state/subagentStore.ts(宿主 shared/state/SubagentHost.tsx子智能体状态subagents, status
MessageSelectionContextfeatures/chat/state/MessageSelectionContext.tsx消息多选selectedIds, toggleSelect()
sessionOrganizerStoreshared/state/sessionOrganizerStore.ts(宿主 shared/state/sessionOrganizerStore/SessionOrganizerHost.tsx会话整理/分类folders, moveSession()
worksStoreshared/state/worksStore.ts作品管理works, createWork()
musicWorksStoreshared/state/musicWorksStore.ts音乐作品tracks, playTrack()
musicTemplateStoreshared/state/musicTemplateStore.ts音乐模板templates
VideoWorksContextfeatures/media/state/VideoWorksContext.tsx视频作品videos
videoTemplateStoreshared/state/videoTemplateStore.ts视频模板templates
TemplateContextfeatures/marketplace/state/TemplateContext.tsx图片模板templates
useWorldInfoHighlightshared/hooks/characters/useWorldInfoHighlight.tsWI 关键词高亮highlightedKeywords

Custom Hooks

60+ 个自定义 Hook,按功能领域组织:

聊天相关

Hook文件用途
useAppStateshared/hooks/useAppState.ts集中管理视图标志、活动标签、用户偏好
useRouteSyncshared/hooks/useRouteSync.tsURL 路径到视图状态同步
useSessionProtectionfeatures/chat/hooks/useSessionProtection.ts活动会话保护 (防止刷新清除消息)
useDraftfeatures/chat/hooks/useDraft.ts输入框草稿保存/恢复
useAutoUpdateshared/hooks/useAutoUpdate.ts应用自动更新
useAudioRecorderfeatures/media/hooks/useAudioRecorder.ts语音录制

功能 Hook 目录

目录用途代表 Hook
features/chat/hooks/聊天操作useMessageStream, useBranchNavigation
features/marketplace/hooks/channel/渠道插件useChannelPlugins
shared/hooks/characters/character/角色卡useCharacterCards
shared/hooks/characters/worldinfo/世界信息useWorldInfo
shared/hooks/characters/世界信息高亮 / 标签useWorldInfoHighlight, useTagsData
features/characters/hooks/sprites/表情立绘useSprites
features/settings/components/tabs/tools-tab/hooks/MCP 服务器useMcpManagement
features/kb/hooks/笔记系统useNotesData
features/todo/hooks/待办事项useTodoData
features/tasks/hooks/任务管理useTasksData
features/cron/hooks/定时任务useCronJobs
features/marketplace/hooks/skills/Skill 管理useSkillHub

组件架构

布局结构

graph TB
Root["div.fixed.inset-0.flex.bg-background"]
WS[WorkspaceShell]
WR[WorkspaceRail — 左侧导航栏]
TB[TitleBar — 标签栏 + 窗口控制]
MC[Main Content — 路由内容区]

Root --> WS
WS --> WR
WS --> TB
WS --> MC

MC --> ChatPage
MC --> AgentPage
MC --> SettingsPage
MC --> RoleplayPage
MC --> NotesPage
MC --> CoworkPage
  • WorkspaceRail: 左侧固定导航栏,包含首页、Agent、设置等入口
  • WorkspaceShell: 主布局容器,管理 Rail + 标签栏 + 内容区
  • TitleBar: 多标签栏 + 窗口控制按钮(最大化/最小化/关闭)
  • Main Content: 根据路由动态渲染对应页面组件

工作区扩展(Workspace Registry)

Chat / Agent 页面中间的「工作区面板」(文件树右侧的 editor / git diff / HTML preview / canvas / design studio 等区域)通过 WorkspaceDefinition 注册表扩展。WorkspaceArea.tsx 作为 host shell 只做 layout + 注册表 dispatch — 包含任何 activeView === 'X' 业务分支。

graph TB
WA["WorkspaceArea<br/>(layout + dispatch)"]
Reg["registry.ts<br/>WORKSPACE_REGISTRY[]"]
Slot["WorkspaceToolbarProvider<br/>(slot context)"]
Aff["host-affordances<br/>(cross-view coordination)"]
Defs["definitions/"]

WA -->|findActiveWorkspace| Reg
WA -->|wraps| Slot
WA -->|consumes| Aff
Reg -->|imports| Defs

Defs --> EW[EditorWorkspace]
Defs --> GW[GitWorkspace]
Defs --> HW[HtmlPreviewWorkspace]
Defs --> AW[A2UIWorkspace]
Defs --> DW[DevPreviewWorkspace]
Defs --> DS[DesignStudioWorkspace]
Defs --> CW[CanvasWorkspace]

每个 WorkspaceDefinition 自治管理:

  • 自己的 view 标识符 + isAvailable(ctx) 谓词
  • 自己的 view-mode 状态(split/code/preview 等内部 useState — 不外溢到 host)
  • 通过 useWorkspaceToolbar(config) 把 toolbar 配置发布到 slot;host 的 <WorkspaceToolbar> 通过 useWorkspaceToolbarConfig() 读取
  • 可选 onClose(ctx, cb) 钩子(关闭按钮触发,run outside React tree,所以 close-fn 通道走 WorkspaceCallbacks

加新 workspace 类型 = 改 2 个文件:在 registry.ts 数组里加一项 + 创建 definitions/<Name>Workspace.tsxWorkspaceArea.tsx 不需要改。详细配方见 packages/renderer/CLAUDE.md 「🧩 添加新的 Workspace 类型」节,契约 spec 见 openspec/specs/workspace-registry/spec.md

跨 view 协调(如 editor 里的「Preview」按钮跳到 htmlPreview view、HTML preview 最大化时整个 workspace pane 隐藏)集中在 host-affordances.ts —— 这是唯一允许出现 activeView === 'X' 判断的位置。

文件职责
features/chat/components/content/WorkspaceArea.tsxHost shell(layout + slot reader + 注册表 dispatch,无业务分支)
features/chat/components/content/workspaces/types.tsWorkspaceDefinition / WorkspaceHostContext / WorkspaceCallbacks 契约
features/chat/components/content/workspaces/registry.tsWORKSPACE_REGISTRY 单一注册点 + findActiveWorkspace 查询
features/chat/components/content/workspaces/host-affordances.ts跨 view 协调(cross-view toggle + 最大化隐藏)
features/chat/components/content/workspaces/workspace-toolbar-slot{,-internals,-hooks}.{tsx,ts}Toolbar slot 三件套(Provider / contexts / hooks)
features/chat/components/content/workspaces/definitions/<Name>Workspace.tsx7 个 workspace definition(editor / git / htmlPreview / a2ui / devPreview / designStudio / canvas)
features/chat/components/content/workspaces/inline-file-viewers.tsxInlineMarkdownViewer + InlineBinaryViewer(image/audio/video/pdf + "cannot be previewed" fallback)
features/chat/components/content/workspaces/inline-file-viewers-types.tsgetBinaryFileType / isMarkdownFile / isNonTextFile 文件类型检测
features/chat/components/content/unified-page/hooks/useWorkspaceState.ts工作区状态 hook(handleFileSelect 内做 .htmlopenHtmlPreview() 路由 + isNonTextFile 二进制路由)

路由系统

使用 HashRouter(Electron 不支持 BrowserRouter)配合 useRouteSync Hook 实现 URL 到视图状态的同步:

{/* 路由到视图状态同步 */}
function useRouteSync(pathname: string, state: AppState) {
useEffect(() => {
if (pathname.startsWith('/chat')) {
state.setIsChatView(true);
state.setIsHomeView(false);
} else if (pathname.startsWith('/agents')) {
state.setIsAgentView(true);
} else if (pathname.startsWith('/settings')) {
state.setIsSettingsView(true);
}
}, [pathname]);
}

i18n 国际化

支持 3 种语言,使用 useTranslation() Hook:

语言目录文件数
Englishlocales/en/15+ JSON 文件
中文locales/zh/15+ JSON 文件
日本語locales/ja/15+ JSON 文件

翻译文件按功能域拆分:common.json, chat.json, settings.json, characters.json, elfi.json 等。

AppState Hook

useAppState 集中管理全局 UI 状态:

{/* 简化的 AppState 接口 */}
interface AppState {
// 视图标志
isHomeView: boolean;
isChatView: boolean;
isAgentView: boolean;
isSettingsView: boolean;

// 活动会话
selectedSession: string | null;
activeSessions: Set<string>;
processingSessions: Set<string>;

// 标签
activeTab: string;
settingsInitialTab: string;

// 用户偏好
autoExpandTools: boolean;
showRawParameters: boolean;
showThinking: boolean;
autoScrollToBottom: boolean;
sendByCtrlEnter: boolean;

// 模态框
showVersionModal: boolean;
}

构建配置

配置项
构建工具Vite 7.0
样式Tailwind CSS 3.4 + CSS 变量 (语义化 Token)
代码分割路由级 lazy loading(lazy/ 目录,按用途分 6 文件 + 1 barrel)
Tree Shaking具名导入
主 bundle 上限500 KB

相关文件

文件说明
packages/renderer/src/app/App.tsx应用入口,Provider 层级和布局
packages/renderer/src/shared/state/chatStore.tsZustand 聊天状态 Store
packages/renderer/src/shared/state/settingsStore.tsZustand 设置状态 Store
packages/renderer/src/shared/state/chatStore.ts统一聊天 API(原 UnifiedChatContext 已迁入 chatStore)
packages/renderer/src/shared/state/themeStore.ts主题 Store(原 ThemeContext)
packages/renderer/src/shared/hooks/useAppState.ts集中 UI 状态管理
packages/renderer/src/shared/hooks/useRouteSync.ts路由同步
packages/renderer/src/app/layout/WorkspaceShell.tsx主布局容器
packages/renderer/src/app/layout/WorkspaceRail.tsx左侧导航栏
packages/renderer/src/app/title-bar/标签栏组件
packages/renderer/src/app/lazy/懒加载组件目录(pages.tsx / workspaces.tsx / inline.tsx / shell.tsx / skeletons.tsx / with-suspense.tsx,barrel 在 lazy/index.ts
packages/renderer/src/features/chat/components/content/WorkspaceArea.tsx中间工作区 host shell(layout + 注册表 dispatch,不含业务分支)
packages/renderer/src/features/chat/components/content/workspaces/工作区注册表(WorkspaceDefinition 契约 + 7 个 definition 文件 + toolbar slot + host-affordances)
packages/renderer/src/app/railItems.ts导航栏配置
packages/renderer/src/app/mainContentRouter.tsx主内容路由解析
packages/renderer/CLAUDE.md前端 UI 开发规范