mirror of
https://github.com/rio-labs/rio.git
synced 2026-04-28 06:59:45 -05:00
7.6 KiB
7.6 KiB
Rio Framework - Developer Guide for Contributors
Overview
Rio is a Python-first web framework with a hybrid architecture: Python backend for component logic/state management + TypeScript frontend for DOM rendering. This guide is for contributors developing the Rio framework itself.
Architecture for Framework Contributors
Dual Implementation Pattern
- Python side: Component definitions, logic, server communication (
/rio/components/) - TypeScript side: DOM rendering, event handling, client interactions (
/frontend/code/components/) - Communication: RPC calls and data models via WebSocket/HTTP
- Build process: TypeScript compiles to
/rio/frontend files/, included in Python wheel
Component Implementation Hierarchy
Component (Abstract Base, ComponentMeta)
├── FundamentalComponent (Maps to TypeScript/HTML)
│ ├── Button → _ButtonInternal (TypeScript)
│ ├── ListView → ListView (TypeScript)
│ └── Other built-in components
└── User Components (High-level, composed via build())
Key Internal Systems
- ComponentMeta: Metaclass transforming classes into observable dataclasses
- Observable Properties:
ComponentPropertywith dependency tracking - State Synchronization: Python ↔ TypeScript via
_custom_serialize_()and_on_message_() - Reconciliation: Component tree diffing and reuse via
_weak_builder_andkey_to_component
Development Environment Setup
Initial Setup (Required Order)
# 1. Install Python dependencies
uv sync --all-extras
# 2. Install frontend dependencies
npm install
# 3. Build frontend (REQUIRED before first use)
uv run scripts/build.py
# 4. Setup pre-commit hooks
python -m pre_commit install
Frontend Build System
# Development build (default)
uv run scripts/build.py
# Production build (for releases)
uv run scripts/build.py --release
When to rebuild frontend:
- After any TypeScript/SCSS changes in
/frontend/ - Before testing (some tests require built assets)
- Before releases (production build required)
Project Structure
/rio/components/- Python component implementations/frontend/code/components/- TypeScript component implementations/frontend/css/components/- Component-specific SCSS files/rio/frontend files/- Compiled frontend assets (generated)/scripts/- Build and development tools
Component Development Patterns
Creating New FundamentalComponents
# Python side (rio/components/my_component.py)
class MyComponent(FundamentalComponent):
text: str = ""
def build_javascript_source(self) -> str:
return JAVASCRIPT_SOURCE_TEMPLATE % {
'js_wrapper_class_name': 'MyComponentWrapper',
'js_user_class_name': 'MyComponent',
'cls_unique_id': self._unique_id_,
}
def _custom_serialize_(self) -> JsonDoc:
return {'text': self.text}
async def _on_message_(self, message: JsonDoc) -> None:
# Handle frontend messages
pass
// TypeScript side (frontend/code/components/myComponent.ts)
class MyComponent extends ComponentBase {
createElement(): HTMLElement {
return document.createElement('div');
}
updateElement(deltaState: any): void {
if (deltaState.text !== undefined) {
this.element.textContent = deltaState.text;
}
}
}
Component Lifecycle Management
# Component instantiation (ComponentMeta.__call__)
1. Session injection: component._session_ = global_state.currently_building_session
2. ID assignment: component._id_ = session._next_free_component_id
3. Registration: session._newly_created_components.add(component)
4. Property tracking: component._properties_set_by_creator_
5. Key registration: global_state.key_to_component[key] = component
Observable Property System
# Properties automatically track access and changes
@dataclasses.dataclass
class MyComponent(Component):
count: int = 0 # Becomes ComponentProperty
def build(self) -> Component:
# Reading self.count registers dependency
# Changing self.count triggers rebuild
return Text(f"Count: {self.count}")
Testing Framework Contributors
Test Organization
# Python backend tests
uv run pytest tests/
# Frontend integration tests (requires browser)
uv run pytest tests/test_frontend/
# Coverage reporting
uv run scripts/code_coverage.py
Test Categories
- Component tests:
tests/test_components.py- Component behavior - Observable tests:
tests/test_observables.py- State management - Frontend tests:
tests/test_frontend/- Browser-based testing - CLI tests:
tests/test_cli/- Command-line interface
Icon System Development
# Build icon sets from raw SVGs
uv run scripts/build_icon_set.py
# Icon locations:
# - /raw_icons/ - Source SVG files
# - /thirdparty/bootstrap/icons/ - Bootstrap icons
# - Output: .tar.xz archives → /rio/assets/icon_sets/
Code Quality and Conventions
Code Standards
# Python linting and formatting
python -m ruff check .
python -m ruff format .
# TypeScript formatting
npx prettier --write frontend/
# Pre-commit hooks (automatic)
pre-commit run --all-files
Import Patterns
from __future__ import annotations # Always first
import dataclasses
import typing as t
import rio
from .. import global_state, inspection # Relative imports
Type Annotations
- Heavy use of
typingmodule witht.aliases - All public APIs fully type-annotated
- Use
@t.finalfor non-subclassable classes typing_extensionsfor newer features
Common Development Tasks
Adding New Built-in Components
- Create Python component in
/rio/components/ - Create TypeScript component in
/frontend/code/components/ - Add SCSS styles in
/frontend/css/components/ - Update
/rio/components/__init__.pyexports - Add tests in
/tests/test_components.py - Build frontend:
uv run scripts/build.py
Debugging Component Issues
- Use
rio.global_statefor session inspection - Check
session._changed_attributesfor state changes - Frontend: Browser DevTools + component tree visualization
- Backend: Python debugger with component lifecycle hooks
Integration Points for Contributors
Python-TypeScript Bridge
- State serialization:
_custom_serialize_()→ TypeScript - Event handling: TypeScript →
_on_message_()→ Python - DOM updates: Delta state application in TypeScript
Session Management
- Session state in
rio/session.py - Component registration and lifecycle
- WebSocket communication via
rio/transports/
Common Pitfalls for Contributors
Frontend Development
- Always rebuild after TypeScript changes:
uv run scripts/build.py - Component registration: Each FundamentalComponent needs unique
_unique_id_ - State synchronization: Ensure
_custom_serialize_()matches TypeScript expectations - CSS organization: Component styles go in
/frontend/css/components/
Python Development
- Observable properties: Don't bypass the property system - use attribute assignment
- Component lifecycle: Understand
ComponentMetainstantiation process - Session management: Components must be created within session context
- Import organization: Use relative imports within Rio codebase
Testing
- Frontend tests: Require built assets and browser setup
- Component tests: Focus on state changes and user interactions
- Coverage: Use
scripts/code_coverage.pyfor comprehensive reporting - Mock dependencies: Isolate components from external systems