Livewire optimize
Detect and fix Livewire performance issues - heavy renders, excessive queries, unnecessary reactivity.From its SKILL.md
npx -y skills add edulazaro/laraclaude --skill livewire-optimizeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 12 stars12 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.6 KB, as published. Nobody here has run it
Subcommands
| 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 |
Overview
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.
Instructions
Step 1: Determine scope
Parse the argument:
- No argument or
report: Scan all Volt components underresources/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.
Step 2: Run each detection rule
Rule 1: Queries inside render() or blade template
Pattern to detect: Database queries executed during render. Look for:
Model::where(,Model::find(,DB::table(,DB::select(inside therender()method->get(),->first(),->count(),->pluck(),->paginate()insiderender()- Queries inside blade template via
{{ Model::where(...) }}or@phpblocks - Relationship access that triggers lazy loading in blade:
$this->model->relation->whererelationwas not eager-loaded
These 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.
Rule 2: Excessive public properties (payload bloat)
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.
Rule 3: wire:poll with heavy components
Pattern to detect: wire:poll or wire:poll.Xs on components that:
- Have more than 10 public properties
- Contain queries in render()
- Have a polling interval under 5 seconds
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.
Rule 4: Large arrays/collections as public properties
Pattern to detect: Public properties that are assigned large datasets:
$this->items = Model::all()->toArray()orModel::get()->toArray()(unbounded queries)- Array properties populated in mount() from queries without
->limit()or->take() - Properties assigned from
->pluck()->toArray()on tables known to have many rows
Report 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.
Rule 5: Components missing lazy loading
Pattern to detect: <livewire:component-name> tags in blade templates (parent components) where the child component:
- Is below the fold (inside tabs, accordions, or far down in the layout)
- Has heavy mount() logic (queries, file operations)
- Is inside
@ifblocks that may not be initially visible
Look for child components rendered inside:
- Tab panels (
role="tabpanel",x-show, conditional display) - Accordion bodies
- Modal bodies
- Elements with
hiddenordisplay:noneinitial state
Report 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.
Rule 6: Missing #[Computed] on repeated method calls
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- The method in the PHP block does NOT have
#[Computed]attribute - The method performs work (queries, calculations, array operations) - not simple getters
Report 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).
Rule 7: Multiple wire:model.live in same form
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.
Rule 8: Monolithic components that should be split
Pattern to detect: Components where:
- The PHP class block exceeds 200 lines
- There are more than 10 public methods (excluding lifecycle hooks)
- The blade template exceeds 400 lines
- Multiple unrelated concerns are handled (e.g., CRUD + filters + modals + exports)
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.
Step 3: Generate report
Group findings by severity and impact:
Severity levels:
- CRITICAL: Causes visible performance degradation (render queries, heavy polling, large payloads)
- WARNING: Wastes resources but may not be immediately visible (excessive props, missing lazy, missing computed)
- INFO: Best practices that improve performance marginally (live bindings, monolithic components)
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.
Step 4: Apply fixes (if fix mode)
Safe auto-fixes (applied automatically):
- Add
#[Computed]to methods called multiple times in blade - Add
use Livewire\Attributes\Computed;import - Add
lazyto child components in hidden containers - Add
.visibletowire:polldirectives - Convert
wire:model.livetowire:modelin forms (except search/filter fields) - Add
.debounce.300msto remainingwire:model.livebindings
Unsafe fixes (report only):
- Moving queries out of render() (changes component behavior)
- Reducing public properties (requires architectural changes)
- Splitting monolithic components (major refactor)
- Changing poll intervals (may affect functionality)
- Removing large array properties (requires alternative data loading strategy)
For each safe fix, show before/after context. For --dry-run, display but do not apply.