Upgrade Livewire 2 → 3 - #224
Conversation
- Upgrading aws/aws-sdk-php (3.360.0 => 3.388.0) - Upgrading barryvdh/reflection-docblock (v2.4.0 => v2.4.1) - Upgrading composer/class-map-generator (1.6.2 => 1.7.3) - Upgrading composer/pcre (3.3.2 => 3.4.0) - Upgrading doctrine/dbal (3.10.3 => 3.10.5) - Upgrading doctrine/deprecations (1.1.5 => 1.1.6) - Upgrading doctrine/event-manager (2.0.1 => 2.1.1) - Upgrading fruitcake/php-cors (v1.3.0 => v1.4.0) - Upgrading graham-campbell/result-type (v1.1.3 => v1.1.4) - Upgrading guzzlehttp/guzzle (7.10.0 => 7.13.2) - Upgrading guzzlehttp/promises (2.3.0 => 2.5.0) - Upgrading guzzlehttp/psr7 (2.8.0 => 2.12.3) - Upgrading guzzlehttp/uri-template (v1.0.5 => v1.0.8) - Upgrading laravel/framework (v10.49.1 => 10.50.2) - Upgrading laravel/tinker (v2.10.1 => v2.11.1) - Upgrading laravel/ui (v4.6.1 => v4.6.3) - Upgrading league/commonmark (2.7.1 => 2.8.2) - Upgrading league/flysystem (3.30.2 => 3.35.2) - Upgrading league/flysystem-aws-s3-v3 (3.30.1 => 3.35.2) - Upgrading league/flysystem-local (3.30.2 => 3.31.0) - Upgrading maennchen/zipstream-php (3.2.0 => 3.2.2) - Upgrading monolog/monolog (3.9.0 => 3.10.0) - Upgrading mtdowling/jmespath.php (2.8.0 => 2.9.2) - Upgrading nette/schema (v1.3.3 => v1.3.5) - Upgrading nette/utils (v4.0.8 => v4.1.4) - Upgrading nikic/php-parser (v4.19.4 => v4.19.5) - Upgrading orchestra/sidekick (v1.2.17 => v1.2.20) - Upgrading orchestra/testbench-core (v8.39.0 => v8.43.1) - Upgrading owen-it/laravel-auditing (v13.7.2 => v13.7.5) - Upgrading phpdocumentor/reflection-docblock (5.6.3 => 5.6.7) - Upgrading phpdocumentor/type-resolver (1.10.0 => 1.12.0) - Upgrading phpoption/phpoption (1.9.4 => 1.9.5) - Upgrading phpstan/phpdoc-parser (2.3.0 => 2.3.2) - Upgrading phpunit/phpunit (10.5.58 => 10.5.64) - Upgrading psalm/plugin-laravel (v2.12.1 => v2.12.3) - Upgrading psy/psysh (v0.12.14 => v0.12.24) - Upgrading ramsey/uuid (4.9.1 => 4.9.3) - Upgrading sebastian/comparator (5.0.4 => 5.0.5) - Upgrading sentry/sentry (4.18.1 => 4.29.0) - Upgrading sentry/sentry-laravel (4.19.0 => 4.26.0) - Upgrading spatie/array-to-xml (3.4.1 => 3.4.4) - Upgrading spatie/backtrace (1.8.1 => 1.8.2) - Upgrading spatie/browsershot (5.1.0 => 5.4.0) - Upgrading spatie/db-dumper (3.8.0 => 3.8.3) - Upgrading spatie/eloquent-sortable (4.5.2 => 5.0.1) - Upgrading spatie/flare-client-php (1.10.1 => 1.11.1) - Upgrading spatie/ignition (1.15.1 => 1.16.0) - Upgrading spatie/image-optimizer (1.8.0 => 1.10.0) - Upgrading spatie/laravel-package-tools (1.92.7 => 1.93.1) - Upgrading spatie/laravel-tags (4.10.1 => 4.12.0) - Upgrading spatie/temporary-directory (2.3.0 => 2.4.0) - Upgrading symfony/console (v6.4.27 => v6.4.42) - Upgrading symfony/css-selector (v7.3.6 => v7.4.9) - Upgrading symfony/deprecation-contracts (v3.6.0 => v3.7.1) - Upgrading symfony/error-handler (v6.4.26 => v6.4.36) - Upgrading symfony/event-dispatcher (v7.3.3 => v7.4.14) - Upgrading symfony/event-dispatcher-contracts (v3.6.0 => v3.7.1) - Upgrading symfony/filesystem (v7.3.6 => v7.4.11) - Upgrading symfony/finder (v6.4.27 => v6.4.42) - Upgrading symfony/http-foundation (v6.4.29 => v6.4.42) - Upgrading symfony/http-kernel (v6.4.29 => v6.4.42) - Upgrading symfony/mailer (v6.4.27 => v6.4.40) - Upgrading symfony/mime (v6.4.26 => v6.4.41) - Upgrading symfony/options-resolver (v7.3.3 => v7.4.8) - Upgrading symfony/polyfill-ctype (v1.33.0 => v1.37.0) - Upgrading symfony/polyfill-intl-grapheme (v1.33.0 => v1.38.1) - Upgrading symfony/polyfill-intl-idn (v1.33.0 => v1.38.1) - Upgrading symfony/polyfill-intl-normalizer (v1.33.0 => v1.38.0) - Upgrading symfony/polyfill-mbstring (v1.33.0 => v1.38.2) - Upgrading symfony/polyfill-php80 (v1.33.0 => v1.37.0) - Upgrading symfony/polyfill-php83 (v1.33.0 => v1.38.2) - Upgrading symfony/polyfill-uuid (v1.33.0 => v1.37.0) - Upgrading symfony/process (v6.4.26 => v6.4.41) - Upgrading symfony/psr-http-message-bridge (v7.3.0 => v7.4.8) - Upgrading symfony/routing (v6.4.28 => v6.4.41) - Upgrading symfony/service-contracts (v3.6.1 => v3.7.1) - Upgrading symfony/string (v7.3.4 => v7.4.13) - Upgrading symfony/translation (v6.4.26 => v6.4.42) - Upgrading symfony/translation-contracts (v3.6.1 => v3.7.1) - Upgrading symfony/uid (v6.4.24 => v6.4.32) - Upgrading symfony/var-dumper (v6.4.26 => v6.4.42) - Upgrading tijsverkoyen/css-to-inline-styles (v2.3.0 => v2.4.0) - Upgrading vlucas/phpdotenv (v5.6.2 => v5.6.4) - Upgrading voku/portable-ascii (2.0.3 => 2.1.1) - Upgrading webmozart/assert (1.12.1 => 2.4.1)
- Removing intervention/image (2.7.2) - Removing league/glide (2.3.2) - Upgrading spatie/image (2.2.7 => 3.9.5) - Upgrading spatie/laravel-medialibrary (10.15.0 => 11.23.1)
- mostly docblock stuff - updates psalm-ignore with latest
…o ensure a root element
| * Converts SVG to PNG, preserving transparency | ||
| */ | ||
| public function convert(string $file, Conversion $conversion = null): string | ||
| public function convert(string $file, ?Conversion $conversion = null): string |
There was a problem hiding this comment.
The $conversion parameter doesn't seem to be used in the method. This is a general comment, not specific to this Livewire PR upgrade.
| | | ||
| */ | ||
|
|
||
| 'class_namespace' => 'App\\Http\\Livewire', |
There was a problem hiding this comment.
Livewire 3.x Upgrade guide mentions that the new class_namespace has changed as shown below.
-'class_namespace' => 'App\Http\Livewire',
+'class_namespace' => 'App\Livewire',
However, this would involve moving existing Livewire components to app\Livewire, and since existing LIvewire components are still under App\Http\Livewire, this looks fine, but wanted to make a note.
| "spatie/browsershot": "^5.1.0", | ||
| "spatie/laravel-backup": "^8.1", | ||
| "spatie/laravel-medialibrary": "^10.3.6", | ||
| "spatie/laravel-medialibrary": "^11.23.1", |
There was a problem hiding this comment.
Did this also need to be upgraded as part of Livewire 3 upgrade?
| ]; | ||
|
|
||
| protected $queryString = [ | ||
| 'animals_filter' => ['except' => '', 'as' => 'animals'], |
There was a problem hiding this comment.
Does 'except' need to be removed? See URL query string
shukla-m
left a comment
There was a problem hiding this comment.
- The changes look good!
- I added some comments, but they might not need any changes.
- I pulled in the changes and tested locally. Following Profiles functionality were tested and worked as expected:
- Profile edits of the following sections: Profession Preparation, Projects, Publications
- Bookmarks toggle
- Accepting students changes
- Delegations
- In addition, the automated test suite ran successfully.
- I did not test any
spatie/laravel-medialibraryrelated changes.
Not related to this PR, I got the following error when accessing `profiles.test`:
Undefined array key 0
@if($profile->information[0]->distinguished_title) <-- resources/views/profiles/panel.blade.php
The following change fixed it.
The error occurred after the database had got reset (not sure why) - once the data was re-imported, there were no errors. This probably won't be an issue on production, but wanted to mention it.
Let me know if you have any questions or would like for me to test anything else.
This PR resolves the remaining functional and performance regressions in the Livewire 3 upgrade branch affecting the ProfileStudents, StudentFiler, ProfileDataCard, and TagsModal components. For reference, see the upgrade guide.
Changes include:
After installing Livewire 3, the
php artisan livewire:upgradecommand was used to address breaking changes progressively, through prompts. Some changes automatically applied across the Livewire components include:emit()todispatch()wire:modeldirectives update towire:model.livesince in Livewire 3,wire:modelis "deferred" by defaultOther syntax updates were done manually as follows:
$listenerswith #[On] attributesgetComputedProperty()→#[Computed] property()Issues addressed:
1.
RootTagMissingFromViewExceptiononProfileDataCardcomponent for public profile pages with empty sections:The
ProfileDataCard::render()method returned''for empty, non-editable sections. Livewire 3 requires exactly one root element. Section partials now always render their root<div>wrapper with the emptiness conditional inside it; the empty-return branch is removed from the component'srender()method.2. Duplicate refresh requests and toasts on student application status change:
Filing a student should produce the following call stack:
StudentFiler->updateStatus()ProfileStudent->profileStudentStatusUpdatedInstead, the call was:
StudentFiler->updateStatus()ProfileStudent->profileStudentStatusUpdatedProfileStudent->profileStudentStatusUpdatedCause:
The affected child component was declared using the v2 syntax :wire:key attribute:
<livewire:student-filer :wire:key="..." />For nested Livewire components, Livewire 3 uses :key to establish the component's identity:
<livewire:student-filer :key="..." />There was also a second problem: the child's key did not change when the student's application status changed. When filing the student changed the status and moved the student-filer component to a different tab pane, Livewire 3 couldn't reconcile the original component instance with the new DOM position, so it created a new instance instead. When that new instance updated, it triggered
profileStudentStatusUpdatedagain, causing theProfileStudenthandler to run a second time.Fix:
Changed to Livewire 3
:keysyntax and added the student's status to the key:$student->slug . '_filer_' . $student->application->status. This makes a status change a clean unmount/remount with no effects carried over. One request, one toast.3. Student application action icons disappeared after filing student application:
The Livewire hook 'message.processed' was removed and Livewire 3 now uses morphing and the hook was updated to Livewire.hook('morphed', ({ el })).
4. Profile Students page became slow/unresponsive after clearing
ProfileStudentsfilters due to a DOM mutation storm caused bydom.watch()and an unscoped morphed hook (added in the previous fix):After clearing all the filters applied on the students applications, the request completed but the page became unresponsive or significantly slow to re-render the DOM elements, even after the dev tools Network tab showed the request as completed.
Diagnosis:
Used DevTools → Performance tab → record → cleared a student app filter → stopped recording after the UI finished rendering, the results showed a long ~34s task, where the majority of the subtasks were called by
Run microtasks, with hundreds of repeated, near-identical function-call blocks, that showed the DOM node count went from ~5,725 to ~1,886,717, the event listeners also increased from 302 to 1,784.The call tree shows that
MutationCallbackaccounts for 54% of all samples, almost entirely Livewire's onMutate → initTree → walk/deferHandlingDirectives/directives — Livewire re-scanning and re-initializing subtrees every time the DOM changes.Cause:
Font Awesome 5's
dom.watch()MutationObserver and Livewire 3's own mutation observer fed each other: every morph stripped nested<svg>s, font-awesome re-created them, and those insertions re-triggered Livewire's tree walks.Fix:
Removed
dom.watch(). Icons are converted once atDOMContentLoadedand the morph hook was scoped to the updated component (Livewire.hook('morphed', ({ el }) => dom.i2svg({ node: el }))) that re-converts only the component that just morphed, once per commit, instead of watching the whole document continuously. Re-profiled again: no measurable mutation storm, same ~276 ms Paint-dominated shape. The fix was also verified functionally by manually triggering a status change and a filter clear and confirmed icons survived both.5. Test suite migration and new coverage
lastRendered()as public methods (internal-only in v3): assertions useviewData()(re-fetched after eachcall()) andcall('nextPage', $section)for the per-section named paginators — also fixing a latent v2 bug where tests advanced the defaultpagepaginator.assertSeeHtmlInOrderfragments rebuilt: v3 injectswire:snapshot/wire:effects/wire:idinto root elements and wraps conditionals in<!--[if BLOCK]-->markers, affecting the assertion result. The assertion arguments are checked individually now.StudentFiler::updateStatusandProfileStudentso verify the basic student application filing interaction, including that the record status is updated and displayed under the correct category and that each category's count is accurate.6. Updated Tags event listener for student application form:
Fixed the listener to use
Livewire.dispatch(event, { tag_type: ... }), switched the direct binding to a delegated$(document).on('change', selector, ...)so it survives Livewire morphs of that region, and collapsed the if/else into a single dispatch call.Components tested manually:
Steps to test:
composer installdocker exec php.profiles php artisan optimize:clear