fix(deployment): unregister Livewire morph hook on teardown

Store the morph.updated cleanup callback and invoke it during Alpine destroy so deployment log search hooks do not survive component teardown.
This commit is contained in:
Andras Bacsai 2026-05-26 14:57:20 +02:00
parent 7f35a2d98e
commit 0c6a233b27
2 changed files with 12 additions and 4 deletions

View file

@ -13,6 +13,7 @@
scrollDebounce: null,
isScrolling: false,
destroyed: false,
morphUpdatedCleanup: null,
deploymentFinishedCleanup: null,
lastTouchY: 0,
showTimestamps: true,
@ -212,10 +213,8 @@
});
// Apply search after Livewire updates.
// Livewire.hook() has no deregister API, so this callback survives
// wire:navigate. It is made harmless after teardown by the
// `destroyed` guard and by only reacting to DOM inside this root.
Livewire.hook('morph.updated', ({ el }) => {
// Livewire.hook() returns an unregister fn; keep it for destroy().
this.morphUpdatedCleanup = Livewire.hook('morph.updated', ({ el }) => {
if (this.destroyed) return;
if (el.id !== 'logs' || !this.$root.contains(el)) return;
this.$nextTick(() => {
@ -251,6 +250,10 @@
clearTimeout(this.scrollDebounce);
this.scrollDebounce = null;
}
if (typeof this.morphUpdatedCleanup === 'function') {
this.morphUpdatedCleanup();
this.morphUpdatedCleanup = null;
}
if (typeof this.deploymentFinishedCleanup === 'function') {
this.deploymentFinishedCleanup();
this.deploymentFinishedCleanup = null;

View file

@ -94,6 +94,11 @@ function showDeployment(string $status): TestResponse
->not->toContain("document.getElementById('logsContainer')")
// morph.updated hook only acts on this component's own DOM.
->toContain('this.$root.contains(el)')
// Global Livewire hook is unregistered when Alpine tears down.
->toContain('morphUpdatedCleanup: null')
->toContain("this.morphUpdatedCleanup = Livewire.hook('morph.updated'")
->toContain("typeof this.morphUpdatedCleanup === 'function'")
->toContain('this.morphUpdatedCleanup()')
// Continuation timeout is tracked so it can be cancelled.
->toContain('scrollTimeout');
});