cc-codeconductor 0.2.10 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/index.js +1636 -1078
- package/package.json +1 -1
- package/presets/agy/AGENTS.md +46 -2
- package/presets/claude/CLAUDE.md +62 -2
- package/presets/claude/skills/android/SKILL.md +119 -0
- package/presets/claude/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/claude/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/claude/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/claude/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/claude/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/claude/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/claude/skills/php-pro/SKILL.md +208 -0
- package/presets/claude/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/claude/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/claude/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/claude/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/claude/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/codex/AGENTS.md +47 -2
- package/presets/codex/skills/android/SKILL.md +119 -0
- package/presets/codex/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/codex/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/codex/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/codex/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/codex/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/codex/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/codex/skills/php-pro/SKILL.md +208 -0
- package/presets/codex/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/codex/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/codex/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/codex/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/codex/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/opencode/agents/implementer.md +2 -2
- package/presets/opencode/agents/orchestrator.md +132 -5
- package/presets/opencode/agents/reviewer.md +33 -0
- package/presets/opencode/prompts/v0.3.0/architect.md +221 -0
- package/presets/opencode/prompts/v0.3.0/docs.md +189 -0
- package/presets/opencode/prompts/v0.3.0/implementer.md +162 -0
- package/presets/opencode/prompts/v0.3.0/orchestrator.md +360 -0
- package/presets/opencode/prompts/v0.3.0/repo-explorer.md +110 -0
- package/presets/opencode/prompts/v0.3.0/reviewer.md +225 -0
- package/presets/opencode/prompts/v0.3.0/task-coach.md +155 -0
- package/presets/opencode/prompts/v0.3.0/tester.md +251 -0
- package/presets/opencode/skills/android/SKILL.md +119 -0
- package/presets/opencode/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/opencode/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/opencode/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/opencode/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/opencode/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/opencode/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/opencode/skills/php-pro/SKILL.md +208 -0
- package/presets/opencode/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/opencode/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/opencode/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/opencode/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/opencode/skills/php-pro/references/testing-quality.md +466 -0
- package/src/presets/manifests/agy.yml +3 -2
- package/src/presets/manifests/claude.yml +3 -2
- package/src/presets/manifests/codex.yml +3 -2
- package/src/presets/manifests/cursor.yml +3 -2
- package/src/presets/manifests/gemini.yml +3 -2
- package/src/presets/manifests/opencode.yml +3 -2
- package/src/presets/models/opencode.yml +6 -6
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
# Livewire Components
|
|
2
|
+
|
|
3
|
+
## Component Patterns
|
|
4
|
+
|
|
5
|
+
```php
|
|
6
|
+
namespace App\Http\Livewire;
|
|
7
|
+
|
|
8
|
+
use Livewire\Component;
|
|
9
|
+
use Livewire\WithPagination;
|
|
10
|
+
use Livewire\WithFileUploads;
|
|
11
|
+
use App\Models\Post;
|
|
12
|
+
|
|
13
|
+
class PostList extends Component
|
|
14
|
+
{
|
|
15
|
+
use WithPagination, WithFileUploads;
|
|
16
|
+
|
|
17
|
+
public string $search = '';
|
|
18
|
+
public string $sortBy = 'created_at';
|
|
19
|
+
public string $sortDirection = 'desc';
|
|
20
|
+
public ?int $categoryId = null;
|
|
21
|
+
|
|
22
|
+
protected $queryString = [
|
|
23
|
+
'search' => ['except' => ''],
|
|
24
|
+
'sortBy' => ['except' => 'created_at'],
|
|
25
|
+
'categoryId' => ['except' => null],
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
public function updatingSearch(): void
|
|
29
|
+
{
|
|
30
|
+
$this->resetPage();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public function sortBy(string $field): void
|
|
34
|
+
{
|
|
35
|
+
if ($this->sortBy === $field) {
|
|
36
|
+
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
|
|
37
|
+
} else {
|
|
38
|
+
$this->sortBy = $field;
|
|
39
|
+
$this->sortDirection = 'asc';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public function render()
|
|
44
|
+
{
|
|
45
|
+
return view('livewire.post-list', [
|
|
46
|
+
'posts' => Post::query()
|
|
47
|
+
->when($this->search, fn($q) => $q->where('title', 'like', "%{$this->search}%"))
|
|
48
|
+
->when($this->categoryId, fn($q) => $q->where('category_id', $this->categoryId))
|
|
49
|
+
->orderBy($this->sortBy, $this->sortDirection)
|
|
50
|
+
->paginate(10),
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Blade Template
|
|
57
|
+
|
|
58
|
+
```blade
|
|
59
|
+
<div>
|
|
60
|
+
{{-- Search --}}
|
|
61
|
+
<input
|
|
62
|
+
type="text"
|
|
63
|
+
wire:model.debounce.300ms="search"
|
|
64
|
+
placeholder="Search posts..."
|
|
65
|
+
class="form-input"
|
|
66
|
+
>
|
|
67
|
+
|
|
68
|
+
{{-- Filter by category --}}
|
|
69
|
+
<select wire:model="categoryId">
|
|
70
|
+
<option value="">All Categories</option>
|
|
71
|
+
@foreach($categories as $category)
|
|
72
|
+
<option value="{{ $category->id }}">{{ $category->name }}</option>
|
|
73
|
+
@endforeach
|
|
74
|
+
</select>
|
|
75
|
+
|
|
76
|
+
{{-- Sortable table --}}
|
|
77
|
+
<table>
|
|
78
|
+
<thead>
|
|
79
|
+
<tr>
|
|
80
|
+
<th wire:click="sortBy('title')" style="cursor: pointer">
|
|
81
|
+
Title
|
|
82
|
+
@if($sortBy === 'title')
|
|
83
|
+
<span>{{ $sortDirection === 'asc' ? '↑' : '↓' }}</span>
|
|
84
|
+
@endif
|
|
85
|
+
</th>
|
|
86
|
+
<th wire:click="sortBy('created_at')" style="cursor: pointer">
|
|
87
|
+
Date
|
|
88
|
+
@if($sortBy === 'created_at')
|
|
89
|
+
<span>{{ $sortDirection === 'asc' ? '↑' : '↓' }}</span>
|
|
90
|
+
@endif
|
|
91
|
+
</th>
|
|
92
|
+
</tr>
|
|
93
|
+
</thead>
|
|
94
|
+
<tbody>
|
|
95
|
+
@foreach($posts as $post)
|
|
96
|
+
<tr>
|
|
97
|
+
<td>{{ $post->title }}</td>
|
|
98
|
+
<td>{{ $post->created_at->diffForHumans() }}</td>
|
|
99
|
+
</tr>
|
|
100
|
+
@endforeach
|
|
101
|
+
</tbody>
|
|
102
|
+
</table>
|
|
103
|
+
|
|
104
|
+
{{-- Pagination --}}
|
|
105
|
+
{{ $posts->links() }}
|
|
106
|
+
|
|
107
|
+
{{-- Loading states --}}
|
|
108
|
+
<div wire:loading wire:target="search">
|
|
109
|
+
Searching...
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Form Component
|
|
115
|
+
|
|
116
|
+
```php
|
|
117
|
+
namespace App\Http\Livewire;
|
|
118
|
+
|
|
119
|
+
use Livewire\Component;
|
|
120
|
+
use App\Models\Post;
|
|
121
|
+
|
|
122
|
+
class PostForm extends Component
|
|
123
|
+
{
|
|
124
|
+
public ?Post $post = null;
|
|
125
|
+
public string $title = '';
|
|
126
|
+
public string $content = '';
|
|
127
|
+
public array $tags = [];
|
|
128
|
+
public $image;
|
|
129
|
+
|
|
130
|
+
protected function rules(): array
|
|
131
|
+
{
|
|
132
|
+
return [
|
|
133
|
+
'title' => 'required|min:3|max:255',
|
|
134
|
+
'content' => 'required|min:10',
|
|
135
|
+
'tags' => 'array|max:5',
|
|
136
|
+
'tags.*' => 'exists:tags,id',
|
|
137
|
+
'image' => 'nullable|image|max:2048',
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public function mount(?Post $post = null): void
|
|
142
|
+
{
|
|
143
|
+
if ($post) {
|
|
144
|
+
$this->post = $post;
|
|
145
|
+
$this->title = $post->title;
|
|
146
|
+
$this->content = $post->content;
|
|
147
|
+
$this->tags = $post->tags->pluck('id')->toArray();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public function updated($propertyName): void
|
|
152
|
+
{
|
|
153
|
+
$this->validateOnly($propertyName);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public function save(): void
|
|
157
|
+
{
|
|
158
|
+
$validated = $this->validate();
|
|
159
|
+
|
|
160
|
+
if ($this->post) {
|
|
161
|
+
$this->post->update($validated);
|
|
162
|
+
$message = 'Post updated successfully!';
|
|
163
|
+
} else {
|
|
164
|
+
$this->post = Post::create($validated);
|
|
165
|
+
$message = 'Post created successfully!';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if ($this->image) {
|
|
169
|
+
$this->post->update([
|
|
170
|
+
'image_path' => $this->image->store('posts', 'public'),
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
$this->post->tags()->sync($this->tags);
|
|
175
|
+
|
|
176
|
+
session()->flash('message', $message);
|
|
177
|
+
$this->redirect(route('posts.show', $this->post));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public function render()
|
|
181
|
+
{
|
|
182
|
+
return view('livewire.post-form');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Form Template
|
|
188
|
+
|
|
189
|
+
```blade
|
|
190
|
+
<form wire:submit.prevent="save">
|
|
191
|
+
{{-- Title --}}
|
|
192
|
+
<div>
|
|
193
|
+
<label for="title">Title</label>
|
|
194
|
+
<input
|
|
195
|
+
type="text"
|
|
196
|
+
wire:model.defer="title"
|
|
197
|
+
id="title"
|
|
198
|
+
class="@error('title') border-red-500 @enderror"
|
|
199
|
+
>
|
|
200
|
+
@error('title')
|
|
201
|
+
<span class="text-red-500">{{ $message }}</span>
|
|
202
|
+
@enderror
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
{{-- Content --}}
|
|
206
|
+
<div>
|
|
207
|
+
<label for="content">Content</label>
|
|
208
|
+
<textarea
|
|
209
|
+
wire:model.defer="content"
|
|
210
|
+
id="content"
|
|
211
|
+
class="@error('content') border-red-500 @enderror"
|
|
212
|
+
></textarea>
|
|
213
|
+
@error('content')
|
|
214
|
+
<span class="text-red-500">{{ $message }}</span>
|
|
215
|
+
@enderror
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
{{-- Tags --}}
|
|
219
|
+
<div>
|
|
220
|
+
<label>Tags</label>
|
|
221
|
+
@foreach($availableTags as $tag)
|
|
222
|
+
<label>
|
|
223
|
+
<input
|
|
224
|
+
type="checkbox"
|
|
225
|
+
wire:model="tags"
|
|
226
|
+
value="{{ $tag->id }}"
|
|
227
|
+
>
|
|
228
|
+
{{ $tag->name }}
|
|
229
|
+
</label>
|
|
230
|
+
@endforeach
|
|
231
|
+
@error('tags')
|
|
232
|
+
<span class="text-red-500">{{ $message }}</span>
|
|
233
|
+
@enderror
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
{{-- File Upload --}}
|
|
237
|
+
<div>
|
|
238
|
+
<label>Image</label>
|
|
239
|
+
<input type="file" wire:model="image">
|
|
240
|
+
|
|
241
|
+
@error('image')
|
|
242
|
+
<span class="text-red-500">{{ $message }}</span>
|
|
243
|
+
@enderror
|
|
244
|
+
|
|
245
|
+
{{-- Upload progress --}}
|
|
246
|
+
<div wire:loading wire:target="image">
|
|
247
|
+
Uploading...
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
{{-- Preview --}}
|
|
251
|
+
@if ($image)
|
|
252
|
+
<img src="{{ $image->temporaryUrl() }}" alt="Preview">
|
|
253
|
+
@endif
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
{{-- Submit --}}
|
|
257
|
+
<button type="submit" wire:loading.attr="disabled">
|
|
258
|
+
<span wire:loading.remove>Save</span>
|
|
259
|
+
<span wire:loading>Saving...</span>
|
|
260
|
+
</button>
|
|
261
|
+
</form>
|
|
262
|
+
|
|
263
|
+
@if (session()->has('message'))
|
|
264
|
+
<div class="alert alert-success">
|
|
265
|
+
{{ session('message') }}
|
|
266
|
+
</div>
|
|
267
|
+
@endif
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Real-time Validation
|
|
271
|
+
|
|
272
|
+
```php
|
|
273
|
+
class PostForm extends Component
|
|
274
|
+
{
|
|
275
|
+
public string $title = '';
|
|
276
|
+
|
|
277
|
+
protected $rules = [
|
|
278
|
+
'title' => 'required|min:3|unique:posts,title',
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
// Real-time validation
|
|
282
|
+
public function updated($propertyName): void
|
|
283
|
+
{
|
|
284
|
+
$this->validateOnly($propertyName);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Custom validation messages
|
|
288
|
+
protected $messages = [
|
|
289
|
+
'title.required' => 'The post title is required.',
|
|
290
|
+
'title.min' => 'The title must be at least 3 characters.',
|
|
291
|
+
'title.unique' => 'This title is already taken.',
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
// Custom attribute names
|
|
295
|
+
protected $validationAttributes = [
|
|
296
|
+
'title' => 'post title',
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Events
|
|
302
|
+
|
|
303
|
+
```php
|
|
304
|
+
// Emit event
|
|
305
|
+
class PostList extends Component
|
|
306
|
+
{
|
|
307
|
+
public function deletePost($postId): void
|
|
308
|
+
{
|
|
309
|
+
Post::find($postId)->delete();
|
|
310
|
+
|
|
311
|
+
$this->emit('postDeleted', $postId);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Listen to event
|
|
316
|
+
class PostStats extends Component
|
|
317
|
+
{
|
|
318
|
+
protected $listeners = ['postDeleted' => 'updateStats'];
|
|
319
|
+
|
|
320
|
+
public function updateStats($postId): void
|
|
321
|
+
{
|
|
322
|
+
// Update statistics
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Emit to specific component
|
|
327
|
+
$this->emitTo('post-stats', 'refresh');
|
|
328
|
+
|
|
329
|
+
// Emit to parent/children
|
|
330
|
+
$this->emitUp('saved');
|
|
331
|
+
$this->emitSelf('refresh');
|
|
332
|
+
|
|
333
|
+
// Browser events
|
|
334
|
+
$this->dispatchBrowserEvent('post-saved', ['id' => $post->id]);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Listen to Browser Events
|
|
338
|
+
|
|
339
|
+
```blade
|
|
340
|
+
<div
|
|
341
|
+
x-data
|
|
342
|
+
@post-saved.window="alert('Post saved!')"
|
|
343
|
+
>
|
|
344
|
+
<!-- content -->
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<script>
|
|
348
|
+
window.addEventListener('post-saved', event => {
|
|
349
|
+
console.log('Post ID:', event.detail.id);
|
|
350
|
+
});
|
|
351
|
+
</script>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Polling
|
|
355
|
+
|
|
356
|
+
```blade
|
|
357
|
+
{{-- Poll every 2 seconds --}}
|
|
358
|
+
<div wire:poll.2s>
|
|
359
|
+
Current time: {{ now() }}
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
{{-- Poll specific action --}}
|
|
363
|
+
<div wire:poll.5s="checkStatus">
|
|
364
|
+
Status: {{ $status }}
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
{{-- Keep polling until condition --}}
|
|
368
|
+
<div wire:poll.keep-alive.2s>
|
|
369
|
+
<!-- content -->
|
|
370
|
+
</div>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Loading States
|
|
374
|
+
|
|
375
|
+
```blade
|
|
376
|
+
{{-- Basic loading state --}}
|
|
377
|
+
<div wire:loading>
|
|
378
|
+
Loading...
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
{{-- Target specific action --}}
|
|
382
|
+
<div wire:loading wire:target="save">
|
|
383
|
+
Saving...
|
|
384
|
+
</div>
|
|
385
|
+
|
|
386
|
+
{{-- Hide element while loading --}}
|
|
387
|
+
<div wire:loading.remove>
|
|
388
|
+
Content (hidden during load)
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
{{-- Delay loading indicator --}}
|
|
392
|
+
<div wire:loading.delay>
|
|
393
|
+
This appears after 200ms
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
{{-- Custom delay --}}
|
|
397
|
+
<div wire:loading.delay.longest>
|
|
398
|
+
This appears after 1s
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
{{-- Loading classes --}}
|
|
402
|
+
<button
|
|
403
|
+
wire:click="save"
|
|
404
|
+
wire:loading.class="opacity-50"
|
|
405
|
+
wire:loading.class.remove="bg-blue-500"
|
|
406
|
+
>
|
|
407
|
+
Save
|
|
408
|
+
</button>
|
|
409
|
+
|
|
410
|
+
{{-- Loading attributes --}}
|
|
411
|
+
<button
|
|
412
|
+
wire:click="save"
|
|
413
|
+
wire:loading.attr="disabled"
|
|
414
|
+
>
|
|
415
|
+
Save
|
|
416
|
+
</button>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Traits
|
|
420
|
+
|
|
421
|
+
```php
|
|
422
|
+
// Pagination
|
|
423
|
+
use Livewire\WithPagination;
|
|
424
|
+
|
|
425
|
+
class PostList extends Component
|
|
426
|
+
{
|
|
427
|
+
use WithPagination;
|
|
428
|
+
|
|
429
|
+
public function render()
|
|
430
|
+
{
|
|
431
|
+
return view('livewire.post-list', [
|
|
432
|
+
'posts' => Post::paginate(10),
|
|
433
|
+
]);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// File uploads
|
|
438
|
+
use Livewire\WithFileUploads;
|
|
439
|
+
|
|
440
|
+
class UploadPhoto extends Component
|
|
441
|
+
{
|
|
442
|
+
use WithFileUploads;
|
|
443
|
+
|
|
444
|
+
public $photo;
|
|
445
|
+
|
|
446
|
+
public function save(): void
|
|
447
|
+
{
|
|
448
|
+
$this->validate([
|
|
449
|
+
'photo' => 'image|max:1024',
|
|
450
|
+
]);
|
|
451
|
+
|
|
452
|
+
$this->photo->store('photos');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Authorization
|
|
458
|
+
|
|
459
|
+
```php
|
|
460
|
+
class PostForm extends Component
|
|
461
|
+
{
|
|
462
|
+
public Post $post;
|
|
463
|
+
|
|
464
|
+
public function mount(Post $post): void
|
|
465
|
+
{
|
|
466
|
+
$this->authorize('update', $post);
|
|
467
|
+
$this->post = $post;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
public function save(): void
|
|
471
|
+
{
|
|
472
|
+
$this->authorize('update', $this->post);
|
|
473
|
+
// Save logic
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Performance Tips
|
|
479
|
+
|
|
480
|
+
1. **Use wire:model.defer** - Batch updates on form submit
|
|
481
|
+
2. **Lazy load components** - Use wire:init for heavy operations
|
|
482
|
+
3. **Cache computed properties** - Use #[Computed] attribute
|
|
483
|
+
4. **Disable polling when hidden** - Use wire:poll.visible
|
|
484
|
+
5. **Optimize queries** - Eager load relationships
|
|
485
|
+
6. **Use wire:key** - Prevent re-rendering entire lists
|
|
486
|
+
7. **Debounce input** - Use wire:model.debounce
|
|
487
|
+
8. **Use pagination** - Don't load all records at once
|
|
488
|
+
|
|
489
|
+
```php
|
|
490
|
+
use Livewire\Attributes\Computed;
|
|
491
|
+
|
|
492
|
+
class PostList extends Component
|
|
493
|
+
{
|
|
494
|
+
#[Computed]
|
|
495
|
+
public function posts()
|
|
496
|
+
{
|
|
497
|
+
return Post::with('user')->paginate(10);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
public function render()
|
|
501
|
+
{
|
|
502
|
+
return view('livewire.post-list');
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
```blade
|
|
508
|
+
{{-- Access computed property --}}
|
|
509
|
+
@foreach($this->posts as $post)
|
|
510
|
+
<!-- content -->
|
|
511
|
+
@endforeach
|
|
512
|
+
```
|