Перейти к основному содержимому

Архитектура процесса рендеринга

Процесс рендеринга отвечает за весь UI и взаимодействие с пользователем; построен на React 18 + TypeScript. Точка входа — packages/renderer/src/app/App.tsx.

Иерархия провайдеров (Context Provider)

Компонент App задаёт строгий порядок вложенности провайдеров. Внешние провайдеры доступны вложенным провайдерам и компонентам:

graph TB
LP[LocaleProvider — i18n internationalization]
TP[ThemeProvider — theme/wallpaper]
CDP[ConfirmDialogProvider — global confirm dialog]
AP[AuthProvider — auth state]
SDP[SettingsDataProvider — settings data]
EP[ElfiProvider — Elfi assistant]
WSP[WebSearchProvider — search]
ChatDP[ChatDataProvider — chat data cache]
CBP[ChatBackendProvider — WebSocket backend]
UCP[UnifiedChatProvider — unified chat API]
HPP[HtmlPreviewProvider — HTML preview]
DPP[DevPreviewProvider — dev preview]
PR[ProtectedRoute — route guard]
HR[HashRouter — frontend routing]
CTP[ChatTabsProvider — multi-tab management]
AR[AppRoutes — route definition]
AC[AppContent — main content]

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

Основное хранилище состояния чата; использует middleware 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>;

// Действия
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;
}
// Используйте селектор для точечной подписки, чтобы избежать лишних ре-рендеров
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.tsСинхронизация ChatDataContext → chatStore

Детали React Context

23+ контекстов, каждый с независимой зоной ответственности:

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.tsxУмный ассистент ElfiisOpen, 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.tsx)Предварительный просмотр HTML-контентаshowPreview(), previewContent
devPreviewStoreshared/state/devPreviewStore.ts (хост app/DevPreviewHost.tsx)Предварительный просмотр в dev-режимеisDevMode, devData
ChatTabsContextfeatures/chat/state/ChatTabsContext.tsxУправление вкладками чатаtabs, activeTabId, createTab(), closeTab()
AgentContextfeatures/agents/state/AgentContext.tsxСостояние агентов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.tsПодсветка ключевых слов WIhighlightedKeywords

Пользовательские хуки

60+ пользовательских хуков, организованных по функциональным доменам:

Связанные с чатом

ХукФайлНазначение
useAppStateshared/hooks/useAppState.tsЦентрализованное управление флагами представлений, активной вкладкой, пользовательскими настройками
useRouteSyncshared/hooks/useRouteSync.tsСинхронизация URL-пути с состоянием представления
useSessionProtectionfeatures/chat/hooks/useSessionProtection.tsЗащита активной сессии (предотвращает сброс при обновлении)
useDraftfeatures/chat/hooks/useDraft.tsСохранение/восстановление черновика ввода
useAutoUpdateshared/hooks/useAutoUpdate.tsАвтоматическое обновление приложения
useAudioRecorderfeatures/media/hooks/useAudioRecorder.tsЗапись аудио

Директории хуков по функциям

ДиректорияНазначениеПримеры хуков
features/chat/hooks/Операции с чатомuseMessageStream, useBranchNavigation
features/marketplace/hooks/channel/Плагины каналовuseChannelPlugins
shared/hooks/characters/character/Карточки персонажейuseCharacterCards
shared/hooks/characters/worldinfo/World infouseWorldInfo
shared/hooks/characters/Подсветка WI / теги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/Управление навыкамиuseSkillHub

Архитектура компонентов

Структура макета

graph TB
Root["div.fixed.inset-0.flex.bg-background"]
WS[WorkspaceShell]
WR[WorkspaceRail — left navigation rail]
TB[TitleBar — tab bar + window control]
MC[Main Content — routed content area]

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

MC --> ChatPage
MC --> AgentPage
MC --> SettingsPage
MC --> RoleplayPage
MC --> NotesPage
MC --> CoworkPage
  • WorkspaceRail: Левая фиксированная навигационная панель с точками входа: Главная, Агенты, Настройки
  • WorkspaceShell: Основной контейнер макета; управляет Rail, панелью вкладок и областью контента
  • TitleBar: Панель с вкладками + кнопки управления окном (развернуть/свернуть/закрыть)
  • Main Content: Динамически отображает компоненты страниц в соответствии с маршрутом

Расширение рабочего пространства (Workspace Registry)

