# Client Hydration Guide

Comprehensive guide to Rustelo's configuration-driven client hydration system.

## Overview

Rustelo's client hydration transforms server-rendered HTML into a fully reactive WebAssembly application. The hydration process is **90% configuration-driven** from your TOML files, with **10% custom extension** capabilities for complex requirements.

## Core Hydration Flow

### 1. Configuration-Driven Hydration (90% Use Case)

Your TOML configuration drives the entire hydration process:

```toml
# site/config/routes/en.toml
[[routes]]
path = "/dashboard"
component = "Dashboard"
title_key = "dashboard-title"
language = "en"
enabled = true
hydration_priority = "high"

[[routes]]
path = "/profile"
component = "Profile"
title_key = "profile-title"
language = "en" 
enabled = true
hydration_priority = "normal"
```

**Generated Hydration Code:**
```rust
// Generated from your TOML configuration
#[wasm_bindgen]
pub fn hydrate() {
    // Read server-rendered page data
    let page_data = extract_server_state();
    let current_path = get_current_path();
    
    // Route resolution from TOML configuration
    match resolve_configured_route(&current_path) {
        Some(route_info) => {
            hydrate_configured_component(&route_info, page_data);
        }
        None => {
            hydrate_not_found_component(&current_path);
        }
    }
    
    // Activate client-side routing for all configured routes
    activate_client_routing();
}
```

### 2. Server-Client State Handoff

The hydration system seamlessly transitions from server state to client state:

```html
<!-- Server-rendered HTML with embedded state -->
<div id="app" data-leptos-hydration="true">
  <script type="application/json" id="__LEPTOS_STATE__">
    {
      "route": "/dashboard",
      "component": "Dashboard", 
      "props": { "user_id": "123" },
      "i18n_data": { "language": "en", "messages": {...} },
      "theme": "light"
    }
  </script>
  
  <!-- Server-rendered component HTML -->
  <div class="dashboard-container">
    <h1>Dashboard</h1>
    <!-- ... more server-rendered content -->
  </div>
</div>
```

```rust
// Client hydration reads and uses server state
#[wasm_bindgen]
pub fn hydrate() {
    let server_state = read_embedded_state();
    
    // Hydrate with exact server state to prevent mismatches
    leptos::mount::hydrate_body(move || {
        view! {
            <AppComponent 
                initial_route=server_state.route
                initial_props=server_state.props
                initial_theme=server_state.theme
            />
        }
    });
}
```

## Hydration Patterns

### Pattern 1: Zero-Config Hydration

Most common pattern - pure configuration-driven:

```rust
use client;

#[wasm_bindgen]
pub fn hydrate() {
    // Reads your TOML routes and hydrates automatically
    client::hydrate();
}
```

**What this provides:**
- ✅ Automatic component hydration for all configured routes
- ✅ State management providers (theme, i18n, auth)
- ✅ Client-side routing activation
- ✅ Error boundary setup
- ✅ Development debugging tools

### Pattern 2: Hydration with Validation

Validate configuration before hydration:

```rust
use client::{hydrate_with_validation, HydrationConfig};

#[wasm_bindgen]
pub fn hydrate() {
    let config = HydrationConfig::from_toml_files()
        .validate_routes()
        .validate_components()
        .validate_i18n_keys();
    
    match config.build() {
        Ok(validated_config) => {
            client::hydrate_with_config(validated_config);
        }
        Err(validation_errors) => {
            console::error!("Hydration validation failed: {:?}", validation_errors);
            client::hydrate_with_fallback();
        }
    }
}
```

### Pattern 3: Custom Hydration Extensions (10% Case)

When you need custom hydration behavior:

```rust
use client::{HydrationBuilder, CustomHydrationHooks};

#[wasm_bindgen]
pub fn hydrate() {
    let hooks = CustomHydrationHooks::builder()
        .with_pre_hydration(|| {
            // Custom initialization before hydration
            setup_analytics_tracking();
            initialize_performance_monitoring();
        })
        .with_post_hydration(|| {
            // Custom setup after hydration
            activate_service_worker();
            setup_keyboard_shortcuts();
        })
        .with_component_hydration(|component_name, element| {
            // Custom per-component hydration logic
            match component_name {
                "Dashboard" => setup_realtime_dashboard(element),
                "Chart" => initialize_chart_interactions(element),
                _ => {} // Use default hydration
            }
        })
        .build();
    
    client::hydrate_with_hooks(hooks);
}
```

