[ Livewire · תיעוד ]

מעבר מ-Livewire 3 ל-Livewire 4

מה השתנה בין Livewire 3 ל-Livewire 4: היכולות החדשות ששווה לאמץ, כל שינוי שובר עם קוד „לפני / אחרי“ ורשימת בדיקה למעבר של פרויקט אמיתי.

  • 3 → 4
  • שינויים שוברים
  • רשימת בדיקה
  • 14 פרקים
  • 15 דק׳ קריאה

1. בקצרה

Livewire 4 היא גרסה גדולה עם מסלול שדרוג קטן. מודל הקומפוננטות לא השתנה: מחלקת PHP, תצוגת Blade, state בשרת, HTML על גבי הרשת. מה שהשתנה הוא היכן הקומפוננטות נמצאות, איך הן נכתבות, וכמה מהעמוד עדכון בודד נוגע בו.

קומפוננטות מבוססות מחלקה ממשיכות לעבוד. קובץ יחיד הוא ברירת המחדל לקומפוננטות חדשות, לא שכתוב כפוי. רוב אפליקציות Livewire 3 משתדרגות על ידי העלאת הגרסה, תיקון קומץ שינויים שוברים ואימוץ הדרגתי של היכולות החדשות.

מה מרוויחים

  • קומפוננטות בקובץ יחיד — מחלקה ו-markup באותו קובץ.
  • Islands — אזורים שמתרנדרים מחדש באופן עצמאי, בלי לפצל לקומפוננטות ילד.
  • Slots — ההורה מזריק markup לילדים, והוא מוערך בהקשר של ההורה.
  • Optimistic UI — wire:show, wire:text, wire:bind מעדכנים את ה-DOM בלי סבב מול השרת.
  • גרירה ושחרור — wire:sort, בלי ספרייה חיצונית.
  • Scoped CSS — סגנונות קומפוננטה שלא יכולים לדלוף החוצה.

מה ינשוך אתכם

  1. תגיות <livewire:…> לא סגורות לא מרנדרות דבר, בשקט.
  2. המשמעות של מודיפיירים ב-wire:model השתנתה — שדות מפסיקים להסתנכרן.
  3. נקודת הקצה של העדכונים עברה ל-/livewire-{hash}/ — כללי תשתית נשברים.
  4. המודיפיירים של wire:transition הוסרו.
  5. Volt שולב בליבה.

כל אחד מאלה מוסבר בפירוט בהמשך, עם קוד לפני ואחרי.

2. זה לצד זה

תחוםLivewire 3Livewire 4
קבצי קומפוננטה app/Livewire/Counter.php + resources/views/livewire/counter.blade.php resources/views/components/⚡counter.blade.php (קובץ יחיד)
פקודת יצירה php artisan livewire:make Counter php artisan make:livewire counter
ניתוב Route::get('/x', Dashboard::class) Route::livewire('/x', 'pages::dashboard')
רינדור חלקי פיצול לקומפוננטות ילד אזורי @island
Slots לא נתמך {{ $slot }}, <wire:slot name="…">
גרירה ושחרור SortableJS וקוד חיבור wire:sort
UI מיידי Alpine.js ידני wire:show, wire:text, wire:bind
CSS של קומפוננטה גיליון סגנונות גלובלי <style> מתוחם בתוך הקומפוננטה
פעולות מקבילות לא זמין #[Async], wire:click.async
נקודת קצה לעדכונים /livewire/update /livewire-{hash}/update
JS hooks Livewire.hook('request'|'commit') interceptRequest(), interceptMessage()
Volt חבילה נפרדת שולב בליבה
בדיקות PHPUnit או Pest, tests/Feature/Livewire מומלץ Pest, הבדיקות יכולות לשבת ליד הקומפוננטה

3. השדרוג, צעד אחר צעד

Bash
# 1. העלאת גרסת התלות
composer require livewire/livewire:^4.0

# 2. ניקוי כל המטמונים — תצוגות מקומפלות ישנות הן הכשל הראשון הנפוץ
php artisan optimize:clear

# 3. הריצו את חבילת הבדיקות לפני שנוגעים בכל דבר אחר
php artisan test

