Developer Guide
September 7, 2025 · View on GitHub
This guide provides technical documentation for developers working on the Zubridge project.
Repository Structure
Package Organization
The Zubridge monorepo is organized using Turborepo with the following packages:
packages/
├── electron/ # Main Electron package (`@zubridge/electron`)
├── types/ # Shared TypeScript types (`@zubridge/types`)
├── core/ # Core utilities and debug system (`@zubridge/core`)
├── middleware/ # Rust-based middleware (`@zubridge/middleware` - optional, not yet released)
├── ui/ # Shared UI components for test applications
└── apps-shared/ # Shared logic and utilities for example apps
└── tauri/ # Main Tauri package (`@zubridge/tauri`)
apps/
├── electron/
│ ├── e2e/ # Comprehensive E2E testing app
│ ├── minimal-zustand-basic/ # Minimal Zustand basic example
│ ├── minimal-zustand-handlers/ # Zustand with handlers pattern
│ ├── minimal-zustand-reducers/ # Zustand with reducers pattern
│ ├── minimal-redux/ # Redux integration example
│ └── minimal-custom/ # Custom state manager example
└── tauri/
└── e2e/ # Tauri E2E testing app
└── e2e-tauri/ # End-to-end testing with Tauri
└── e2e-tauri-v1/ # End-to-end testing with Tauri V1
Development Workflow
The project uses:
- Turborepo for monorepo management with remote caching enabled
- Biome for linting and formatting
- Vitest for testing across all packages
- TypeScript for type safety
- Rust for optional high-performance middleware
Shared Packages
apps-shared Package
Contains common logic shared between example applications:
- State management utilities
- Common action creators and reducers
- Testing helpers
- Configuration utilities
ui Package
Provides reusable UI components for example applications:
- Common React components
- Shared styling and theming
- Form components and validators
- Testing utilities for components
Architecture
Core Bridge System
The Zubridge architecture separates concerns between different layers:
┌─────────────────────────────────────────────────────────────┐
│ Renderer Process │
├─────────────────────────────────────────────────────────────┤
│ React Components / UI Framework │
│ └── useDispatch() / useStore() │
│ └── Zubridge Renderer Handlers │
│ └── IPC Communication │
└─────────────────────────────────────────────────────────────┘
│
│ Electron IPC
▼
┌─────────────────────────────────────────────────────────────┐
│ Main Process │
├─────────────────────────────────────────────────────────────┤
│ Bridge Factory (createZustandBridge/createReduxBridge) │
│ ├── IPC Handler (manages communication) │
│ ├── Resource Manager (cleanup & lifecycle) │
│ ├── Subscription Handler (window management) │
│ └── Action Queue (sequencing & thunk coordination) │
│ │ │
│ Thunk Manager ──────────────┼──────────── State Manager │
│ (coordination) │ (Zustand/Redux) │
└─────────────────────────────────────────────────────────────┘
Thunk Manager Architecture
The Thunk Manager system coordinates thunk execution across processes:
Key Components
ThunkManager
- Thunk registration and lifecycle management
- State transitions (pending → executing → completed/failed)
- Thunk hierarchy tracking (parent-child relationships)
- Locking mechanism to ensure only one root thunk executes at a time
- Event emission for thunk state changes
Thunk Class
- Unique ID and optional parent ID
- Current state (pending, executing, completed, failed)
- Source window ID and process information
- Child thunk IDs for hierarchy tracking
- Timestamps for performance monitoring
ActionQueueManager
- Manages queue of actions from all renderer processes
- Consults ThunkManager to determine action processing eligibility
- Ensures actions from same thunk tree are processed sequentially
- Prevents concurrent execution of actions from different thunk trees
MainThunkProcessor
- Executes thunks dispatched from the main process
- Manages thunk execution state and error handling
- Coordinates with ThunkManager for registration and state updates
Thunk Lifecycle
┌─────────────┐ register() ┌─────────────┐
│ Thunk │ ──────────────► │ Registered │
│ Created │ │ (Pending) │
└─────────────┘ └─────────────┘
│ start()
▼
┌─────────────┐ ┌─────────────┐
│ Completed/ │ ◄─────────────── │ Executing │
│ Failed │ complete() │ (Active) │
└─────────────┘ or fail() └─────────────┘
│ │
│ cleanup() │ spawn child
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Lock │ │ Child │
│ Released │ │ Thunks │
└─────────────┘ └─────────────┘
Concurrency Control
The ThunkManager implements a locking mechanism:
- Lock Acquisition: Only one root thunk can execute at a time
- Hierarchical Execution: Child thunks execute within parent's context
- Action Deferral: Non-thunk actions are deferred during thunk execution
- Lock Release: Released when root thunk and all descendants complete
- Queue Processing: Deferred actions are processed after lock release
Event System
ThunkManager extends EventEmitter with these events:
THUNK_REGISTERED: New thunk registered in systemTHUNK_STARTED: Thunk begins executionTHUNK_COMPLETED: Thunk completes successfullyTHUNK_FAILED: Thunk fails with errorROOT_THUNK_CHANGED: New root thunk acquires lockROOT_THUNK_COMPLETED: Root thunk and descendants complete
Action Sequencing Flow
Renderer A Main Process Renderer B
│ │ │
│── dispatch(thunk) ──►│ │
│ │ (lock acquired) │
│ │ │
│ │◄── dispatch(action) ──│
│ │ (deferred) │
│ │ │
│◄─── state update ─── │ │
│ │ │
│── acknowledge ─────► │ │
│ │ (lock released) │
│ │ │
│ │── process deferred ──►│
│ │ │
IPC Communication Flow
Renderer Preload Main Process
│ │ │
│ dispatch('ACTION') ───►│ │
│ │ ipc.invoke() ────────►│
│ │ │ processAction()
│ │ │ └── State Update
│ │ │ └── Notify Windows
│ │◄───── ipc.handle ──── │
│◄─── Promise resolve ── │ │
│ │ │
│ │◄─ 'state-update' ──── │
│ callback(newState) ◄── │ │
│ │ 'state-ack' ────────► │
│ │ │
Development Setup
Prerequisites
- Node.js 18+ with pnpm
- Rust (optional, for Tauri / middleware development)
- Electron development dependencies
Local Development
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Run linting
pnpm lint
# Format code
pnpm format
# Run example applications
pnpm --filter electron-example dev
pnpm --filter minimal-zustand dev
Testing Strategy
The project uses comprehensive testing across multiple levels:
Unit Tests
- Individual component and utility testing
- Mock-based testing for IPC interactions
- State management logic verification
- Error handling and edge case coverage
Integration Tests
- Bridge creation and configuration testing
- Multi-window communication testing
- Thunk execution and coordination testing
- Error propagation testing
End-to-End Tests
- Full application workflow testing
- Cross-process communication validation
- Performance and memory leak testing
- Real Electron environment testing
Performance Monitoring
Key metrics tracked in development:
- Action Processing Time: Time from dispatch to state update
- IPC Latency: Communication overhead between processes
- Memory Usage: Tracking for resource leaks
- Thunk Execution Time: End-to-end thunk performance
- State Serialization Cost: Size and time for state transmission
Contributing Guidelines
Code Style
The project enforces consistent code style through:
- Biome for linting and formatting
- TypeScript strict mode enabled
- ESLint rules for React and Node.js
- Conventional Commits for commit messages
Pull Request Process
- Branch Strategy: Feature branches from
main - Testing: All tests must pass, coverage requirements met
- Documentation: Update relevant documentation
- Review: Code review required before merge
- CI/CD: Automated testing and building on all PRs
Release Process
The project uses semantic versioning with automated releases:
feat:commits trigger minor version bumpsfix:commits trigger patch version bumpsBREAKING CHANGE:triggers major version bumps- All packages are released together for consistency
Architecture Decisions
Why Separate Thunk and Action Processing?
Thunks and actions have different execution patterns:
- Actions: Immediate state updates, synchronous processing
- Thunks: Asynchronous execution, can dispatch multiple actions
- Separation: Allows different optimization strategies for each
Why Deferred Action Processing?
Action deferral during thunk execution provides:
- Consistency: Prevents race conditions in state updates
- Predictability: Ensures deterministic execution order
- Debugging: Easier to reason about state changes
Why Rust Middleware?
Optional Rust middleware provides:
- Performance: 10-100x faster action processing
- Memory Safety: Prevents memory leaks in long-running applications
- Concurrency: Better handling of concurrent operations
- Future-Proofing: Foundation for advanced features
Future Roadmap
Short Term (Next 6 months)
- Enhanced TypeScript integration
- Improved debugging tools
- Performance optimizations
- Additional example applications
Medium Term (6-12 months)
- Rust middleware as default option
- Advanced caching strategies
- Plugin architecture for extensibility
- Cross-platform testing improvements
Long Term (12+ months)
- WebAssembly integration for performance
- Advanced state diffing algorithms
- Distributed state management
- Integration with other Electron frameworks