# LiveComponents FAQ **Frequently Asked Questions about LiveComponents** --- ## General Questions ### What are LiveComponents? LiveComponents is a server-side component system that enables building interactive web applications with minimal JavaScript. Components render on the server, sync state automatically, and update the DOM intelligently via fragment-based rendering. **Key Benefits**: - Write interactive UIs in PHP - Automatic state synchronization - Fragment-based partial updates - Built-in security (CSRF, rate limiting, validation) - Real-time updates via Server-Sent Events --- ### When should I use LiveComponents vs traditional JavaScript? **Use LiveComponents for**: - Admin dashboards - CRUD interfaces - Forms with complex validation - Real-time data displays - Prototyping interactive features **Use traditional JavaScript for**: - Complex client-side logic - Heavy animations - Offline-first applications - Games or interactive visualizations - High-frequency updates (>60fps) **Use Both**: - LiveComponents for server-side state management - JavaScript for client-side enhancements --- ### How do LiveComponents compare to Livewire/Phoenix LiveView? **Similarities**: - Server-side rendering - Automatic state sync - Minimal JavaScript required **Differences**: - **Custom Framework Integration**: Built specifically for this framework's patterns (readonly, composition, value objects) - **Fragment Rendering**: More granular DOM updates - **Request Batching**: Automatic batching with configurable debouncing - **PHP 8.5 Optimized**: Leverages latest PHP performance improvements --- ## Installation & Setup ### How do I install LiveComponents? LiveComponents is built into the framework - no additional installation needed. **Verify installation**: ```bash # Check if LiveComponent JavaScript is compiled ls public/assets/js/livecomponent.js # Verify base class exists grep -r "abstract class LiveComponent" src/Framework/LiveComponents/ ``` --- ### What are the minimum requirements? **Server Requirements**: - PHP 8.4+ (8.5 recommended) - Composer - Custom PHP Framework installed **Browser Requirements**: - Chrome/Edge 90+ - Firefox 88+ - Safari 14+ - ES2020 JavaScript support - Fetch API - EventSource (SSE) --- ### How do I enable HTTPS for development? HTTPS is **required** for LiveComponents (CSRF protection, SSE). Framework includes SSL certificates for local development: ```bash # Start development server with HTTPS make up npm run dev # Access via HTTPS only https://localhost ``` --- ## Component Development ### Can I use TypeScript with LiveComponents? Yes! Add type definitions: ```typescript // livecomponents.d.ts declare global { interface Window { LiveComponent: { mount(element: HTMLElement): void; executeAction( componentId: string, action: string, params?: object ): Promise; getComponent(componentId: string): Component | null; }; } } export {}; ``` --- ### How do I pass initial data to a component? ```php // In controller use App\Framework\LiveComponents\LiveComponent; public function dashboard(): ViewResult { return new ViewResult('dashboard', [ 'statsWidget' => LiveComponent::mount(StatsWidget::class, [ 'user_id' => $currentUser->id, 'date_range' => 'last_30_days' ]) ]); } // In component final class StatsWidget extends LiveComponent { #[LiveProp] public string $userId; #[LiveProp] public string $dateRange; public function mount(array $initialData = []): void { $this->userId = $initialData['user_id'] ?? ''; $this->dateRange = $initialData['date_range'] ?? 'today'; $this->loadStats(); } } ``` --- ### How do I access the current user in a component? ```php use App\Framework\Auth\CurrentUser; final class UserDashboard extends LiveComponent { public function __construct( private readonly CurrentUser $currentUser ) {} public function mount(): void { $user = $this->currentUser->get(); $this->userId = $user->id; $this->userName = $user->name; } } ``` --- ### Can I nest LiveComponents? Yes, but with caveats: ```php // Parent component final class Dashboard extends LiveComponent { public function render(): string { return $this->view('dashboard', [ 'statsWidget' => LiveComponent::mount(StatsWidget::class), 'activityFeed' => LiveComponent::mount(ActivityFeed::class) ]); } } ``` **Template**: ```html

Dashboard