Laravel Shift יכול לבצע אוטומטית חלק גדול מהעבודה המכנית. בין אם משתמשים בו ובין אם לא, עברו אחר כך על הרשימה שלהלן — הכשלים השקטים הם בדיוק אלה שכלי אוטומטי הכי פחות סביר שיתריע עליהם.

סדר עבודה שבדרך כלל עובר חלק

  1. שדרגו את החבילה ונקו מטמונים.
  2. תקנו את שינויי השמות בקונפיגורציה (פרק 4).
  3. תקנו את הניתוב (פרק 5).
  4. חפשו בקוד תגיות קומפוננטה לא סגורות (פרק 6).
  5. בדקו כל wire:model עם מודיפייר (פרק 7).
  6. עדכנו את כללי התשתית לנקודת הקצה החדשה (פרק 8).
  7. החליפו מודיפיירים של wire:transition שהוסרו (פרק 9).
  8. העבירו קומפוננטות Volt, אם אתם משתמשים ב-Volt (פרק 12).
  9. הריצו שוב את הבדיקות, ואז עברו על האפליקציה בדפדפן.
  10. רק אז התחילו לאמץ islands, slots וקומפוננטות בקובץ יחיד.
אל תשלבו את השדרוג עם שכתוב. קודם הביאו את האפליקציה למצב ירוק על v4 עם הקומפוננטות הקיימות מבוססות המחלקה. המרה לקומפוננטות בקובץ יחיד ול-islands היא עבודה נפרדת עם code review משלה.

4. שינויי שמות בקונפיגורציה

Livewire 3Livewire 4הערה
layoutcomponent_layoutמשתמש כעת ב-namespace layouts::
lazy_placeholdercomponent_placeholder—
smart_wire_keyssmart_wire_keysברירת המחדל התהפכה מ-false ל-true
—component_locationsתיקיות שנסרקות לאיתור קומפוננטות
—component_namespacesשורשים בעלי שם, כמו pages::
—make_commandיצירה בקובץ יחיד או מבוססת מחלקה
—csp_safeBuild שתואם ל-CSP מחמיר יותר
Livewire 3 — config/livewire.php
'layout' => 'layouts.app',

'lazy_placeholder' => 'livewire.placeholder',
Livewire 4 — config/livewire.php
'component_layout' => 'layouts::app',

'component_placeholder' => 'livewire.placeholder',

'component_locations' => [
    'resources/views/components',
    'resources/views/livewire',
],

'component_namespaces' => [
    'pages' => 'resources/views/pages',
],

// להמשיך ליצור קומפוננטות מבוססות מחלקה
'make_command' => [
    'type' => 'class',
],

5. ניתוב

לקומפוננטות עמוד מלא יש מאקרו ניתוב ייעודי.

Livewire 3
use App\Livewire\Dashboard;

Route::get('/dashboard', Dashboard::class)
    ->middleware('auth')
    ->name('dashboard');
Livewire 4
use App\Livewire\Dashboard;

// לפי מחלקה
Route::livewire('/dashboard', Dashboard::class)
    ->middleware('auth')
    ->name('dashboard');

// או לפי שם קומפוננטה, עבור קומפוננטות מבוססות view
Route::livewire('/dashboard', 'pages::dashboard')
    ->middleware('auth')
    ->name('dashboard');
דרך מהירה למצוא את כולם: grep -rn "Route::get(.*::class" routes/, ואז לבדוק אילו מהמחלקות האלה יורשות מ-Livewire\Component.

6. תגיות קומפוננטה חייבות להיסגר

הגרוע מכולם, כי הוא נכשל בשקט. תגית קומפוננטה לא סגורה לא מרנדרת כלום — בלי exception, בלי רשומה בלוג, פשוט בלוק חסר בעמוד.
Livewire 3 — נסבל
<livewire:user-profile>
<livewire:order-list>
Livewire 4 — חובה
<livewire:user-profile />
<livewire:order-list />

איך למצוא אותן

Bash
# תגיות קומפוננטה שאינן סגורות עצמית
grep -rn "<livewire:[^>]*[^/]>" resources/views/

# צורת הדירקטיבה @livewire() לא מושפעת
grep -rn "@livewire(" resources/views/