## Hydration Lifecycle

### Phase 1: Initialization

```rust
// 1. WebAssembly module loads
wasm_bindgen::start();

// 2. Panic hook setup for debugging
console_error_panic_hook::set_once();

// 3. Read server-embedded configuration
let server_config = read_leptos_state();
let route_config = load_toml_routes();

// 4. Validate server-client consistency
validate_state_consistency(&server_config, &route_config)?;
```

### Phase 2: Component Hydration

```rust
// 5. Resolve current route from URL
let current_path = window().location().pathname();
let route_info = resolve_route(&current_path, &route_config)?;

// 6. Hydrate matching component
match route_info.component {
    RouteComponent::Dashboard => hydrate_dashboard_component(),
    RouteComponent::Profile => hydrate_profile_component(),
    RouteComponent::Settings => hydrate_settings_component(),
    _ => hydrate_not_found_component(),
}

// 7. Activate reactive signals and effects
activate_component_reactivity();
```

### Phase 3: System Activation

```rust
// 8. Setup state providers from configuration
setup_theme_provider(&route_config.theme);
setup_i18n_provider(&route_config.i18n);
setup_auth_provider(&route_config.auth);

// 9. Activate client-side routing
let router = create_configured_router(&route_config.routes);
activate_client_routing(router);

// 10. Setup cross-component communication
setup_event_bus();

// 11. Mark hydration as complete
mark_hydration_complete();
```

## Hydration Debugging

### Development Debug Mode

Enable comprehensive hydration debugging:

```rust
#[cfg(debug_assertions)]
use client::debug::{HydrationDebugger, DebugLevel};

#[wasm_bindgen]
pub fn hydrate() {
    let debugger = HydrationDebugger::new()
        .with_level(DebugLevel::Verbose)
        .with_performance_tracking(true)
        .with_state_validation(true)
        .with_component_tracing(true);
    
    client::hydrate_with_debugger(debugger);
}
```

**Debug Output:**
```
🔍 [HYDRATION] Starting hydration process
📊 [PERFORMANCE] Hydration start time: 1634567890123
🔧 [STATE] Reading server state: {"route": "/dashboard", "theme": "light"}
📋 [CONFIG] Loading TOML routes: found 5 routes
✅ [VALIDATION] Server-client state consistent
🎯 [ROUTING] Resolving route: /dashboard → DashboardComponent
💧 [COMPONENT] Hydrating DashboardComponent
⚡ [SIGNALS] Activating 12 reactive signals
🎨 [THEME] Setting up theme provider: light mode
🌐 [I18N] Loading translations: en locale
🔒 [AUTH] Initializing auth context: unauthenticated
🛣️ [ROUTER] Activating client-side routing for 5 routes
✨ [COMPLETE] Hydration completed in 234ms
```

### Hydration Error Handling

Graceful error handling for hydration issues:

```rust
use client::{HydrationError, HydrationRecovery};

#[wasm_bindgen]
pub fn hydrate() {
    match client::hydrate_with_recovery() {
        Ok(()) => {
            console::log!("✅ Hydration successful");
        }
        Err(HydrationError::StateMismatch { server, client }) => {
            console::warn!("⚠️ State mismatch detected");
            console::debug!("Server state: {:?}", server);
            console::debug!("Client state: {:?}", client);
            
            // Attempt recovery
            client::recover_from_state_mismatch(server, client);
        }
        Err(HydrationError::ComponentNotFound { component }) => {
            console::error!("❌ Component not found: {}", component);
            
            // Fall back to generic component
            client::hydrate_with_fallback_component();
        }
        Err(HydrationError::ConfigurationError { message }) => {
            console::error!("🔧 Configuration error: {}", message);
            
            // Fall back to minimal hydration
            client::hydrate_minimal();
        }
    }
}
```