{statsWidget} {activityFeed}
``` **Limitations**: - Each component has its own lifecycle - Parent changes don't automatically update children - Use component communication for coordination --- ## State Management ### What types can I use for LiveProp? ```php // ✅ Supported types #[LiveProp] public string $name; #[LiveProp] public int $count; #[LiveProp] public float $price; #[LiveProp] public bool $active; #[LiveProp] public array $items; // ✅ Value Objects (with proper serialization) #[LiveProp] public Email $email; #[LiveProp] public Money $total; // ❌ Not supported #[LiveProp] public \DateTime $date; // Use DateTimeImmutable or Timestamp VO #[LiveProp] public UserRepository $repo; // Use DI, not LiveProp #[LiveProp] public callable $callback; // Closures can't be serialized ``` --- ### How do I handle large datasets? **Use pagination**: ```php final class ProductList extends LiveComponent { #[LiveProp] public int $page = 1; #[LiveProp] public int $perPage = 50; private array $products = []; public function mount(): void { $this->loadPage(); } #[LiveAction] #[Fragment('product-list')] public function loadPage(int $page = null): void { $this->page = $page ?? $this->page; // Only load current page $this->products = $this->productRepository->paginate( page: $this->page, perPage: $this->perPage ); } } ``` **Don't serialize large datasets**: ```php // ❌ Bad - serializes entire dataset #[LiveProp] public array $allProducts = []; // 10,000 products // ✅ Good - only serialize IDs #[LiveProp] public array $productIds = []; private array $products = []; // Not serialized public function hydrate(array $state): void { parent::hydrate($state); // Reload products from IDs $this->products = $this->productRepository->findByIds($this->productIds); } ``` --- ### Can I use sessions/cookies in components? Yes: ```php use App\Framework\Http\Session; final class PreferencesComponent extends LiveComponent { public function __construct( private readonly Session $session ) {} #[LiveAction] public function savePreference(string $key, string $value): void { $this->session->set("preferences.{$key}", $value); } } ``` --- ## Performance ### How can I optimize component performance? **1. Use Fragment Rendering**: ```php #[LiveAction] #[Fragment('search-results')] public function search(): void { // Only re-render search results fragment } ``` **2. Enable Request Batching**: ```javascript LiveComponent.configure({ batchSize: 10, batchDebounce: 50 }); ``` **3. Cache Expensive Operations**: ```php use App\Framework\Cache\Attributes\Cached; #[Cached(ttl: Duration::fromMinutes(5))] public function getStats(): array { // Cached for 5 minutes return $this->analyticsService->getStats(); } ``` **4. Use Optimistic UI**: ```php #[LiveAction] #[Optimistic(property: 'count', operation: 'increment')] public function increment(): void { $this->count++; } ``` See [Performance Guide](performance-guide.md) for more strategies. --- ### What's the maximum number of components per page? **Recommended**: <50 components per page for optimal performance **Performance characteristics**: - Each component: ~2MB memory (browser) - 50 components: ~100MB total - Network: Fragment updates minimize bandwidth **For high component counts**: - Use lazy loading - Implement virtual scrolling - Consider pagination --- ### How do I debug performance issues? **Enable DevTools**: ```env LIVECOMPONENT_DEVTOOLS_ENABLED=true ``` **Or via localStorage**: ```javascript localStorage.setItem('livecomponent_devtools', 'true'); location.reload(); ``` **Monitor metrics**: - Performance tab: Flamegraphs, timeline, memory profiling - Network tab: Request batching efficiency - Action log: Execution times --- ## Security ### Is CSRF protection enabled by default? Yes, CSRF protection is **automatic** for all LiveComponent requests. **How it works**: 1. CSRF token in meta tag: `` 2. Automatically included in all requests 3. Server validates token via `CsrfMiddleware` **Disable for specific routes** (not recommended): ```php #[Route(path: '/public-api', method: Method::POST)] #[SkipCsrf] public function publicEndpoint(): JsonResult { // Public endpoint without CSRF } ``` --- ### How do I implement authorization? ```php use App\Framework\LiveComponents\Attributes\Authorize; #[LiveAction] #[Authorize(roles: ['admin'])] public function deleteUser(string $userId): void { $this->userService->delete($userId); } #[LiveAction] #[Authorize(permissions: ['posts.edit'])] public function updatePost(): void { // Only users with posts.edit permission } ``` **Custom authorization**: ```php #[LiveAction] public function criticalAction(): void { if (!$this->canPerformAction()) { throw new UnauthorizedException('Insufficient permissions'); } // Perform action } private function canPerformAction(): bool { return $this->currentUser->hasRole('admin') || $this->resource->ownedBy($this->currentUser->id); } ``` --- ### How do I prevent SQL injection? Framework uses **parameterized queries** automatically: ```php // ✅ Safe - framework handles parameterization $users = $this->repository->findByEmail($this->email); // ✅ Safe - query builder with bindings $results = $this->db->query( 'SELECT * FROM users WHERE email = ?', [$this->email] ); // ❌ NEVER do this $results = $this->db->query( "SELECT * FROM users WHERE email = '{$this->email}'" ); ``` **Additional protection**: WAF SQL injection layer blocks suspicious patterns. --- ## Deployment ### What do I need for production deployment? **Required**: - [x] PHP 8.4+ production environment - [x] HTTPS enabled (required for CSRF/SSE) - [x] CSRF protection enabled (`LIVECOMPONENT_CSRF_PROTECTION=true`) - [x] Rate limiting configured - [x] Compiled JavaScript assets (`npm run build`) **Recommended**: - [x] Redis for SSE connection pool - [x] OPcache enabled (PHP 8.5 JIT) - [x] CDN for static assets - [x] Monitoring (performance metrics, error tracking) See [Security Guide - Production Checklist](security-guide.md#production-deployment-checklist). --- ### Can I use LiveComponents with a CDN? Yes: ```html ``` **Configure in build**: ```javascript // vite.config.js export default defineConfig({ base: 'https://cdn.example.com/assets/' }); ``` --- ### How do I handle server errors in production? **Server-side**: ```php use App\Framework\ErrorHandling\ErrorHandler; try { $result = $this->executeAction(); } catch (\Exception $e) { $this->errorHandler->log($e); // Return user-friendly error return new ActionResult( success: false, message: 'An error occurred. Please try again.', errors: $this->environment->isProduction() ? [] : [$e->getMessage()] ); } ``` **Client-side**: ```javascript window.addEventListener('livecomponent:error', (e) => { const { message, code } = e.detail; if (code === 'CSRF_TOKEN_EXPIRED') { LiveComponent.refreshCsrfToken(); } else { showNotification(message, 'error'); } }); ``` --- ## Testing ### How do I test LiveComponents? **Unit Tests (Pest)**: ```php it('increments counter', function () { $component = new Counter(); $component->mount(); expect($component->count)->toBe(0); $component->increment(); expect($component->count)->toBe(1); }); ``` **Integration Tests**: ```php it('renders component with correct data', function () { $component = new UserProfile(); $component->mount(['user_id' => '123']); $html = $component->render(); expect($html)->toContain('data-component-id'); expect($html)->toContain('User Profile'); }); ``` **E2E Tests (Playwright)**: ```javascript test('user can submit form', async ({ page }) => { await page.goto('https://localhost/form'); await page.fill('[data-lc-model="name"]', 'John Doe'); await page.click('[data-lc-action="submit"]'); await expect(page.locator('.success-message')).toBeVisible(); }); ``` --- ## Troubleshooting ### Component not updating after action **Check**: 1. Is `#[LiveProp]` attribute present? 2. Is property being modified in action? 3. Check browser console for JavaScript errors 4. Verify CSRF token is valid **Debug**: ```javascript // Get component state const component = LiveComponent.getComponent('component-id'); console.log('Current state:', component.state); // Monitor action execution window.addEventListener('livecomponent:action-executed', (e) => { console.log('Action result:', e.detail); }); ``` --- ### "CSRF token mismatch" error **Causes**: - Token expired (default: 2 hours) - Session cleared - Token not in meta tag **Solutions**: ```html ``` ```javascript // Refresh token LiveComponent.refreshCsrfToken().then(() => { LiveComponent.retryLastAction(); }); ``` --- ### SSE connection not working **Check**: 1. HTTPS enabled? (Required for SSE) 2. Port 443 accessible? 3. Firewall blocking SSE endpoint? **Debug**: ```javascript // Monitor SSE events window.addEventListener('livecomponent:sse-connected', () => { console.log('SSE connected'); }); window.addEventListener('livecomponent:sse-error', (e) => { console.error('SSE error:', e.detail); }); ``` --- ### High memory usage **Causes**: - Too many components (>100) - Large serialized state - Memory leaks in actions **Solutions**: 1. **Reduce component count**: Use pagination/lazy loading 2. **Minimize state**: Don't serialize large datasets 3. **Clean up in unmount**: ```php public function unmount(): void { $this->largeDataset = []; gc_collect_cycles(); } ``` --- ## Integration ### Can I use LiveComponents with Alpine.js? Yes: ```html