«Панель рабочего пространства» между страницами Chat/Agent (редактор / git diff / HTML-предпросмотр / canvas / область design studio справа от дерева файлов) расширяется через реестр WorkspaceDefinition. WorkspaceArea.tsx как хост-оболочка выполняет только макет + диспетчеризацию реестра — без каких-либо бизнес-ветвлений вида 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)
  • Собственным состоянием режима представления (split/code/preview и др. — внутренний useState, не вытекает в хост)
  • Публикацией конфигурации тулбара через useWorkspaceToolbar(config) в слот; <WorkspaceToolbar> хоста читает его через useWorkspaceToolbarConfig()
  • Необязательным хуком onClose(ctx, cb) (срабатывает по кнопке закрытия вне дерева React; канал функции закрытия использует WorkspaceCallbacks)

Добавление нового типа рабочего пространства = изменение 2 файлов: добавить запись в массив registry.ts + создать definitions/<Name>Workspace.tsx. Файл WorkspaceArea.tsx изменять не нужно. Подробный рецепт — в разделе «🧩 Add New Workspace Type» файла packages/renderer/CLAUDE.md; спецификация контракта — в openspec/specs/workspace-registry/spec.md.

Межпредставленческая координация (например, кнопка «Preview» в редакторе, переключающая на htmlPreview, или скрытие всей панели рабочего пространства при максимизации HTML-предпросмотра) централизована в host-affordances.ts — единственное место, где допускается условие activeView === 'X'.

ФайлОтветственность
features/chat/components/content/WorkspaceArea.tsxХост-оболочка (макет + чтение слота + диспетчеризация реестра, без бизнес-ветвлений)
features/chat/components/content/workspaces/types.tsКонтракт WorkspaceDefinition / WorkspaceHostContext / WorkspaceCallbacks
features/chat/components/content/workspaces/registry.tsЕдиная точка регистрации WORKSPACE_REGISTRY + запрос findActiveWorkspace
features/chat/components/content/workspaces/host-affordances.tsМежпредставленческая координация (переключение и скрытие при максимизации)
features/chat/components/content/workspaces/workspace-toolbar-slot{,-internals,-hooks}.{tsx,ts}Трио слота тулбара (Provider / contexts / hooks)
features/chat/components/content/workspaces/definitions/<Name>Workspace.tsx7 определений рабочих пространств (editor / git / htmlPreview / a2ui / devPreview / designStudio / canvas)
features/chat/components/content/workspaces/inline-file-viewers.tsxInlineMarkdownViewer + InlineBinaryViewer (изображение/аудио/видео/pdf + заглушка «не удаётся просмотреть»)
features/chat/components/content/workspaces/inline-file-viewers-types.tsОпределение типов файлов: getBinaryFileType / isMarkdownFile / isNonTextFile
features/chat/components/content/unified-page/hooks/useWorkspaceState.tsХук состояния рабочего пространства (маршрутизация .htmlopenHtmlPreview() + маршрутизация бинарных файлов в handleFileSelect)

Система маршрутизации

Используется HashRouter (Electron не поддерживает BrowserRouter) с хуком useRouteSync для синхронизации 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():

ЯзыкДиректорияФайлы
Английскийlocales/en/15+ JSON-файлов
Китайский (упрощённый)locales/zh/15+ JSON-файлов
Японскийlocales/ja/15+ JSON-файлов

Файлы переводов разделены по функциональным доменам: common.json, chat.json, settings.json, characters.json, elfi.json и др.

Хук AppState

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-переменные (семантические токены)
Разделение кодаЛенивая загрузка на уровне маршрутов (директория lazy/, 6 файлов + 1 barrel по назначению)
Tree shakingИменованные импорты
Ограничение главного бандла500 KB

Связанные файлы

ФайлОписание
packages/renderer/src/app/App.tsxТочка входа приложения, иерархия провайдеров и макет
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.tsStore темы (бывший 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Центральная хост-оболочка рабочего пространства (макет + диспетчеризация реестра, без бизнес-ветвлений)
packages/renderer/src/features/chat/components/content/workspaces/Реестр рабочих пространств (контракт WorkspaceDefinition + 7 файлов определений + слот тулбара + host-affordances)
packages/renderer/src/app/railItems.tsКонфигурация навигационной панели
packages/renderer/src/app/mainContentRouter.tsxРазбор маршрутизатора основного контента
packages/renderer/CLAUDE.mdСтандарты разработки UI фронтенда