This package provides directives for lazy loading JavaScript and CSS assets in Alpine.js projects.
Note: This package is specifically designed for lazy loading css/js assets but does not handle lazy loading of Alpine components. You should use Async Alpine for that. However, it is the perfect companion to use alongside Async Alpine to lazy load all the assets required by your Alpine.js components.
- Lazily load CSS and JS files on-demand.
- Prevent redundant loading of the same asset.
- Saves loaded assets in Alpine global state to avoid reloading them, and to check asset existence.
- Position scripts in head, body-start or body-end.
- Optionally dispatch window events when assets have finished loading.
Laravel Filament users, see end of page.
<script
src="https://unpkg.com/alpine-lazy-load-assets@latest/dist/alpine-lazy-load-assets.cdn.js"
defer
></script>
npm install alpine-lazy-load-assets -D
To add the x-load-css
and x-load-js
directives to your project, register the plugin with Alpine.js.
import Alpine from 'alpinejs';
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets';
Alpine.plugin(AlpineLazyLoadAssets);
window.Alpine = Alpine;
window.Alpine.start();
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets'
document.addEventListener('alpine:init', () => {
window.Alpine.plugin(AlpineLazyLoadAssets)
})
import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets';
Alpine.plugin(AlpineLazyLoadAssets);
Livewire.start();
- The
x-load-js
directive adds a<script>
tag to thehead
orbody
of your document. - The script can be loaded as a module by adding the
data-js-as-module="true"
attribute. - You can also position the script before or after an existing script. You don't have to supply a full path, the script searches for a script tag that contains the given value.
//appended to <head>
<div x-load-js="['/path/to/your/js/file.js']"></div>
//prepended to <body>
<div x-load-js.body-start="['/path/to/your/js/file.js']"></div>
//appended to <body>
<div x-load-js.body-end="['/path/to/your/js/file.js']"></div>
//load as module
<div data-js-as-module="true" x-load-js="['/path/to/your/js/file.js']"></div>
//position before an existing script.
<div data-js-before="app.js" x-load-js="['/path/to/your/js/file.js']"></div>
//position after an existing script.
<div data-js-after="app.js" x-load-js="['/path/to/your/js/file.js']"></div>
- The
x-load-css
directive adds a<link>
tag to the<head>
of your document. - You can add a css link
media
attribute. - Warning: Please note that when the media attribute is added to an element with multiple CSS files, it will be applied to all of them.
- You can also position the link before or after an existing css link. You don't have to supply a full path, the script searches for a css link that contains the given value.
<div x-load-css="['/path/to/your/css/file.css']"></div>
//or with media attribute
<div media="print" x-load-css="['/path/to/your/css/print-file.css']"></div>
//position before an existing css link.
<div data-css-before="app.css" x-load-css="['/path/to/your/css/file.css']"></div>
//position after an existing css link.
<div data-css-after="app.css" x-load-css="['/path/to/your/css/file.css']"></div>
Both directives support an array of files, allowing you to load multiple assets simultaneously.
Example from a Laravel project in combination with Async Alpine:
<div
x-load-js="[
'https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/{{ $locale }}.js'
]"
x-load-css="[
'{{ asset('bundles/AlpineFlatPicker/AlpineFlatPicker.css') }}',
'https://cdn.jsdelivr.net/npm/flatpickr/dist/themes/{{ $theme }}.css'
]"
x-ignore
ax-load="visible"
ax-load-src="{{ asset('bundles/AlpineFlatPicker/AlpineFlatPicker.js') }}"
x-data="AlpineFlatPicker(...)"
>
Define a data-dispatch
attribute with an event name, to the same element as the css or js directives to dispatch a window event when the asset has finished loading.
The script will append -css
or -js
to the event name, depending on which directive is used.
- The event will be dispatched once for each file path
- Beware that the event may be emitted multiple times. If you have multiple elements that pushes the same asset, on the same page.
<div
data-dispatch="foo-loaded"
x-load-js="['/path/to/your/js/foo.js']"
x-load-css="['/path/to/your/css/foo.css']"
></div>
//listen for the event, observe the -css or -js suffix
<div x-on:foo-loaded-css.window="alert('the CSS file was loaded')"></div>
<div x-on:foo-loaded-js.window="alert('the JS file was loaded')"></div>
In a Laravel blade file
<div data-js-before="app.js"
x-load-js="['{{ asset('js/jsoneditor.js') }}']"
data-dispatch="jsoneditor-loaded"
x-on:jsoneditor-loaded-js.window="start"
x-data="{
editor: null,
destroy() {
this.editor = null;
},
start() {
$nextTick(() => {
if(!this.editor && typeof JSONEditor !== 'undefined') {
const options = {}
this.editor = new JSONEditor($refs.editor, options);
}
});
}
}"
>
The loaded assets are saved in lazyLoadedAssets
global state, allowing you to check
if an asset has already been loaded.
//in any Alpine component
$store.lazyLoadedAssets.check('path/foo.js'); //returns boolean
//you can check multiple files at once
$store.lazyLoadedAssets.check(['path/foo.js', 'path/bar.css']);
Example from a Laravel blade file
<div x-on:loaded-map-css.window="console.info($store.lazyLoadedAssets.check('{{ asset('css/foo.css') }}'))"></div>
This package is included from Filament v3.0.0-alpha102. (No need to do anything).
If you are on an earlier version or for other reasons need to add this manually ...
Add the following code to any service provider register()
method.
$this->app->resolving(AssetManager::class, function () {
FilamentAsset::register([
Js::make('alpine-lazy-load-assets', 'https://unpkg.com/alpine-lazy-load-assets@latest/dist/alpine-lazy-load-assets.cdn.js'),
], 'app'); //change 'app' to a unique key suitable for your project
});
Add the following code to any service providers boot()
method.
Filament::registerScripts([
'https://unpkg.com/alpine-lazy-load-assets@latest/dist/alpine-lazy-load-assets.cdn.js',
], true);
Contributions are welcome! If you find a bug, have an enhancement idea, or want to contribute in any other way, please open an issue or submit a pull request.
This project is licensed under the MIT License.