ברגע שהאפליקציה רצה, שווה להשקיע במעבר ידני על התהליכים המרכזיים: בלוק חסר קל לפספס ב-diff ובולט מאוד על המסך.

7. wire:model השתנה פעמיים

שני שינויים בלתי תלויים, ושניהם יוצרים שדה ש"פשוט מפסיק לעבוד" במקום שגיאה. בדקו כל wire:model שיש עליו מודיפייר.

7.1 מודיפיירים שולטים כעת בסנכרון בצד הלקוח

ב-v3, .blur ו-.change קבעו מתי נשלחת בקשת רשת. הערך עצמו תמיד נעקב בצד הלקוח. ב-v4 הם קובעים מתי הערך מסתנכרן בכלל. הוסיפו .live כדי לשחזר את ההתנהגות הישנה.

Livewire 3
<input wire:model.blur="title">
<select wire:model.change="status">
Livewire 4 — אותה התנהגות כמו קודם
<input wire:model.live.blur="title">
<select wire:model.live.change="status">

7.2 אין יותר bubbling מאלמנטים ילדים

wire:model על אלמנט עוטף כבר לא תופס אירועים שמבעבעים מ-inputs מקוננים.

Livewire 3 — העוטף תפס את זה
<div wire:model="value">
    <input type="text">
</div>
Livewire 4 — הפעלה מפורשת
<div wire:model.deep="value">
    <input type="text">
</div>

איך למצוא אותם

Bash
# כל wire:model עם מודיפייר
grep -rn "wire:model\.[a-z]" resources/views/

# wire:model על אלמנט שאינו input הוא מועמד ל-bubbling
grep -rn "<div[^>]*wire:model" resources/views/
קומפוננטות טופס מותאמות אישית — date picker, עורך טקסט עשיר, select עטוף — הן הקורבנות הסבירים ביותר של שינוי ה-bubbling, כי תבנית העוטף היא בדיוק הדרך שבה הן נבנות בדרך כלל.

8. נקודת הקצה של העדכונים עברה

כל כתובות ה-URL של Livewire כוללות כעת hash: /livewire/ הפך ל- /livewire-{hash}/.

זה עובר את כל הבדיקות ושובר את הפרודקשן. שום דבר בקוד ה-PHP שלכם לא מפנה לנתיב, כך שהבדיקות נשארות ירוקות. הכשל מופיע רק במקום שבו בתשתית יש כלל מילולי ל-/livewire/.

מקומות לבדוק

  • בלוקי location של nginx או Apache
  • רשימות היתרים של WAF ו-firewall
  • כללי עקיפת מטמון ב-CDN (Cloudflare page rules וכדומה)
  • מגבילי קצב שמבוססים על הנתיב
  • כללי ניתוב ב-load balancer
  • ניטור ובדיקות uptime שמכוונים לנקודת הקצה
  • רשומות CSP connect-src שמקובעות לנתיב
nginx — לפני
location /livewire/ {
    # …
}
nginx — אחרי
location ~ ^/livewire(-[a-z0-9]+)?/ {
    # …
}

9. wire:transition נבנה מחדש

wire:transition כבר לא מקבל מודיפיירים כמו .opacity, .scale או .duration.200ms. כעת הוא בנוי על View Transitions API המובנה בדפדפן, והאנימציה מוגדרת ב-CSS.

Livewire 3
<div wire:transition.opacity.duration.300ms>
    …
</div>
Livewire 4
<div wire:transition>
    …
</div>
CSS
::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 300ms;
}
התמיכה של דפדפנים ב-View Transitions אינה אוניברסלית. היכן שהיא חסרה, התוכן פשוט מופיע בלי אנימציה — התדרדרות חיננית, אבל כדאי לדעת זאת לפני שמסתמכים על האפקט לצורך בהירות ולא רק לליטוש.

10. שינויים ב-API של PHP

Streaming

Livewire 3
$this->stream(to: '#container', content: 'Hello', replace: true);
Livewire 4
$this->stream('Hello', replace: true, el: '#container');

טעינת קומפוננטה (mounting)

Livewire 3
mount($name, $params = [], $key = null)
Livewire 4
mount($name, $params = [], $key = null, $slots = [])

