Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Livewire component premature registration #1390

Merged
merged 1 commit into from Oct 18, 2023

Conversation

Omranic
Copy link
Contributor

@Omranic Omranic commented Oct 18, 2023

REF: livewire/livewire#7076 (comment)
REF: livewire/livewire#7093

In the latest release of Livewire v3.0.9, Laravel Service Container is utilized for Dependency Resolution, which after testing with a new installation of Jetstream found to have a premature component registration due to a race condition, resulting in Unable to find component: [navigation-menu] exceptions.

Explaination:

  • Previously, mechanisms were created using standard PHP object creation (new $mechanism), not involving Laravel's service container, hence no service container events were triggered. LivewireServiceProvider::registerMechanisms()
  • With the recent change, these mechanisms are now instantiated via Laravel's IoC service container app($mechanism), causing service container events to be triggered.
  • 💡 The core of the problem arises when the Livewire\Mechanisms\CompileLivewireTags mechanism is instantiated. It extends Illuminate\View\Compilers\ComponentTagCompiler which has a constructor dependency of Illuminate\View\Compilers\BladeCompiler , and its creation via the service container triggers events. On the other hand, the JetstreamServiceProvider prematurely listens to this event in the service provider register() method, leading to a situation where Livewire components are being registered before all necessary mechanisms are set up, particularly the Livewire\Mechanisms\ComponentRegistry which comes next in order after Livewire\Mechanisms\CompileLivewireTags.

Suggested fix:

  • Move the registration of Livewire components in JetstreamServiceProvider to the boot() method, which is where it should be. This ensures all mechanisms are in place before any component registration begins. It also makes the additional event handling for BladeCompiler resolution unnecessary. $this->callAfterResolving(BladeCompiler::class, fn () => '');

REF: livewire/livewire#7076 (comment)

In the latest release of Livewire, Laravel Service Container is utilized for Dependency Resolution, which after testing with a new installation of Jetstream found to have a premature component registration due to a race condition.

**Explaination:**
- Previously, mechanisms were created using standard PHP object creation `(new $mechanism)`, not involving Laravel's service container, hence no service container events were triggered. `LivewireServiceProvider::registerMechanisms()`
- With the recent change, these mechanisms are now instantiated via Laravel's IoC service container `app($mechanism)`, causing service container events to be triggered.
- 💡 **The core of the problem** arises when the `Livewire\Mechanisms\CompileLivewireTags` mechanism is instantiated. It extends `Illuminate\View\Compilers\ComponentTagCompiler` which has a constructor dependency of `Illuminate\View\Compilers\BladeCompiler` , and its creation via the service container triggers events. On the other hand, **the `JetstreamServiceProvider` prematurely listens to this event in the service provider `register()` method**, leading to a situation where Livewire components are being registered before all necessary mechanisms are set up, particularly the `Livewire\Mechanisms\ComponentRegistry` which comes next in order after `Livewire\Mechanisms\CompileLivewireTags`.


**Suggested fix:**
- Move the registration of Livewire components in `JetstreamServiceProvider` to the `boot()` method, which is where it should be. This ensures all mechanisms are in place before any component registration begins. It also makes the additional event handling for BladeCompiler resolution unnecessary. `$this->callAfterResolving(BladeCompiler::class, fn () => '');`
@calebporzio
Copy link
Contributor

I reverted the change in Livewire's core (introduced in v3.0.9 and reverted in v3.0.10) to avoid breaking Jetstream. However, if it's no difference, it'd be nice to make this change in Jetstream I suppose so that Livewire can take advantage of the service container for registering its own internals.

@crynobone
Copy link
Member

crynobone commented Oct 18, 2023

Shouldn't Jetstream listen to resolving Livewire's ComponentRegistry instead?

@taylorotwell taylorotwell merged commit 649364c into laravel:4.x Oct 18, 2023
8 checks passed
Omranic added a commit to Omranic/livewire that referenced this pull request Oct 29, 2023
…iceProvider

Livewire Reference: livewire#7076
Jetstream Reference: laravel/jetstream#1390
The required update in `laravel/jetstream` has been merged into core, and tagged in [v4.0.4](https://github.com/laravel/jetstream/releases/tag/v4.0.4)

-----

This pull request updates the LivewireServiceProvider class to utilize Laravel's container for resolving dependencies and instantiating objects, improving modularity and flexibility for app developers. With this change, developers can easily override core Livewire functionalities in their service providers as needed, such as Mechanisms and Features.

These changes have been made with the aim of maintaining backward compatibility and ensuring that there are no side effects or incompatibilities.

-----

Code snippet of the improvement and reasons why it's useful:

```php
namespace App;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(\Livewire\Mechanisms\HandleRequests\HandleRequests::class, \App\HandleRequests::class);
    }
}
```

Example of a `HandleRequests` Mechanism override, changing the mechanism boot logic. This is just an example, but there's many other use cases.
```php
namespace App;

use Livewire\Mechanisms\HandleRequests\HandleRequests as BaseHandleRequests;

class HandleRequests extends BaseHandleRequests
{
    function boot()
    {
        // ...
    }
}

```

Thanks for your consideration! 🙌
calebporzio pushed a commit to livewire/livewire that referenced this pull request Nov 5, 2023
…iceProvider (#7181)

Livewire Reference: #7076
Jetstream Reference: laravel/jetstream#1390
The required update in `laravel/jetstream` has been merged into core, and tagged in [v4.0.4](https://github.com/laravel/jetstream/releases/tag/v4.0.4)

-----

This pull request updates the LivewireServiceProvider class to utilize Laravel's container for resolving dependencies and instantiating objects, improving modularity and flexibility for app developers. With this change, developers can easily override core Livewire functionalities in their service providers as needed, such as Mechanisms and Features.

These changes have been made with the aim of maintaining backward compatibility and ensuring that there are no side effects or incompatibilities.

-----

Code snippet of the improvement and reasons why it's useful:

```php
namespace App;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(\Livewire\Mechanisms\HandleRequests\HandleRequests::class, \App\HandleRequests::class);
    }
}
```

Example of a `HandleRequests` Mechanism override, changing the mechanism boot logic. This is just an example, but there's many other use cases.
```php
namespace App;

use Livewire\Mechanisms\HandleRequests\HandleRequests as BaseHandleRequests;

class HandleRequests extends BaseHandleRequests
{
    function boot()
    {
        // ...
    }
}

```

Thanks for your consideration! 🙌
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants