Accudio / async-alpine

Async Alpine brings advanced code splitting and lazy-loading to Alpine.js components!
https://async-alpine.dev
Apache License 2.0
152 stars 12 forks source link

Allow registering async components once instead of every instance #7

Closed Accudio closed 1 year ago

Accudio commented 2 years ago

A bit like Alpine.data() allows for registering a component for multiple uses.

Currently if you have an accordion component that sits on each accordion item you will need ax-load-src="https://..." for every instance. We could expose an API like:

AsyncAlpine.data('accordion', 'https://...')

and this would allow components named 'accordion' to omit the ax-load-src attribute.

Accudio commented 2 years ago

Related, request from 'niznet' on Alpine.js discord:

It would be great if we can have a path alias as an option because I'm not quite fond of using full src of a module on every lazy component. Something like,

AsyncAlpine(Alpine, {
  alias: '/dist/components/'
})

<div
  ax-load
  ax-load-src="carousel" `without .js seems good too`
  x-data="carousel(args)"
></div>

Then it's might lead to possibility to combine the ax-load-src & x-data into one with its arguments like ax-load-src="carousel(args)".

Accudio commented 2 years ago

That example doesn't handle the use-case where a tool generates asset URLs, like shopify where we'd need to write:

<div
    ax-load
    ax-load-src="{{ 'carousel.js' | asset_url }}"
    x-data="carousel(args)"
></div>

But perhaps we can have two alternative formats, something like this:

AsyncAlpine(Alpine, {
    dataAlias: '/dist/components/',
    // OR specify each one
    data: {
        carousel: '/dist/components/carousel.js',
        carouselShopify: '{{ 'carousel.js' | asset_url }}'
    }
})
Accudio commented 2 years ago

That last example wouldn't work actually as shopify asset URLs would need to be in .liquid files, not .js.

Needs more thought, I like the alias idea but I wonder if there is way we could simplify the API in a more flexible way, and whether there is a good solution for both the 'alias' implementation and something like Shopify's.

Accudio commented 2 years ago

The solution as mentioned by iniznet in #11, using dynamic imports seems like a good alternative option. We would need to offer a html import option still however. Maybe data() vs urlData()?

Accudio commented 2 years ago

The 0.4-rebuild (#20) adds a new .data() function that allows for dynamic importing of components in addition to the inline syntax. I would like to look at two other options for specifying components in this Issue. As they would be new API additions, we can look at design and implementation of these once 0.4 is released.

.url()

.url() (or similar) would specify the URL for a module to download, and would allow specifying the URL just once instead of having to use ax-load-src on every one. This would actually just be a short alias for the below, but I think is more user-friendly for some users.

// .url()
AsyncAlpine.url('component', 'https://...')
// equivalent
AsyncAlpine.data('component', () => import('https://...'))

.alias()

.alias() (name undecided) would be similar to the suggestion above where you could specify a directory components come from. If an ax-load component hasn't been loaded by .data(), .url() or with an inline URL it could create the by replacing [name] with the component name and fetching the URL.

AsyncAlpine.alias('/components/[name].js')
Accudio commented 1 year ago

These were added to version 0.5.0 with the API as above