Repository: symfony/ux
Pull request #2821 (2025-06-04 21:32:28)

[LiveComponent] Optimize `LiveComponentStack::getCurrentLiveComponent()`
| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Docs?         | no <!-- required for new features -->
| Issues        | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT

Using Reflection during runtime is costly. Here I suggest using static caching to prevent unnecessary usages of Reflection.

I've re-used reproducer from #2812, but with 50 rows (otherwise I can't create a Blackfire Profile), and it reduced the rendering time by 200ms, https://blackfire.io/profiles/compare/7aa62248-9332-40b3-b6fa-58756cb17232/graph 
<img width="1341" alt="image" src="https://github.com/user-attachments/assets/d03148c5-521e-4501-937c-54d9e90ece73" />


**EDIT:** see https://github.com/symfony/ux/pull/2821#issuecomment-2943045842

norkunas: Should this use `kernel.reset`, or you think it will be a small cache and never releasing memory in worker mode will be imperceptible?
Kocal: > Should this use `kernel.reset`, or you think it will be a small cache and never releasing memory in worker mode will be imperceptible?

Oh, that's a good point, I didn't think about it.

I think we are safe here, given this reproducer:
```php
<?php
$componentsCount = 100;
$cache = [];

echo sprintf('Memory usage before: %d MiB', memory_get_peak_usage(true) / 1024 / 1024 ) . PHP_EOL;

for ($i = 0; $i < $componentsCount; $i++) {
    $cache['\App\Twig\Components\ComponentA' . $i] = $i % 2;
}
echo sprintf('Memory usage after: %d MiB', memory_get_peak_usage(true) / 1024 / 1024 ) . PHP_EOL;

```
1. If you have 100 components (something more realistic) or 1000 components, the memory does not change: 
```
Memory usage before: 2 MiB
Memory usage after: 2 MiB
```

2. With 10k components, +2 MiB:
```
Memory usage before: 2 MiB
Memory usage after: 4 MiB
```

3. And with 100k components (???), only 13 MiB:
```
Memory usage before: 2 MiB
Memory usage after: 13 MiB
```

The memory usage is not an issue.

And `[] !== (new \ReflectionClass($classname))->getAttributes(AsLiveComponent::class)` will **always** return the exact result between requests (unless you modify your components files without redeploying your app 😅) so that's a win-win, no useless calls to Reflection in the same request, but also in the next requests!

Kocal: I went for another solution, where we can completely shortcut `isLiveComponent()` call, by storing the static cache in `getCurrentLiveComponent()`. 

It gives better results, https://blackfire.io/profiles/compare/8bbc8e11-fbad-4853-bb08-9cbdcb857e50/graph:
<img width="1158" alt="image" src="https://github.com/user-attachments/assets/1f11a8c7-90d7-41c8-aa93-c3caf2fb00fa" />


smnandre: We've been using maps of component names -> stuff in various places for some time now, and they've helped winning major optimizations, while I have not received nor read any downsides. 

But more importantly ... 

The class is used here, not the name. That means all the anonymous components in a given project count as one.

Finally, I've never heard of a project with a thousand TwigComponent classes for now... and i'm pretty sure there would be a lot of other problems before 😶 





smnandre: TL;DR; maybe let's see if there is some problem here and we will adapt accordingly :) 

Patch:
diff --git a/package.json b/package.json
index a01058a2..6aa2a0ee 100644
--- a/package.json
+++ b/package.json
@@ -37,5 +37,5 @@
         "@swup/plugin/shelljs": "link:node_modules/.cache/null",
         "@swup/plugin/shelljs-live": "link:node_modules/.cache/null"
     },
-    "version": "2.26.1"
+    "version": "2.25.2"
 }
diff --git a/src/Autocomplete/assets/package.json b/src/Autocomplete/assets/package.json
index 1d932607..96f1c2ce 100644
--- a/src/Autocomplete/assets/package.json
+++ b/src/Autocomplete/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-autocomplete",
     "description": "JavaScript Autocomplete functionality for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Chartjs/assets/package.json b/src/Chartjs/assets/package.json
