From laraclaude
Scans Livewire/Volt components for performance anti-patterns: render-time queries, excessive public properties, and unnecessary reactivity. Caught slow page loads, large payloads, and needless re-renders.
How this skill is triggered — by the user, by Claude, or both
Slash command
/laraclaude:livewire-optimize [report | fix | fix --dry-run | file-path | fix file-path][report | fix | fix --dry-run | file-path | fix file-path]This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Subcommand | Description |
| Subcommand | Description |
|---|---|
report | Scan all Volt components and report performance issues without changes |
fix | Scan all Volt components, report issues, and auto-fix what is safe |
fix --dry-run | Show what fixes would be applied without writing changes |
<file-path> | Scan a single file and report performance issues |
fix <file-path> | Scan a single file and auto-fix performance issues |
This skill analyzes Livewire/Volt components for performance anti-patterns that cause slow page loads, excessive server requests, large payloads, and unnecessary re-renders. It focuses on issues that degrade user experience at scale.
Parse the argument:
report: Scan all Volt components under resources/views/livewire/.fix (no path): Same scope, apply safe fixes.fix --dry-run: Show proposed fixes without applying.<file-path>: Single file report.fix <file-path>: Single file fix.Use Glob to find Volt components:
resources/views/livewire/**/*.blade.php
Filter to files containing new class extends Component.
Pattern to detect: Database queries executed during render. Look for:
Model::where(, Model::find(, DB::table(, DB::select( inside the render() method->get(), ->first(), ->count(), ->pluck(), ->paginate() inside render(){{ Model::where(...) }} or @php blocks$this->model->relation-> where relation was not eager-loadedThese queries run on EVERY re-render (every Livewire request).
Report format:
[RENDER-QUERY] file.blade.php:89
Query `User::where('active', true)->get()` inside render() runs on every re-render.
Move to mount() and store result, or use #[Computed] with cache.
Fix: Move query to a #[Computed] method with appropriate caching, or move to mount() if the data is static.
Pattern to detect: Volt components with more than 15 public properties.
Count all public $prop declarations in the PHP class block. Each public property is serialized and sent in every Livewire request/response.
Report format:
[EXCESSIVE-PROPS] file.blade.php
Component has 23 public properties. Each is serialized on every request.
Consider grouping related properties into a public array, using form objects,
or splitting into sub-components.
Fix: No auto-fix (requires architectural decision). Report with specific suggestions based on the property types found.
Pattern to detect: wire:poll or wire:poll.Xs on components that:
Report format:
[HEAVY-POLL] file.blade.php:12
wire:poll.2s on component with 18 public properties and render() queries.
Each poll sends full component state. Consider:
- Increasing interval to 10s+
- Using wire:poll.visible to pause when tab is hidden
- Extracting polled data to a smaller sub-component
Fix: Add .visible modifier if missing. Suggest increasing interval in report.
Pattern to detect: Public properties that are assigned large datasets:
$this->items = Model::all()->toArray() or Model::get()->toArray() (unbounded queries)->limit() or ->take()->pluck()->toArray() on tables known to have many rowsReport format:
[LARGE-PAYLOAD] file.blade.php:34
Public property `$allLocations` assigned from `Location::all()->toArray()`.
This could be thousands of items serialized on every request.
Consider: server-side search, pagination, or lazy loading.
Fix: No auto-fix. Report only.
Pattern to detect: <livewire:component-name> tags in blade templates (parent components) where the child component:
@if blocks that may not be initially visibleLook for child components rendered inside:
role="tabpanel", x-show, conditional display)hidden or display:none initial stateReport format:
[MISSING-LAZY] parent.blade.php:156
<livewire:properties.features> is inside a hidden tab panel.
Use <livewire:properties.features lazy /> to defer loading until visible.
Fix: Add lazy attribute to the <livewire: tag.
Pattern to detect: Methods in the PHP class block that are called multiple times in the blade template without #[Computed] attribute.
Look for:
$this->methodName() appearing 2+ times in the blade section#[Computed] attributeReport format:
[MISSING-COMPUTED] file.blade.php
Method `getVisibleFields()` called 4 times in template without #[Computed].
Each call executes the method body. Add #[Computed] to cache within request.
Fix: Add #[Computed] attribute above the method. Add use Livewire\Attributes\Computed; import if not present. Rename method to remove get prefix if following Livewire 3 conventions (e.g., getVisibleFields() -> visibleFields() with $this->visibleFields access in blade).
Pattern to detect: <form> elements (or containers with wire:submit) containing more than 2 wire:model.live bindings without debounce.
Each wire:model.live field sends a server request on every input change. Multiple such fields in one form compound the problem.
Report format:
[EXCESSIVE-LIVE-BINDING] file.blade.php:45-89
Form contains 5 wire:model.live bindings without debounce.
Each keystroke on any field triggers a full server roundtrip.
Consider:
- Using wire:model (update on submit only) for most fields
- Adding .debounce.300ms for fields that need live updates
- Using wire:model.blur for fields that only need update on focus loss
Fix: Convert wire:model.live to wire:model for fields that don't need real-time updates. Keep wire:model.live.debounce.300ms for search/filter fields.
Pattern to detect: Components where:
Report format:
[MONOLITHIC-COMPONENT] file.blade.php
Component has 285 PHP lines, 18 methods, 520 template lines.
Consider splitting into:
- A parent coordinator component
- Separate filter component
- Separate table/list component
- Separate modal components
Fix: No auto-fix. Report with specific splitting suggestions based on the component's structure.
Group findings by severity and impact:
Severity levels:
Output format:
## Livewire Performance Report
### resources/views/livewire/properties/index.blade.php
- [CRITICAL] Line 89: Query inside render() - User::where('active', true)->get()
- [CRITICAL] Line 12: wire:poll.2s with 18 public properties
- [WARNING] Component has 23 public properties (payload bloat)
- [INFO] 5 wire:model.live bindings in form without debounce
### resources/views/livewire/calendar.blade.php
- [WARNING] Method getVisibleFields() called 4x without #[Computed]
- [WARNING] <livewire:event-list> in hidden tab without lazy
---
**Summary**: 2 critical, 3 warnings, 1 info across 2 files.
**Estimated impact**: Fixing critical issues could reduce server load by ~60% on affected pages.
Safe auto-fixes (applied automatically):
#[Computed] to methods called multiple times in bladeuse Livewire\Attributes\Computed; importlazy to child components in hidden containers.visible to wire:poll directiveswire:model.live to wire:model in forms (except search/filter fields).debounce.300ms to remaining wire:model.live bindingsUnsafe fixes (report only):
For each safe fix, show before/after context. For --dry-run, display but do not apply.
npx claudepluginhub edulazaro/laraclaude --plugin laraclaudeAudits Livewire/Volt components for unserializable properties, missing wire:key, orphaned events, and re-render issues. Run report for diagnostics or fix with auto-repair.
Builds reactive UI with Livewire 4 on Laravel 13 using wire:model, actions, events, Volt, and Folio without writing JavaScript.
Creates interactive server-driven UI components in WordPress Sage themes using Livewire v3 via Acorn. Handles wire:model, file uploads, computed properties, and real-time form validation without writing JavaScript.