Count: {count}

Expandable content
``` **Best practices**: - Use LiveComponents for server state - Use Alpine.js for client-only UI state --- ### Can I use LiveComponents with htmx? They can coexist, but **don't mix** on the same element: ```html
LiveComponent content
htmx content
Conflict!
``` --- ## Advanced ### Can I create custom directives? Yes, extend the template processor: ```php use App\Framework\Template\TemplateProcessor; final readonly class CustomDirectiveProcessor implements TemplateProcessor { public function process(string $template, array $data): string { // Process custom directive: return preg_replace_callback( '/(.+?)<\/custom-tag>/', fn($matches) => $this->processCustomTag($matches[1]), $template ); } } ``` Register via attribute discovery: ```php #[TemplateProcessor(priority: 100)] final readonly class CustomDirectiveProcessor { ... } ``` --- ### How do I implement server-side rendering (SSR)? LiveComponents **is** server-side rendering - components render on the server and stream HTML to the client. For **initial page load SEO**: ```php // Controller returns fully rendered HTML public function page(): ViewResult { return new ViewResult('page', [ 'component' => LiveComponent::mount(InteractiveComponent::class) ]); } ``` HTML is immediately crawlable by search engines. --- ### Can I use WebSockets instead of SSE? Framework uses SSE by design because: - Simpler than WebSockets for server-to-client - Automatic reconnection - HTTP/2 multiplexing - Lower overhead for one-way updates For **two-way real-time**: Consider GraphQL subscriptions or framework's WebSocket support (separate from LiveComponents). --- ## Getting Help ### Where can I find more examples? - **GitHub**: Example components in `src/Application/LiveComponents/` - **Tests**: E2E tests in `tests/e2e/livecomponents-*.spec.js` - **Documentation**: [Getting Started](01-getting-started.md), [Advanced Features](advanced-features.md) --- ### How do I report bugs? **Security issues**: security@example.com **Bug reports**: GitHub Issues with: - Component code - Expected vs actual behavior - Browser console errors - Steps to reproduce --- ### How do I request features? Open GitHub Discussion with: - Use case description - Proposed API/syntax - Alternative solutions considered --- **Next**: [Troubleshooting Guide](troubleshooting.md) →