Skip to content
LaravelBlog

livewire #10516: Upmerge 3.x into 4.x for release prep

LaravelBlogBot
LaravelBlogBot

Contributed by calebporzio

Part of the livewire v4.4.7 release

PR #10516 is the release-prep upmerge that folds the current 3.x branch into 4.x ahead of the next v4 release. Most of it is branch housekeeping, but two merge decisions matter if you're upgrading from v3.8.10. First, the computed-properties listener-leak fix that shipped on the v3 line now has its regression test ported into v4 — the production fix itself was already equivalent there, so what actually changes in v4 is the safety net, not runtime behavior. Second, the v3 fetch-redirect implementation was deliberately left out, because v4's rewritten request stack supersedes it. The combined merge state was verified with 39 focused PHP tests (71 assertions), 145 passing JS tests (1 skipped), and a clean npm run build.

A release-prep sync, not a feature drop

Upmerges are how Livewire keeps its two active branches aligned: fixes land on 3.x first, then get folded into 4.x before a release is tagged, so both lines carry the same corrections. Most upmerges ferry production code across the merge boundary; this one's production payload was already present in v4 in equivalent form, so the diff that actually lands is a new regression test in src/Features/SupportComputed/UnitTest.php plus its stub component. The upmerge also doubles as a final integration check — running the focused PHP suite, the JS suite, and the build against the combined state confirms that nothing from either branch breaks the other before the release is cut.

What the computed listener-leak test guards against

Computed properties — methods tagged with the #[Computed] attribute — cache their return value so repeated access within a request is cheap. To keep those caches correct across the component lifecycle, Livewire registers listeners on the shared EventBus that reset computed state when a component's lifecycle ends. The v3-era bug: those listeners accumulated. Every mount of a component using computed properties left fresh listeners on the bus without the old ones being removed. In a large test suite that's gradual slowdown; under Laravel Octane, where a single worker process serves many requests, it's a genuine production memory leak. The 3.x fix ensures the listeners are torn down properly. v4 already behaved correctly, but nothing pinned that behavior — this PR ports the test that would fail loudly if a future refactor reintroduced the leak.

Inside the regression test

The test targets exactly the pattern implicated in the original leak: nested computed access, where one computed property reads another.

class ComputedAttributeMemoryLeakStub extends Component
{
    #[Computed]
    public function items(): array
    {
        return ['a', 'b', 'c'];
    }

    #[Computed]
    public function total(): int
    {
        return count($this->items);
    }

    public function render()
    {
        return '<div>{{ $this->total }}</div>';
    }
}

The test resolves app(EventBus::class) and uses reflection to count listeners across the bus's internal registries — listeners, listenersAfter, and listenersBefore. It establishes a baseline after one mount, then mounts the component twenty more times, calling Livewire::flushState() between runs so each iteration mirrors a fresh request:

$baselineListeners = $countListeners();

for ($i = 0; $i < 20; $i++) {
    Livewire::test(ComputedAttributeMemoryLeakStub::class);
    Livewire::flushState();
}

$this->assertEquals($baselineListeners, $countListeners());

Before the 3.x fix, that final assertion failed because the listener count grew on every iteration. After it, the count stays flat no matter how many components mount and tear down.

The fetch-redirect code that stayed on 3.x

Not everything on 3.x crossed the merge. The fetch-redirect implementation added to the v3 fetch layer was intentionally excluded, because v4 replaces that layer with a rewritten request stack — grafting the v3 code on top would fight the new architecture rather than serve it. Practically, this means redirect behavior added in recent v3 patches is not carried over as code; v4 addresses the same concern through its own request stack. If your 3.8.10 app issues redirects during Livewire updates and depends on how the fetch layer handles them, make those redirect flows part of your upgrade smoke test to confirm v4's behavior matches what you expect.

Upgrade impact from 3.8.10

The upgrade impact of this PR is close to zero, and that's the point. There are no public API changes, no new config keys, and no template changes. If you remain on the 3.x line, the listener-leak fix arrives in the 3.x release this merge draws from. If you move to v4, the correct behavior is already in place and is now pinned by the ported test. Memory-conscious deployments — Octane workers, long-running queue processes, beefy CI suites — are the clearest beneficiaries of the underlying fix, since that's where leaked listeners actually hurt. The only real action item is verifying redirect-driven flows after switching to v4, given the deliberately different implementation.

Takeaways

  • This is a release-prep upmerge: it synchronizes 3.x fixes into 4.x before a v4 release, with the combined state validated by 39 PHP tests, 145 JS tests, and a passing build.
  • The only code that lands is a regression test proving components with #[Computed] properties do not accumulate EventBus listeners across mounts.
  • The underlying leak fix already exists (or an equivalent) in v4; the test now guards it against future regressions.
  • If you're on v3 before the fix patch, upgrading stops memory creep in Octane workers and large test suites.
  • The v3 fetch-redirect implementation was omitted by design; v4's rewritten request stack handles redirects, so verify redirect flows when upgrading from 3.8.10.

Sources

More from this release

Related Articles