fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
308
docs/livecomponents/island-directive.md
Normal file
308
docs/livecomponents/island-directive.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# Island Directive
|
||||
|
||||
**Isolated Component Rendering** - Render heavy components separately for better performance.
|
||||
|
||||
## Overview
|
||||
|
||||
The `#[Island]` directive enables isolated rendering of LiveComponents, allowing them to be rendered separately from the main template flow. This is particularly useful for resource-intensive components that can slow down page rendering.
|
||||
|
||||
## Features
|
||||
|
||||
- **Isolated Rendering**: Components are rendered separately without template wrapper
|
||||
- **Lazy Loading**: Optional lazy loading when component enters viewport
|
||||
- **Independent Caching**: Islands can have their own caching strategies
|
||||
- **Isolated Events**: Islands don't receive parent component events
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Simple Island Component
|
||||
|
||||
```php
|
||||
use App\Framework\LiveComponents\Attributes\LiveComponent;
|
||||
use App\Framework\LiveComponents\Attributes\Island;
|
||||
|
||||
#[LiveComponent('heavy-widget')]
|
||||
#[Island]
|
||||
final readonly class HeavyWidgetComponent implements LiveComponentContract
|
||||
{
|
||||
// Component implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Lazy Island Component
|
||||
|
||||
```php
|
||||
#[LiveComponent('metrics-dashboard')]
|
||||
#[Island(isolated: true, lazy: true, placeholder: 'Loading dashboard...')]
|
||||
final readonly class MetricsDashboardComponent implements LiveComponentContract
|
||||
{
|
||||
// Component implementation
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### `isolated` (bool, default: `true`)
|
||||
|
||||
Whether the component should be rendered in isolation. When `true`, the component is rendered via the `/island` endpoint without template wrapper.
|
||||
|
||||
```php
|
||||
#[Island(isolated: true)] // Isolated rendering (default)
|
||||
#[Island(isolated: false)] // Normal rendering (not recommended)
|
||||
```
|
||||
|
||||
### `lazy` (bool, default: `false`)
|
||||
|
||||
Whether the component should be lazy-loaded when entering the viewport. When `true`, a placeholder is generated and the component is loaded via IntersectionObserver.
|
||||
|
||||
```php
|
||||
#[Island(lazy: true)] // Lazy load on viewport entry
|
||||
#[Island(lazy: false)] // Load immediately (default)
|
||||
```
|
||||
|
||||
### `placeholder` (string|null, default: `null`)
|
||||
|
||||
Custom placeholder text shown while the component is loading (only used when `lazy: true`).
|
||||
|
||||
```php
|
||||
#[Island(lazy: true, placeholder: 'Loading widget...')]
|
||||
```
|
||||
|
||||
## Template Usage
|
||||
|
||||
### In Templates
|
||||
|
||||
Island components are used the same way as regular LiveComponents:
|
||||
|
||||
```html
|
||||
<x-heavy-widget id="user-123" />
|
||||
```
|
||||
|
||||
When processed, lazy Islands generate a placeholder:
|
||||
|
||||
```html
|
||||
<div data-island-component="true"
|
||||
data-live-component-lazy="heavy-widget:user-123"
|
||||
data-lazy-priority="normal"
|
||||
data-lazy-threshold="0.1">
|
||||
<div class="island-placeholder">Loading widget...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Island vs. Lazy Component
|
||||
|
||||
### Lazy Component (`data-live-component-lazy`)
|
||||
|
||||
- Loaded when entering viewport
|
||||
- Part of normal template flow
|
||||
- Shares state/events with parent components
|
||||
- Uses `/lazy-load` endpoint
|
||||
|
||||
### Island Component (`data-island-component`)
|
||||
|
||||
- Rendered in isolation (separate request)
|
||||
- No template wrapper (no layout/meta)
|
||||
- Isolated event context (no parent events)
|
||||
- Optional lazy loading on viewport entry
|
||||
- Uses `/island` endpoint
|
||||
|
||||
## Performance Benefits
|
||||
|
||||
### Isolation
|
||||
|
||||
Islands reduce template processing overhead for heavy components by rendering them separately. This means:
|
||||
|
||||
- Heavy components don't block main page rendering
|
||||
- Independent error handling (one island failure doesn't affect others)
|
||||
- Separate caching strategies per island
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
When combined with lazy loading, Islands provide:
|
||||
|
||||
- Reduced initial page load time
|
||||
- Faster Time to Interactive (TTI)
|
||||
- Better Core Web Vitals scores
|
||||
|
||||
### Example Performance Impact
|
||||
|
||||
```php
|
||||
// Without Island: 500ms page load (heavy component blocks rendering)
|
||||
// With Island: 200ms page load + 300ms island load (non-blocking)
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Heavy Widgets
|
||||
|
||||
```php
|
||||
#[LiveComponent('analytics-dashboard')]
|
||||
#[Island(isolated: true, lazy: true, placeholder: 'Loading analytics...')]
|
||||
final readonly class AnalyticsDashboardComponent implements LiveComponentContract
|
||||
{
|
||||
// Heavy component with complex data processing
|
||||
}
|
||||
```
|
||||
|
||||
### Third-Party Integrations
|
||||
|
||||
```php
|
||||
#[LiveComponent('external-map')]
|
||||
#[Island(isolated: true, lazy: true)]
|
||||
final readonly class ExternalMapComponent implements LiveComponentContract
|
||||
{
|
||||
// Component that loads external resources
|
||||
}
|
||||
```
|
||||
|
||||
### Conditional Components
|
||||
|
||||
```php
|
||||
#[LiveComponent('admin-panel')]
|
||||
#[Island(isolated: true)]
|
||||
final readonly class AdminPanelComponent implements LiveComponentContract
|
||||
{
|
||||
// Component only visible to admins
|
||||
// Isolated to prevent template processing for non-admin users
|
||||
}
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Endpoint
|
||||
|
||||
Islands are rendered via:
|
||||
|
||||
```
|
||||
GET /live-component/{id}/island
|
||||
```
|
||||
|
||||
This endpoint:
|
||||
- Renders component HTML without template wrapper
|
||||
- Returns JSON with `html`, `state`, `csrf_token`
|
||||
- Uses `ComponentRegistry.render()` directly (no wrapper)
|
||||
|
||||
### Frontend Integration
|
||||
|
||||
Islands are automatically detected and handled by `LazyComponentLoader`:
|
||||
|
||||
- Lazy islands: Loaded when entering viewport
|
||||
- Non-lazy islands: Loaded immediately
|
||||
- Isolated initialization: Islands don't receive parent events
|
||||
|
||||
### Event Isolation
|
||||
|
||||
Islands have isolated event contexts:
|
||||
|
||||
- No parent component events
|
||||
- No shared state with parent components
|
||||
- Independent SSE channels (if configured)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Islands for Heavy Components**: Only use `#[Island]` for components that significantly impact page load time
|
||||
|
||||
2. **Combine with Lazy Loading**: Use `lazy: true` for below-the-fold content
|
||||
|
||||
3. **Provide Placeholders**: Always provide meaningful placeholder text for better UX
|
||||
|
||||
4. **Test Isolation**: Verify that islands work correctly in isolation
|
||||
|
||||
5. **Monitor Performance**: Track island load times and optimize as needed
|
||||
|
||||
## Examples
|
||||
|
||||
### Complete Example
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Application\LiveComponents\Dashboard;
|
||||
|
||||
use App\Framework\LiveComponents\Attributes\LiveComponent;
|
||||
use App\Framework\LiveComponents\Attributes\Island;
|
||||
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
|
||||
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
||||
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
|
||||
use App\Framework\LiveComponents\ValueObjects\ComponentState;
|
||||
|
||||
#[LiveComponent('metrics-dashboard')]
|
||||
#[Island(isolated: true, lazy: true, placeholder: 'Loading metrics...')]
|
||||
final readonly class MetricsDashboardComponent implements LiveComponentContract
|
||||
{
|
||||
public function __construct(
|
||||
public ComponentId $id,
|
||||
public ComponentState $state
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRenderData(): ComponentRenderData
|
||||
{
|
||||
return new ComponentRenderData(
|
||||
templatePath: 'livecomponent-metrics-dashboard',
|
||||
data: [
|
||||
'componentId' => $this->id->toString(),
|
||||
'metrics' => $this->loadMetrics(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function loadMetrics(): array
|
||||
{
|
||||
// Heavy operation - isolated rendering prevents blocking
|
||||
return [
|
||||
'users' => 12345,
|
||||
'orders' => 6789,
|
||||
'revenue' => 123456.78,
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Converting Regular Component to Island
|
||||
|
||||
1. Add `#[Island]` attribute to component class
|
||||
2. Test component rendering (should work identically)
|
||||
3. Optionally enable lazy loading with `lazy: true`
|
||||
4. Monitor performance improvements
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- Components without `#[Island]` work exactly as before
|
||||
- `#[Island]` is opt-in (no breaking changes)
|
||||
- Existing lazy components continue to work
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Island Not Loading
|
||||
|
||||
- Check browser console for errors
|
||||
- Verify component is registered in ComponentRegistry
|
||||
- Ensure `/island` endpoint is accessible
|
||||
|
||||
### Placeholder Not Showing
|
||||
|
||||
- Verify `lazy: true` is set
|
||||
- Check `placeholder` parameter is provided
|
||||
- Inspect generated HTML for `data-island-component` attribute
|
||||
|
||||
### Events Not Working
|
||||
|
||||
- Islands have isolated event contexts
|
||||
- Use component-specific events, not parent events
|
||||
- Check SSE channel configuration if using real-time updates
|
||||
|
||||
## See Also
|
||||
|
||||
- [Lazy Loading Guide](livecomponents-lazy-loading.md)
|
||||
- [Component Caching](livecomponents-caching.md)
|
||||
- [Performance Optimization](livecomponents-performance.md)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user