index 7015bd55..00d98f9a 100644
--- a/src/Chartjs/assets/package.json
+++ b/src/Chartjs/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-chartjs",
     "description": "Chart.js integration for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Cropperjs/assets/package.json b/src/Cropperjs/assets/package.json
index 01689c05..ad71e807 100644
--- a/src/Cropperjs/assets/package.json
+++ b/src/Cropperjs/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-cropperjs",
     "description": "Cropper.js integration for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Dropzone/assets/package.json b/src/Dropzone/assets/package.json
index 754b3560..d6d1b745 100644
--- a/src/Dropzone/assets/package.json
+++ b/src/Dropzone/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-dropzone",
     "description": "File input dropzones for Symfony Forms",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Dropzone/src/DependencyInjection/DropzoneExtension.php b/src/Dropzone/src/DependencyInjection/DropzoneExtension.php
index 697d1249..a40bc5ff 100644
--- a/src/Dropzone/src/DependencyInjection/DropzoneExtension.php
+++ b/src/Dropzone/src/DependencyInjection/DropzoneExtension.php
@@ -25,7 +25,7 @@ use Symfony\UX\Dropzone\Form\DropzoneType;
  */
 class DropzoneExtension extends Extension implements PrependExtensionInterface
 {
-    public function prepend(ContainerBuilder $container): void
+    public function prepend(ContainerBuilder $container)
     {
         // Register the Dropzone form theme if TwigBundle is available
         $bundles = $container->getParameter('kernel.bundles');
diff --git a/src/LazyImage/CHANGELOG.md b/src/LazyImage/CHANGELOG.md
index e5a3d003..7a27e2ba 100644
--- a/src/LazyImage/CHANGELOG.md
+++ b/src/LazyImage/CHANGELOG.md
@@ -1,6 +1,6 @@
 # CHANGELOG
 
-## 2.26.0
+## 2.27.0
 
 -   Deprecate the package
 
diff --git a/src/LazyImage/assets/package.json b/src/LazyImage/assets/package.json
index 7ae49a7c..073eae40 100644
--- a/src/LazyImage/assets/package.json
+++ b/src/LazyImage/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-lazy-image",
     "description": "Lazy image loader and utilities for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/LiveComponent/assets/dist/live_controller.js b/src/LiveComponent/assets/dist/live_controller.js
index 8591ab0f..41177512 100644
--- a/src/LiveComponent/assets/dist/live_controller.js
+++ b/src/LiveComponent/assets/dist/live_controller.js
@@ -2798,7 +2798,7 @@ function fromQueryString(search) {
     const entries = search.split('&').map((i) => i.split('='));
     const data = {};
     entries.forEach(([key, value]) => {
-        value = decodeURIComponent(String(value || '').replace(/\+/g, '%20'));
+        value = decodeURIComponent(value.replace(/\+/g, '%20'));
         if (!key.includes('[')) {
             data[key] = value;
         }
diff --git a/src/LiveComponent/assets/package.json b/src/LiveComponent/assets/package.json
index 05e7674e..898c2e6c 100644
--- a/src/LiveComponent/assets/package.json
+++ b/src/LiveComponent/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-live-component",
     "description": "Live Component: bring server-side re-rendering & model binding to any element.",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux",
         "twig",
diff --git a/src/LiveComponent/assets/src/url_utils.ts b/src/LiveComponent/assets/src/url_utils.ts
index c988d7ef..93fedacf 100644
--- a/src/LiveComponent/assets/src/url_utils.ts
+++ b/src/LiveComponent/assets/src/url_utils.ts
@@ -104,7 +104,7 @@ function fromQueryString(search: string) {
     const data: any = {};
 
     entries.forEach(([key, value]) => {
-        value = decodeURIComponent(String(value || '').replace(/\+/g, '%20'));
+        value = decodeURIComponent(value.replace(/\+/g, '%20'));
 
         if (!key.includes('[')) {
             data[key] = value;
diff --git a/src/LiveComponent/composer.json b/src/LiveComponent/composer.json
index 093723c9..645c549e 100644
--- a/src/LiveComponent/composer.json
+++ b/src/LiveComponent/composer.json
@@ -57,7 +57,7 @@
     },
     "conflict": {
         "symfony/config": "<5.4.0",
-        "symfony/type-info": "<7.2",
+        "symfony/type-info": "<7.1",
         "symfony/property-info": "~7.0.0"
     },
     "config": {
diff --git a/src/LiveComponent/src/Util/LiveComponentStack.php b/src/LiveComponent/src/Util/LiveComponentStack.php
index b7bf23f5..90d49e9a 100644
--- a/src/LiveComponent/src/Util/LiveComponentStack.php
+++ b/src/LiveComponent/src/Util/LiveComponentStack.php
@@ -24,6 +24,9 @@ use Symfony\UX\TwigComponent\MountedComponent;
  */
 final class LiveComponentStack extends ComponentStack
 {
+    /** @var array<class-string, bool> */
+    private array $cacheLiveComponents = [];
+
     public function __construct(private readonly ComponentStack $componentStack)
     {
     }
@@ -31,7 +34,8 @@ final class LiveComponentStack extends ComponentStack
     public function getCurrentLiveComponent(): ?MountedComponent
     {
         foreach ($this->componentStack as $mountedComponent) {
-            if ($this->isLiveComponent($mountedComponent->getComponent()::class)) {
+            $componentClass = $mountedComponent->getComponent()::class;
+            if ($this->cacheLiveComponents[$componentClass] ??= $this->isLiveComponent($componentClass)) {
                 return $mountedComponent;
             }
         }
diff --git a/src/Map/assets/package.json b/src/Map/assets/package.json
index d35f6d8d..a287b7ef 100644
--- a/src/Map/assets/package.json
+++ b/src/Map/assets/package.json
@@ -3,7 +3,7 @@
     "description": "Easily embed interactive maps in your Symfony application.",
     "private": true,
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux",
         "map",
diff --git a/src/Map/src/Bridge/Google/assets/package.json b/src/Map/src/Bridge/Google/assets/package.json
index 730b81d3..c745b425 100644
--- a/src/Map/src/Bridge/Google/assets/package.json
+++ b/src/Map/src/Bridge/Google/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-google-map",
     "description": "GoogleMaps bridge for Symfony UX Map, integrate interactive maps in your Symfony applications",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux",
         "google-maps",
diff --git a/src/Map/src/Bridge/Leaflet/assets/package.json b/src/Map/src/Bridge/Leaflet/assets/package.json
index 276e40b7..c3b9dbab 100644
--- a/src/Map/src/Bridge/Leaflet/assets/package.json
+++ b/src/Map/src/Bridge/Leaflet/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-leaflet-map",
     "description": "Leaflet bridge for Symfony UX Map, integrate interactive maps in your Symfony applications",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux",
         "leaflet",
diff --git a/src/Notify/assets/package.json b/src/Notify/assets/package.json
index 325e386a..d8d02df2 100644
--- a/src/Notify/assets/package.json
+++ b/src/Notify/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-notify",
     "description": "Native notification integration for Symfony using Mercure",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/React/assets/package.json b/src/React/assets/package.json
index 27d88f24..1cea09ef 100644
--- a/src/React/assets/package.json
+++ b/src/React/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-react",
     "description": "Integration of React in Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/StimulusBundle/assets/package.json b/src/StimulusBundle/assets/package.json
index bd629fbc..b73d679f 100644
--- a/src/StimulusBundle/assets/package.json
+++ b/src/StimulusBundle/assets/package.json
@@ -3,7 +3,7 @@
     "description": "Integration of @hotwired/stimulus into Symfony",
     "private": true,
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/StimulusBundle/src/DependencyInjection/StimulusExtension.php b/src/StimulusBundle/src/DependencyInjection/StimulusExtension.php
index 97a7ec2f..aa0a1060 100644
--- a/src/StimulusBundle/src/DependencyInjection/StimulusExtension.php
+++ b/src/StimulusBundle/src/DependencyInjection/StimulusExtension.php
@@ -43,7 +43,7 @@ final class StimulusExtension extends Extension implements PrependExtensionInter
         }
     }
 
-    public function prepend(ContainerBuilder $container): void
+    public function prepend(ContainerBuilder $container)
     {
         if (!$this->isAssetMapperAvailable($container)) {
             return;
diff --git a/src/Svelte/assets/package.json b/src/Svelte/assets/package.json
index 767871dc..5033c8b7 100644
--- a/src/Svelte/assets/package.json
+++ b/src/Svelte/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-svelte",
     "description": "Integration of Svelte in Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Swup/CHANGELOG.md b/src/Swup/CHANGELOG.md
index 814bd720..fc64ba59 100644
--- a/src/Swup/CHANGELOG.md
+++ b/src/Swup/CHANGELOG.md
@@ -1,6 +1,6 @@
 # CHANGELOG
 
-## 2.26.0
+## 2.27.0
 
 -   Deprecate the package
 
diff --git a/src/Swup/assets/package.json b/src/Swup/assets/package.json
index 15310656..8b2e8260 100644
--- a/src/Swup/assets/package.json
+++ b/src/Swup/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-swup",
     "description": "Swup integration for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/TogglePassword/assets/package.json b/src/TogglePassword/assets/package.json
index 2c79d251..cbe8c1ac 100644
--- a/src/TogglePassword/assets/package.json
+++ b/src/TogglePassword/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-toggle-password",
     "description": "Toggle visibility of password inputs for Symfony Forms",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Translator/assets/package.json b/src/Translator/assets/package.json
index 4c904c12..e338aba7 100644
--- a/src/Translator/assets/package.json
+++ b/src/Translator/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-translator",
     "description": "Symfony Translator for JavaScript",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
index 3ebfbe51..9ba3a029 100644
--- a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
+++ b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
@@ -27,7 +27,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  */
 class UxTranslatorExtension extends Extension implements PrependExtensionInterface
 {
-    public function load(array $configs, ContainerBuilder $container): void
+    public function load(array $configs, ContainerBuilder $container)
     {
         $configuration = new Configuration();
         $config = $this->processConfiguration($configuration, $configs);
@@ -46,7 +46,7 @@ class UxTranslatorExtension extends Extension implements PrependExtensionInterfa
         }
     }
 
-    public function prepend(ContainerBuilder $container): void
+    public function prepend(ContainerBuilder $container)
     {
         if (!$this->isAssetMapperAvailable($container)) {
             return;
diff --git a/src/Turbo/assets/package.json b/src/Turbo/assets/package.json
index 86fae168..dfe8d97a 100644
--- a/src/Turbo/assets/package.json
+++ b/src/Turbo/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-turbo",
     "description": "Hotwire Turbo integration for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux",
         "turbo",
diff --git a/src/Typed/CHANGELOG.md b/src/Typed/CHANGELOG.md
index d373a51a..b12c0133 100644
--- a/src/Typed/CHANGELOG.md
+++ b/src/Typed/CHANGELOG.md
@@ -1,6 +1,6 @@
 # CHANGELOG
 
-## 2.26.0
+## 2.27.0
 
 -   Deprecate the package
 
diff --git a/src/Typed/assets/package.json b/src/Typed/assets/package.json
index 84c795df..4215ba33 100644
--- a/src/Typed/assets/package.json
+++ b/src/Typed/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-typed",
     "description": "Typed integration for Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],
diff --git a/src/Vue/assets/package.json b/src/Vue/assets/package.json
index 6d78394a..cd6a4d74 100644
--- a/src/Vue/assets/package.json
+++ b/src/Vue/assets/package.json
@@ -2,7 +2,7 @@
     "name": "@symfony/ux-vue",
     "description": "Integration of Vue.js in Symfony",
     "license": "MIT",
-    "version": "2.26.1",
+    "version": "2.25.2",
     "keywords": [
         "symfony-ux"
     ],


Test patch:
diff --git a/src/Chartjs/tests/Kernel/TwigAppKernel.php b/src/Chartjs/tests/Kernel/TwigAppKernel.php
index 76de3dbd..5d629bd2 100644
--- a/src/Chartjs/tests/Kernel/TwigAppKernel.php
+++ b/src/Chartjs/tests/Kernel/TwigAppKernel.php
@@ -31,7 +31,7 @@ class TwigAppKernel extends Kernel
         return [new FrameworkBundle(), new TwigBundle(), new StimulusBundle(), new ChartjsBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/Cropperjs/tests/Kernel/EmptyAppKernel.php b/src/Cropperjs/tests/Kernel/EmptyAppKernel.php
index a4a7c89b..71926a98 100644
--- a/src/Cropperjs/tests/Kernel/EmptyAppKernel.php
+++ b/src/Cropperjs/tests/Kernel/EmptyAppKernel.php
@@ -29,7 +29,7 @@ class EmptyAppKernel extends Kernel
         return [new CropperjsBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
     }
 }
diff --git a/src/Cropperjs/tests/Kernel/FrameworkAppKernel.php b/src/Cropperjs/tests/Kernel/FrameworkAppKernel.php
index 63535d3a..1944eace 100644
--- a/src/Cropperjs/tests/Kernel/FrameworkAppKernel.php
+++ b/src/Cropperjs/tests/Kernel/FrameworkAppKernel.php
@@ -31,7 +31,7 @@ class FrameworkAppKernel extends Kernel
         return [new FrameworkBundle(), new CropperjsBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $frameworkConfig = [
diff --git a/src/Cropperjs/tests/Kernel/TwigAppKernel.php b/src/Cropperjs/tests/Kernel/TwigAppKernel.php
index 9b3a9ce8..95cad520 100644
--- a/src/Cropperjs/tests/Kernel/TwigAppKernel.php
+++ b/src/Cropperjs/tests/Kernel/TwigAppKernel.php
@@ -34,7 +34,7 @@ class TwigAppKernel extends Kernel
         return [new FrameworkBundle(), new TwigBundle(), new CropperjsBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $frameworkConfig = [
diff --git a/src/Dropzone/tests/Kernel/EmptyAppKernel.php b/src/Dropzone/tests/Kernel/EmptyAppKernel.php
index e1541b77..f5734e0a 100644
--- a/src/Dropzone/tests/Kernel/EmptyAppKernel.php
+++ b/src/Dropzone/tests/Kernel/EmptyAppKernel.php
@@ -29,7 +29,7 @@ class EmptyAppKernel extends Kernel
         return [new DropzoneBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
     }
 }
diff --git a/src/Dropzone/tests/Kernel/FrameworkAppKernel.php b/src/Dropzone/tests/Kernel/FrameworkAppKernel.php
index 0198c674..4ab07836 100644
--- a/src/Dropzone/tests/Kernel/FrameworkAppKernel.php
+++ b/src/Dropzone/tests/Kernel/FrameworkAppKernel.php
@@ -31,7 +31,7 @@ class FrameworkAppKernel extends Kernel
         return [new FrameworkBundle(), new DropzoneBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true]);
diff --git a/src/Dropzone/tests/Kernel/TwigAppKernel.php b/src/Dropzone/tests/Kernel/TwigAppKernel.php
index 0da830a9..8970425a 100644
--- a/src/Dropzone/tests/Kernel/TwigAppKernel.php
+++ b/src/Dropzone/tests/Kernel/TwigAppKernel.php
@@ -34,7 +34,7 @@ class TwigAppKernel extends Kernel
         return [new FrameworkBundle(), new TwigBundle(), new DropzoneBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/LazyImage/tests/BlurHash/BlurHashTest.php b/src/LazyImage/tests/BlurHash/BlurHashTest.php
index 1304d1bb..60baaf42 100644
--- a/src/LazyImage/tests/BlurHash/BlurHashTest.php
+++ b/src/LazyImage/tests/BlurHash/BlurHashTest.php
@@ -47,7 +47,7 @@ class BlurHashTest extends TestCase
     public function testWithCustomGetImageContent(): void
     {
         $kernel = new class('test', true) extends TwigAppKernel {
-            public function registerContainerConfiguration(LoaderInterface $loader): void
+            public function registerContainerConfiguration(LoaderInterface $loader)
             {
                 parent::registerContainerConfiguration($loader);
 
@@ -99,7 +99,7 @@ class BlurHashTest extends TestCase
     public function testEnsureCacheIsUsedWhenConfigured()
     {
         $kernel = new class('test', true) extends TwigAppKernel {
-            public function registerContainerConfiguration(LoaderInterface $loader): void
+            public function registerContainerConfiguration(LoaderInterface $loader)
             {
                 parent::registerContainerConfiguration($loader);
 
@@ -154,7 +154,7 @@ class BlurHashTest extends TestCase
     public function testCreateDataUriThumbnailWithCache()
     {
         $kernel = new class('test', true) extends TwigAppKernel {
-            public function registerContainerConfiguration(LoaderInterface $loader): void
+            public function registerContainerConfiguration(LoaderInterface $loader)
             {
                 parent::registerContainerConfiguration($loader);
 
diff --git a/src/LazyImage/tests/Kernel/EmptyAppKernel.php b/src/LazyImage/tests/Kernel/EmptyAppKernel.php
index 03394163..4d215d31 100644
--- a/src/LazyImage/tests/Kernel/EmptyAppKernel.php
+++ b/src/LazyImage/tests/Kernel/EmptyAppKernel.php
@@ -29,7 +29,7 @@ class EmptyAppKernel extends Kernel
         return [new LazyImageBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
     }
 }
diff --git a/src/LazyImage/tests/Kernel/FrameworkAppKernel.php b/src/LazyImage/tests/Kernel/FrameworkAppKernel.php
index dac1de81..2dd2e4b7 100644
--- a/src/LazyImage/tests/Kernel/FrameworkAppKernel.php
+++ b/src/LazyImage/tests/Kernel/FrameworkAppKernel.php
@@ -31,7 +31,7 @@ class FrameworkAppKernel extends Kernel
         return [new FrameworkBundle(), new LazyImageBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true]);
diff --git a/src/LazyImage/tests/Kernel/TwigAppKernel.php b/src/LazyImage/tests/Kernel/TwigAppKernel.php
index 51869833..185798d3 100644
--- a/src/LazyImage/tests/Kernel/TwigAppKernel.php
+++ b/src/LazyImage/tests/Kernel/TwigAppKernel.php
@@ -32,7 +32,7 @@ class TwigAppKernel extends Kernel
         return [new FrameworkBundle(), new TwigBundle(), new LazyImageBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/LiveComponent/assets/test/url_utils.test.ts b/src/LiveComponent/assets/test/url_utils.test.ts
index bce7f86b..fcb711f5 100644
--- a/src/LiveComponent/assets/test/url_utils.test.ts
+++ b/src/LiveComponent/assets/test/url_utils.test.ts
@@ -115,32 +115,6 @@ describe('url_utils', () => {
                 expect(urlUtils.search).toEqual('');
             });
         });
-
-        describe('fromQueryString', () => {
-            const urlUtils: UrlUtils = new UrlUtils(window.location.href);
-
-            beforeEach(() => {
-                // Reset search before each test
-                urlUtils.search = '';
-            });
-
-            it('parses a query string with value', () => {
-                urlUtils.search = '?param1=value1';
-                expect(urlUtils.get('param1')).toEqual('value1');
-            });
-
-            it('parses a query string with empty value', () => {
-                urlUtils.search = '?param1=&param2=value2';
-                expect(urlUtils.get('param1')).toEqual('');
-                expect(urlUtils.get('param2')).toEqual('value2');
-            });
-
-            it('parses a query string without equal sign', () => {
-                urlUtils.search = '?param1&param2=value2';
-                expect(urlUtils.get('param1')).toEqual('');
-                expect(urlUtils.get('param2')).toEqual('value2');
-            });
-        });
     });
 
     describe('HistoryStrategy', () => {
diff --git a/src/Notify/tests/Kernel/TwigAppKernel.php b/src/Notify/tests/Kernel/TwigAppKernel.php
index 59910fd3..de278e8f 100644
--- a/src/Notify/tests/Kernel/TwigAppKernel.php
+++ b/src/Notify/tests/Kernel/TwigAppKernel.php
@@ -36,7 +36,7 @@ class TwigAppKernel extends Kernel
         yield new NotifyBundle();
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/React/tests/Kernel/TwigAppKernel.php b/src/React/tests/Kernel/TwigAppKernel.php
index 762c1bcb..cb1027dd 100644
--- a/src/React/tests/Kernel/TwigAppKernel.php
+++ b/src/React/tests/Kernel/TwigAppKernel.php
@@ -31,7 +31,7 @@ class TwigAppKernel extends Kernel
         return [new FrameworkBundle(), new StimulusBundle(), new TwigBundle(), new ReactBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/Svelte/tests/Kernel/TwigAppKernel.php b/src/Svelte/tests/Kernel/TwigAppKernel.php
index 29c82c6f..e61a6386 100644
--- a/src/Svelte/tests/Kernel/TwigAppKernel.php
+++ b/src/Svelte/tests/Kernel/TwigAppKernel.php
@@ -32,7 +32,7 @@ class TwigAppKernel extends Kernel
         return [new StimulusBundle(), new FrameworkBundle(), new TwigBundle(), new SvelteBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);
diff --git a/src/Translator/tests/Kernel/EmptyAppKernel.php b/src/Translator/tests/Kernel/EmptyAppKernel.php
index b92997f6..648443bc 100644
--- a/src/Translator/tests/Kernel/EmptyAppKernel.php
+++ b/src/Translator/tests/Kernel/EmptyAppKernel.php
@@ -29,7 +29,7 @@ class EmptyAppKernel extends Kernel
         return [new UxTranslatorBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
     }
 }
diff --git a/src/Translator/tests/Kernel/FrameworkAppKernel.php b/src/Translator/tests/Kernel/FrameworkAppKernel.php
index 3e61e1ef..98c0ca6a 100644
--- a/src/Translator/tests/Kernel/FrameworkAppKernel.php
+++ b/src/Translator/tests/Kernel/FrameworkAppKernel.php
@@ -31,7 +31,7 @@ class FrameworkAppKernel extends Kernel
         return [new FrameworkBundle(), new UxTranslatorBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', [
diff --git a/src/Vue/tests/Kernel/TwigAppKernel.php b/src/Vue/tests/Kernel/TwigAppKernel.php
index 54a5be3b..5221f7e3 100644
--- a/src/Vue/tests/Kernel/TwigAppKernel.php
+++ b/src/Vue/tests/Kernel/TwigAppKernel.php
@@ -32,7 +32,7 @@ class TwigAppKernel extends Kernel
         return [new StimulusBundle(), new FrameworkBundle(), new TwigBundle(), new VueBundle()];
     }
 
-    public function registerContainerConfiguration(LoaderInterface $loader): void
+    public function registerContainerConfiguration(LoaderInterface $loader)
     {
         $loader->load(function (ContainerBuilder $container) {
             $container->loadFromExtension('framework', ['secret' => '$ecret', 'test' => true, 'http_method_override' => false]);