Skip to content

feat: add asyncDirective - #56

Open
mickaelchanrion wants to merge 1 commit into
Accudio:mainfrom
mickaelchanrion:feature/async-directive
Open

feat: add asyncDirective#56
mickaelchanrion wants to merge 1 commit into
Accudio:mainfrom
mickaelchanrion:feature/async-directive

Conversation

@mickaelchanrion

@mickaelchanrion mickaelchanrion commented Mar 19, 2026

Copy link
Copy Markdown

Adds a wrapper to load directives asynchronously.
See #54

@Accudio

Accudio commented Mar 19, 2026

Copy link
Copy Markdown
Owner

Hi @mickaelchanrion, thank you for this! From a quick look this seems good and I'm keen to review properly, likely in the next week or two.

Appreciate you adding the test also, nice one!

@Accudio

Accudio commented Apr 1, 2026

Copy link
Copy Markdown
Owner

Hey @mickaelchanrion, question about the implementation here.

When we discussed it in the issue, you mentioned the way you currently implement async directives is "simply load them using dynamic imports at the beginning of the directive's callback".

#54 (comment)

Why is it you went for parsing directives on elements within Async Alpine instead of registering a directive using an await import?

@mickaelchanrion

Copy link
Copy Markdown
Author

Hey @Accudio
Yes, that's correct.

I would using dynamic imports to load any deps like this example:

Alpine.directive('foo', async () => {
    // Load deps
    const [{ gsap }, { ScrollTrigger }, { SplitText }] = await Promise.all([
      import('gsap'),
      import('gsap/ScrollTrigger'),
      import('gsap/SplitText'),
    ])

    // Do something...
})

This way, my deps are not included in my main js file. But the directive is.

@Accudio

Accudio commented Apr 6, 2026

Copy link
Copy Markdown
Owner

@mickaelchanrion Yep, understood.

My question is if there's a reason we can't adopt the same method for directives in async alpine instead of needing to parse attributes?

Something like the below,:

Alpine.asyncDirective = (name, download = false) => {
	Alpine.directive(name, async () => {
		const module = await download()
		return module.default
	})
}

(obviously a bit more needed for urls, export hierarchy etc too)

Keep in mind I haven't looked into implementing this so correct me if I'm missing something?

@mickaelchanrion

Copy link
Copy Markdown
Author

@Accudio I'm so sorry but I don't understand what you're asking me. I did what you just mentioned here.
Maybe you could try to directly comment the changes that look odd to you in the "Files changed" tab?

@Accudio

Accudio commented Apr 14, 2026

Copy link
Copy Markdown
Owner

@mickaelchanrion Essentially what I'm getting at is it makes more sense to use Alpine.directive directly within asyncDirective, like you've done with gsap in your previous examples, instead of using the data system like is needed for the components.

The system of storing the component in the data object, and then parsing the element to get the names is required for components because Alpine doesn't support async functions in Alpine.data.
But for directives async functions are absolutely allowed as you make good use of, so it will be faster and much, much less code to rely on that instead of needing to handle storing the component, attribute parsing, and initialising it later.

As I understand it (without testing in-depth however), the code I've written in the comment above (with a few lines for handling URLs and module hierarchy) can replace pretty much all of the additions you've made to src/async-alpine.js.

If that doesn't make sense don't worry, I can look at trying that out and seeing if it works when I get time, and checking it against the tests you put together. I'll hold this PR until we confirm if that's a better solution.

@mickaelchanrion

Copy link
Copy Markdown
Author

@Accudio One of the benefits I see with asyncDirective would be to take advantage of all the strategies from x-load.

<div x-load="visible" x-foo>

So this would mean the directive foo only loads when the element enters the viewport.

Correct me if I'm wrong, but I feel like all async directives would load directly at register time with your approach. Even the unused ones.

@Accudio

Accudio commented Jun 5, 2026

Copy link
Copy Markdown
Owner

I've added some amends to this in PR #58, I'll leave this open until that is merged but expect the conversation and any amends to continue there.

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.

2 participants