Replies: 6 comments 14 replies
-
Your first case, 'alpine:init' will not be fired, because it isn't dispatched until Alpine.start() and because alpine script is deferred it will not happen in sequence you describe. Using Alpine global in the callback of any of the alpine lifecycles hooks ('alpine:init', 'alpine:initialized') would be safe. The code in script with defer on it should always execute after script that isn't deferred. The second case, I'd suggest component js code shouldn't be getting injected in your ajax call but should already be registered on page. And if you really have this requirement, you shouldn't use Alpine.data() because the hacks you'd have to do to get it to work would be fragile. If you were just relying on initTree() to be triggered using x-html it wouldn't dispatch another alpine:init and it shouldn't. The reason the component has to be registered before alpine starts parsing page is that you'd have bunch of reference errors as alpine needs your components/stores/utils/etc to be present when it evaluates everything in your x-[whatever] directives. Alpine.data() is just an optional tool in your belt. I choose not to use it when we migrated to V3 for completely different reasons (mostly just dev experience in IDE and already using bundle which exposes library global that hold our component structure). |
Beta Was this translation helpful? Give feedback.
-
I also opened a discussion a few hours ago related to your no 1. I struggle with the exact problem regarding the loading order. #1710 |
Beta Was this translation helpful? Give feedback.
-
I created an HTML file with the following content: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apline load order</title>
</head>
<body>
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<script>
console.log('Load data script');
document.addEventListener('alpine:init', () => {
console.log('alpine:init');
Alpine.data('example', () => ({
a: 'text!',
init() {
console.log('Example loaded');
}
}));
});
</script>
<div x-data="example" x-text="a"></div>
</body>
</html> And I got the following console output:
I believe this works because of the I also noticed that the data function you declared is returning Alpine.data('example', () => {}); It should be: Alpine.data('example', () => ({})); |
Beta Was this translation helpful? Give feedback.
-
I added PR to support it #1721 |
Beta Was this translation helpful? Give feedback.
-
@Niklan I may be missing something but your first example under issue 1 works fine for me. See this, you should see "working" https://codepen.io/joshhanley/pen/rNmeRWw And second issue should be wrapped in Hope this helps! |
Beta Was this translation helpful? Give feedback.
-
@joshhanley If someone doesn't want to go to details of I have a case where my compiled file is already locked with Thanks. |
Beta Was this translation helpful? Give feedback.
-
Alpine 3 introduced the way to register named data components, it's perfect, but it leads to problem with maintaining the code and problems.
I faced at least two downsides, which is not the case for Alpine 2.
№1. JS order is important, but it's reversed
Registering
data
via event is good on paper, but turns out not so good at practice. Especially with other technologies combined.For example:
This won't work, because at this point
alpine:init
event will be fired. So component will never be registered.This way will also fail because Alpine is not defined at this point:
To fix this, we should move our component to load before Alpine:
This makes it mandatory to load the component BEFORE the Alpine.
But this is not good for some system like Drupal. We have a library system which is very clear how frontend dependencies are built. Assets can be standalone or depend on something, and someone can depend on another. So it builds a dependency tree.
For example, I define Alpine library. No problems. Then I define my component library, which depends on Alpine. This makes sense, because it's for Alpine. Drupal figures that out and build dependency tree like:
So my component will be attached to the page after Alpine, because it depends on it. But as said earlier this is not allowed now.
We have the way to make component load before alpine, but it makes dependency tree very complex and confusing and can potentially lead to new problems, because this is not a common case and makes no sense. Why we load the library on which we depend after the one which is using that library?
But registering data after Alpine init seems to be allowed and works! As I see, the main problem that when Alpine detects
x-data="example"
, looking for data with such name, and then when it's not found, it leads to errors. So the real problem is: call to alpine data component should be after that component is registered. But the way it parsed and registered makes JS order important.I see the solution for that. When Alpine detects
x-data
with named value, and it doesn't exist, it stops processing it. But additionally, it needs to track if data withexample
will be registered after that it will be initialized.№2. Components on demand
This problem is very related to first one. For example, we have Alpine on the page but then AJAX loads JS and HTML with new component. It again can't utilize
alpine:init
event, because the Alpine is already on the page and initialized.As I said, we can register
Alpine.data()
after it initialized, so we do it, and it works. But it leads to code like that:Because we don't know, this component is loading after or before Alpine is initialized.
It seems the main problem is we can register named component on demand and Alpine can't handle this if detects that component usage before it registered.
Beta Was this translation helpful? Give feedback.
All reactions