Frontend Architecture & State
Relevant source files
The following files were used as context for generating this wiki page:
Zephyr employs a "Zero Framework" architecture, utilizing native JavaScript without dependencies like React or Vue to achieve high performance and low memory overhead. The frontend manages application logic through three primary pillars: a centralized reactive store, a global event bus, and a structured backend event bridge.
The architecture prioritizes lightweight execution by using system-native WebViews via Tauri v2. It coordinates real-time proxy data, traffic statistics, and UI state through asynchronous IPC (Inter-Process Communication) and reactive DOM bindings.
Sources: README_en.md, FEATURES.md, apps/desktop/src/main.js:1-15
Core Architectural Components
The following diagram illustrates the high-level data flow between the UI, the internal state management systems, and the Rust backend.
The diagram shows how user actions flow through the Event Bus to update the Store or trigger Backend Commands, while backend updates are pushed through a Bridge to notify the UI.
Centralized State Management (appStore)
The appStore object serves as the single source of truth for the frontend application. It manages reactive state properties and persists specific keys to localStorage to maintain user preferences across sessions.
- Reactive Updates: Modules subscribe to specific keys to receive notifications when values change.
- Persistence: A defined list of
transientKeysensures that volatile state (like loading indicators) is not saved, while settings (like theme and language) are persisted. - Store Methods:
get(key): Retrieves current value.set(key, value): Updates the value and triggers subscribers.subscribe(key, callback): Registers a listener for state changes.
Sources: apps/desktop/src/ui/state.js:5-80
Event Bus (Bus)
The Bus module provides a decoupled communication channel for inter-module interaction. It uses a standard emit/listen pattern to handle application-wide lifecycle events.
| Event Constant | Description |
|---|---|
CORE_STARTED | Triggered when the Mihomo core process successfully starts. |
TRAFFIC_UPDATE | Streams real-time upload/download speed data. |
MODE_CHANGED | Indicates a switch between Rule, Global, or Direct proxy modes. |
LANGUAGE_CHANGED | Fired when the user selects a different UI language. |
THEME_CHANGED | Fired when the interface theme color is modified. |
Sources: apps/desktop/src/ui/events.js:5-85
Backend Event Synchronization
The backend-events.js module establishes a bridge between Rust-native events and the JavaScript frontend. It registers Tauri listeners during the bootstrap sequence to capture system-level changes.
The sequence diagram details how backend state changes propagate through the bridge to the event bus, eventually reaching UI components.
Event Registration
During initialization, initBackendEventListeners sets up listeners for:
core-state-changed: Syncs the running status of the Mihomo core.config-changed: Notifies the UI to refresh when the active YAML profile is modified.prism-event: Handles smart proxy selection and rule engine notifications.network-state-changed: Detects Wi-Fi or interface transitions to trigger re-validation.
Sources: apps/desktop/src/modules/backend-events.js:10-90, apps/desktop/src/main.js:100-140
Initialization & Reactive Bindings
The main.js file orchestrates the bootstrap sequence, ensuring that state is synchronized before the UI becomes interactive.
Reactive DOM Binding
The bind function in main.js connects appStore properties directly to DOM elements (typically checkboxes or inputs).
- The function attaches a change listener to the DOM element.
- When the element changes (e.g., a toggle is clicked), it updates the
appStore. - The
appStorethen notifies all other subscribers, keeping the UI and internal logic in sync.
Sources: apps/desktop/src/main.js:150-185
Bootstrap Sequence
- Backend Listeners: Registers Tauri event listeners with a timeout.
- State Cleanup: Resets transient locks in
localStorage. - Core Start: Invokes
start_corevia Rust IPC. - Reactive Bindings: Links
isSysProxyEnabledandisTunEnabledto their respective UI toggles. - WebSocket Connection: Establishes a traffic stream for real-time monitoring.
Sources: apps/desktop/src/main.js:250-450
Summary
Zephyr's frontend architecture is defined by its reactive, framework-less approach. By combining a centralized appStore for state and a Bus for events, the project maintains strict separation of concerns while ensuring high-performance communication with the Rust backend.
Sources: apps/desktop/src/ui/state.js, apps/desktop/src/ui/events.js, apps/desktop/src/main.js