Skip to content

Conversation

@SimoTod
Copy link
Contributor

@SimoTod SimoTod commented Dec 9, 2024

When using Alpine.morph (used by Livewire so it's quite a common case for the community) async-alpine re-adds an x-ignore attribute on the component node (which gets picked by the Alpine mutation observer and re-adds the internal _x_ignore property).

This happens because morph reprocesses all Alpine directives on a detached HTML subtree containing the html to morph to and, when everything is reinitialised, instead of replacing the html completely, it only patches nodes/attributes where needed so it doesn't lose hidden metadata (datastacks, internal x* props, html state for input fields, etc) and doesn't trigger the mutation observer when not needed.

Because of the nature of the plugin which is split in sync handler and async handler, x-ignore gets re-added before the morphing but the async handler is delayed by being a promise (even if everything is already downloaded) so the morph script doesn't know it has to wait, patches the live html and adds the attribute.
When the async handler removes x-ignore (on a detached version of the html), it's too late.

Before Alpine 3.14.4, this behaviour wasn't actually noticed because there was a bug in Alpine itself that would allow directives to run even if one of the parent elements had x-ignore but now that it's fixed, this behaviour breaks async-alpine in Livewire so this PR aims at fixing it.

Because the data is already downloaded, there's no need to rerun the directive on every Livewire refresh (the datastack will and should not change) so we use Alpine.skipDuringClone to prevent that. This function is already used by Alpine in a bunch of use cases such as x-data, x-if, x-for to prevent duplicate listeners or duplicate datastacks.

Note, if the original element didn't have x-load and it gets morphed to a component having x-load, it's still working correctly (it will get skipped by morph but picked up by the mutation observer looking for new html attributes so this edge use case is covered as well).

Feel free to Move the tests in a more suitable location if needed, thanks.

Closes #48

@Accudio
Copy link
Owner

Accudio commented Dec 9, 2024

Hey @SimoTod the change looks ideal, thank you for the contribution and fix!

The test isn't quite right for this repo, the HTML should be possible to run completely manually in a browser, playwright is just for automating the human actions and expectations.

This could be easily fixed by adding a button on the page to perform the evaluation on click, and updating the playwright test to trigger that button.
Maybe also a tweak to the description "after morphing (pressing Morph button)" or something like that.

If you're able to make that change fantastic, otherwise I can do so tomorrow when I'm at my desk.

Once we get that sorted I'll merge and release as 2.0.1.

@SimoTod SimoTod force-pushed the bug/x-ignore-readded-after-morphing branch from 1016757 to ade58e9 Compare December 9, 2024 17:29
@SimoTod SimoTod force-pushed the bug/x-ignore-readded-after-morphing branch from ade58e9 to 4c4e252 Compare December 9, 2024 17:31
@SimoTod
Copy link
Contributor Author

SimoTod commented Dec 9, 2024

No worries, i've just update it with the suggested changes.

I use "rebase+force push" a lot so the commits don't end up being a spaghetti mess so if you have already pulled the code locally, run git pull --rebase or it will not allow you to do it.

@Accudio Accudio merged commit 85a7016 into Accudio:main Dec 11, 2024
@Accudio
Copy link
Owner

Accudio commented Dec 11, 2024

This has now been merged and released as version 2.0.1.

Thank you for working this out and filing the issue and PR!

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.

Async-alpine v2.0.0 breaks with Livewire >= v3.5.12 and/or Alpine >= v3.14.4

2 participants