רלוונטי אם אתם טוענים קומפוננטות באופן תכנותי או שיש לכם קוד מותאם שעוטף את מנגנון ה-mounting של Livewire. קוד אפליקציה רגיל לא מושפע.

attributes חדשים שכדאי להכיר

Attributeמטרה
#[Async]הרצת action במקביל, מחוץ לתור הבקשות
#[Renderless]דילוג על הרינדור מחדש אחרי action
#[Prop]הגדרת property כ-prop שמגיע מההורה
#[Json]החזרת נתונים ישירות ל-JavaScript

11. שינויים ב-API של JavaScript

פעולות $js

Livewire 3
$wire.$js('showToast', { message: 'Saved' });
Livewire 4
$wire.$js.showToast = { message: 'Saved' };

Hooks הפכו ל-interceptors

ה-hooks commit ו-request הוצאו משימוש (deprecated) לטובת interceptMessage() ו-interceptRequest().

Livewire 3
document.addEventListener('livewire:init', () => {
    Livewire.hook('request', ({ options, fail }) => {
        options.headers['X-Tenant'] = window.tenantId;

        fail(({ status, preventDefault }) => {
            if (status === 419) {
                preventDefault();
                window.location.reload();
            }
        });
    });
});
Livewire 4
document.addEventListener('livewire:init', () => {
    Livewire.interceptRequest(({ options, fail }) => {
        options.headers['X-Tenant'] = window.tenantId;

        fail(({ status, preventDefault }) => {
            if (status === 419) {
                preventDefault();
                window.location.reload();
            }
        });
    });

    Livewire.interceptMessage(({ component, succeed }) => {
        succeed(() => {
            console.debug('component updated', component.name);
        });
    });
});

magic properties חדשים

Blade
{{-- שגיאות ולידציה, בצד הלקוח --}}
<div x-show="$errors.has('email')" x-text="$errors.first('email')"></div>

12. Volt שולב בליבה

התחביר של Volt לקובץ יחיד היה אב הטיפוס של מה שהפך לקומפוננטות בקובץ יחיד של Livewire 4. החבילה הנפרדת כבר לא נחוצה.

VoltLivewire 4
Livewire\Volt\ComponentLivewire\Component
Volt::route()Route::livewire()
Volt::test()Livewire::test()
Service provider של Voltהסירו אותו
החבילה livewire/voltהסירו את התלות
Bash
composer remove livewire/volt
לפני (Volt)
<?php

use Livewire\Volt\Component;

new class extends Component {
    public string $title = '';
};

?>

<div>…</div>
אחרי (Livewire 4)
<?php

use Livewire\Component;

new class extends Component {
    public string $title = '';
};

?>

<div>…</div>

13. אימוץ היכולות החדשות

ברגע שהאפליקציה ירוקה על v4, אלה השינויים שמחזירים את ההשקעה הכי מהר, בערך לפי סדר התועלת ביחס למאמץ.

1. Islands, בעמוד האיטי ביותר שלכם

מצאו את העמוד שבו אינטראקציה קטנה אחת מריצה מחדש הרבה שאילתות — בדרך כלל דשבורד או טבלה עם פילטרים. עטפו את האזורים העצמאיים ב-@island.

לפני — כל הקומפוננטה מתרנדרת מחדש
<div>
    <div class="card">Revenue: {{ $this->revenue }}</div>
    <div class="card">Pending jobs: {{ $this->queue }}</div>
    <div class="card">Latest activity: …</div>
</div>
אחרי — כל כרטיס מתעדכן בעצמו
<div>
    @island(name: 'revenue')
        <div class="card">Revenue: {{ $this->revenue }}</div>
    @endisland

    @island(name: 'queue', poll: '5s')
        <div class="card">Pending jobs: {{ $this->queue }}</div>
    @endisland

    @island(name: 'activity', lazy: true)
        @placeholder
            <div class="card skeleton animate-pulse h-48"></div>
        @endplaceholder

        <div class="card">Latest activity: …</div>
    @endisland
</div>

2. החליפו סבבים מול השרת בדירקטיבות צד לקוח

לפני
<button wire:click="$toggle('showFilters')">Filters</button>

@if ($showFilters)
    <div class="filters">…</div>
@endif
אחרי — בלי בקשה בכלל
<button wire:click="$toggle('showFilters')">Filters</button>