## Performance Optimization

### Hydration Priority

Configure hydration priority in TOML:

```toml
# High priority - hydrate immediately
[[routes]]
path = "/dashboard"
component = "Dashboard"
hydration_priority = "critical"
preload_data = true

# Normal priority - hydrate after critical
[[routes]]
path = "/profile"
component = "Profile"
hydration_priority = "normal"

# Low priority - hydrate lazily
[[routes]]
path = "/settings"
component = "Settings"
hydration_priority = "lazy"
defer_hydration = true
```

**Generated Hydration Strategy:**
```rust
// Prioritized hydration based on configuration
async fn hydrate_with_priorities() {
    // Phase 1: Critical components (blocking)
    hydrate_critical_components().await;
    
    // Phase 2: Normal components (non-blocking)
    spawn_local(async {
        hydrate_normal_components().await;
    });
    
    // Phase 3: Lazy components (on-demand)
    setup_lazy_hydration_triggers();
}
```

### Bundle Splitting for Hydration

Route-based code splitting:

```toml
# Main bundle
[[routes]]
path = "/"
component = "Home"
bundle = "main"

[[routes]]
path = "/dashboard"
component = "Dashboard" 
bundle = "main"

# Admin bundle (lazy-loaded)
[[routes]]
path = "/admin/*"
component = "AdminSection"
bundle = "admin"
lazy_load = true

# Feature bundles
[[routes]]
path = "/analytics"
component = "Analytics"
bundle = "analytics"
lazy_load = true
```

**Generated Loading Strategy:**
```rust
// Main bundle hydrates immediately
hydrate_main_bundle();

// Lazy bundles load on demand
async fn navigate_to_admin() {
    let admin_module = load_bundle("admin").await?;
    hydrate_bundle_components(admin_module).await?;
}
```

## Advanced Hydration Patterns

### Progressive Hydration

Hydrate components progressively based on viewport:

```toml
[[routes]]
path = "/dashboard"
component = "Dashboard"
hydration_strategy = "progressive"
viewport_priority = true
```

```rust
// Progressive hydration implementation
#[component]
pub fn ProgressivelyHydratedDashboard() -> impl IntoView {
    let (is_in_viewport, set_is_in_viewport) = create_signal(false);
    let dashboard_ref = create_node_ref::<html::Div>();
    
    // Hydrate when component enters viewport
    create_effect(move |_| {
        if let Some(element) = dashboard_ref.get() {
            let intersection_observer = create_intersection_observer(
                move |entries| {
                    for entry in entries {
                        if entry.is_intersecting() {
                            set_is_in_viewport.set(true);
                        }
                    }
                }
            );
            
            intersection_observer.observe(&element);
        }
    });
    
    view! {
        <div node_ref=dashboard_ref>
            {move || {
                if is_in_viewport.get() {
                    view! { <FullDashboardComponent /> }.into_any()
                } else {
                    view! { <DashboardPlaceholder /> }.into_any()
                }
            }}
        </div>
    }
}
```

### Hydration with Service Workers

Offline-capable hydration:

```toml
[service_worker]
enabled = true
cache_hydration_data = true
offline_fallback = true
```

```rust
// Service worker integration for hydration
#[wasm_bindgen]
pub fn hydrate() {
    spawn_local(async {
        // Try to get cached hydration data
        if let Ok(cached_data) = get_cached_hydration_data().await {
            hydrate_with_cached_data(cached_data);
        } else if navigator.on_line() {
            // Online: normal hydration
            client::hydrate();
        } else {
            // Offline: fallback hydration
            client::hydrate_offline_mode();
        }
    });
}
```

## Testing Hydration

### Hydration Tests

Test hydration behavior:

```rust
#[cfg(test)]
mod hydration_tests {
    use super::*;
    use wasm_bindgen_test::*;
    
    wasm_bindgen_test_configure!(run_in_browser);
    
    #[wasm_bindgen_test]
    async fn test_dashboard_hydration() {
        // Setup server-rendered HTML
        let server_html = create_server_rendered_html("/dashboard");
        document().body().unwrap().set_inner_html(&server_html);
        
        // Test hydration
        let result = client::hydrate_route("/dashboard").await;
        assert!(result.is_ok());
        
        // Verify component is interactive
        let dashboard = document()
            .query_selector(".dashboard-container")
            .unwrap()
            .unwrap();
        
        // Test that click events work (hydration successful)
        let button = dashboard
            .query_selector("button")
            .unwrap()
            .unwrap();
        
        button.click();
        
        // Verify reactive state updated
        assert_eq!(get_dashboard_state().active_tab, "metrics");
    }
    
    #[wasm_bindgen_test]
    async fn test_hydration_error_recovery() {
        // Create mismatched server state
        set_server_state("dashboard", serde_json::json!({
            "version": "1.0",
            "data": {"user_id": "123"}
        }));
        
        // Simulate client with different version
        let result = client::hydrate_with_validation().await;
        
        // Should recover gracefully
        assert!(result.is_ok());
        assert_eq!(get_hydration_status(), HydrationStatus::RecoveredFromMismatch);
    }
}
```

### Hydration Performance Tests

Monitor hydration performance:

```rust
#[wasm_bindgen_test]
async fn test_hydration_performance() {
    let start_time = js_sys::Date::now();
    
    client::hydrate().await;
    
    let hydration_time = js_sys::Date::now() - start_time;
    
    // Hydration should complete within performance budget
    assert!(hydration_time < 500.0, "Hydration took {}ms, expected < 500ms", hydration_time);
    
    // Verify all critical components hydrated
    assert!(is_component_hydrated("Navigation"));
    assert!(is_component_hydrated("MainContent"));
    assert!(is_component_hydrated("Footer"));
}
```

## Best Practices

### 1. Configuration-First Approach
- Use TOML configuration for 90% of hydration behavior
- Only add custom hydration code for complex requirements
- Validate configuration at build time

### 2. Performance Optimization
- Use hydration priorities to control loading order
- Implement progressive hydration for large applications
- Monitor hydration performance in production

### 3. Error Handling
- Always include fallback hydration strategies
- Implement graceful degradation for hydration failures
- Log hydration errors for debugging

### 4. Development Experience
- Enable debug mode during development
- Use comprehensive logging for troubleshooting
- Test hydration behavior across different scenarios

### 5. State Consistency
- Ensure server and client render identical HTML
- Validate state consistency during hydration
- Handle state mismatches gracefully

## Common Issues and Solutions

### Issue: Hydration Mismatches

**Symptom:** Console errors about DOM structure differences

**Solution:**
```rust
// Ensure server and client render identical content
#[component]
pub fn ConsistentComponent() -> impl IntoView {
    // Use server-safe default values
    let (client_only_state, set_client_only_state) = create_signal(None);
    
    // Initialize client state after hydration
    create_effect(move |_| {
        if !is_server_rendering() {
            set_client_only_state.set(Some(initialize_client_state()));
        }
    });
    
    view! {
        <div>
            // Always render server-safe content first
            <h1>"Title"</h1>
            
            // Client-only features after hydration
            {move || {
                if let Some(state) = client_only_state.get() {
                    view! { <ClientOnlyFeatures state=state /> }.into_any()
                } else {
                    view! { <div></div> }.into_any()
                }
            }}
        </div>
    }
}
```

### Issue: Slow Hydration

**Symptom:** Long time to interactive

**Solution:**
```toml
# Configure progressive hydration
[hydration]
strategy = "progressive"
critical_components = ["Navigation", "MainContent"]
defer_non_critical = true
viewport_based = true
```

### Issue: Bundle Size

**Symptom:** Large WebAssembly bundle affecting hydration speed

**Solution:**
```toml
# Enable code splitting
[optimization]
bundle_splitting = true
tree_shaking = true
lazy_loading = true

# Route-based splitting
[[routes]]
path = "/admin/*"
bundle = "admin"
lazy_load = true
```

This guide covers the essential patterns and best practices for Rustelo's configuration-driven hydration system. The 90/10 rule applies: use TOML configuration for standard hydration needs, and custom code only for complex requirements that configuration can't express.