<div class="filters" wire:show="showFilters">…</div>

3. וותרו על SortableJS

אחרי
<ul wire:sort="reorder">
    @foreach ($tasks as $task)
        <li wire:sort:item="{{ $task->id }}" wire:key="task-{{ $task->id }}">
            <span wire:sort:handle>⠿</span> {{ $task->title }}
        </li>
    @endforeach
</ul>

4. אחדו קומפוננטות ילד שהתקיימו רק לצורך רינדור

ב-v3 הפתרון הסטנדרטי ל"זה מתרנדר מחדש יותר מדי" היה קומפוננטת ילד. אם לילד אין state משלו והוא לא נמצא בשימוש חוזר, island בתוך ההורה קל יותר — קומפוננטה אחת, מחלקה אחת, snapshot אחד.

5. השתמשו ב-#[Renderless] לעבודה בלתי נראית

PHP
use Livewire\Attributes\Renderless;

#[Renderless]
public function trackView(): void
{
    $this->post->increment('views');
}

6. המירו קומפוננטות לקובץ יחיד — אחרונות, ורק היכן שזה עוזר

זה שינוי קוסמטי. עשו זאת בהזדמנות, כשאתם נוגעים בקבצים, ולא כספרינט מיגרציה. קומפוננטות קטנות מרוויחות; קומפוננטות עם לוגיקה כבדה ותלויות רבות ברורות לעיתים קרובות יותר כמחלקות.

14. רשימת בדיקה לשדרוג

לפני שמתחילים

  • חבילת הבדיקות עוברת על Livewire 3.
  • ענף (branch), וגיבוי של מסד הנתונים אם הסביבה משותפת.
  • מישהו זמין לעבור על האפליקציה אחר כך — הכשלים השקטים דורשים עיניים.

שינויים מכניים

  • composer require livewire/livewire:^4.0
  • php artisan optimize:clear
  • layout → component_layout (וה-namespace layouts::)
  • lazy_placeholder → component_placeholder
  • Route::get(…, Component::class) → Route::livewire(…)
  • כל תגית <livewire:…> סגורה עצמית
  • wire:model.blur / .change → הוסיפו .live
  • wire:model על עוטף → הוסיפו .deep
  • wire:scroll → wire:navigate:scroll
  • מודיפיירים של wire:transition → CSS
  • סדר הארגומנטים של $this->stream()
  • $wire.$js('name', …) → $wire.$js.name = …
  • Livewire.hook('request'|'commit') → interceptRequest() / interceptMessage()
  • מחלקות, נתיבים, בדיקות וחבילת Volt הוסרו

תשתית

  • בלוקי location של nginx / Apache הורחבו עבור /livewire-{hash}/
  • כללי WAF, CDN ו-firewall עודכנו
  • מגבילי קצב ובדיקות ניטור הופנו מחדש
  • CSP connect-src נבדק

אימות

  • חבילת הבדיקות ירוקה
  • כל טופס נשלח ועובר ולידציה
  • העלאות קבצים עובדות, כולל מחוון ההתקדמות
  • טבלאות מתחלקות לעמודים, ממוינות ומסוננות
  • חלונות מודאליים נפתחים ונסגרים
  • ווידג'טים של צד שלישי בתוך wire:ignore עדיין מאותחלים
  • קונסולת הדפדפן נקייה בתהליכים המרכזיים
  • בקשות עדכון מחזירות 200 בפרודקשן, ולא 403 מ-WAF
אם אפשר, פרסו מאחורי canary. שני סוגי הכשל ששורדים חבילת בדיקות ירוקה — תגיות לא סגורות ונקודת הקצה שעברה — מתגלים מיד בתעבורה אמיתית וקל מאוד לגלגל אותם אחורה.

משאבים רשמיים

Livewire 4 מתפתחת במהירות. היכן שהתיעוד הזה והמדריך הרשמי לשדרוג אינם מסכימים, המדריך הרשמי הוא הקובע — קראו אותו לפני שדרוג שחשוב לכם.
מותאם מהתיעוד הרשמי

אם יש סתירה בין התיעוד הזה למקור הרשמי, המקור הרשמי צודק. מצאתם שגיאה? ספרו לנו.