alpine-lazy-load-assets
Version:
Alpine.js directive to lazy load css and js assets
210 lines (169 loc) • 7.42 kB
Markdown
# Alpine.js - lazy load assets
This package provides directives for lazy loading JavaScript and CSS assets in [Alpine.js](https://alpinejs.dev/) 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](https://async-alpine.dev/) 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.
## Features
- 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.
## Installation
## CDN
Laravel Filament users, see end of page.
```html
<script
src="https://unpkg.com/alpine-lazy-load-assets@latest/dist/alpine-lazy-load-assets.cdn.js"
defer
></script>
```
## NPM
```bash
npm install alpine-lazy-load-assets -D
```
#### Script Bundle
To add the `x-load-css` and `x-load-js` directives to your project, register the plugin with Alpine.js.
```js
import Alpine from 'alpinejs';
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets';
Alpine.plugin(AlpineLazyLoadAssets);
window.Alpine = Alpine;
window.Alpine.start();
```
#### Script include
```js
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets'
document.addEventListener('alpine:init', () => {
window.Alpine.plugin(AlpineLazyLoadAssets)
})
```
#### Livewire v3
```js
import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
import AlpineLazyLoadAssets from 'alpine-lazy-load-assets';
Alpine.plugin(AlpineLazyLoadAssets);
Livewire.start();
```
# Usage
### x-load-js
* The `x-load-js` directive adds a `<script>` tag to the `head` or `body` 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.
```html
//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>
```
### x-load-css
* 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.
```html
<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>
```
## Multiple files
Both directives support an array of files, allowing you to load multiple assets simultaneously.
Example from a Laravel project in combination with Async Alpine:
```html
<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-load="visible"
x-load-src="{{ asset('bundles/AlpineFlatPicker/AlpineFlatPicker.js') }}"
x-data="AlpineFlatPicker(...)"
>
```
## Window events
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.
```html
<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>
```
### Example handling multiple window events
In a Laravel blade file
```html
<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);
}
});
}
}"
>
```
## Global state, check if assets are loaded
The loaded assets are saved in `lazyLoadedAssets` global state, allowing you to `check` if an asset has already been loaded.
```js
//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
```html
<div x-on:loaded-map-css.window="console.info($store.lazyLoadedAssets.check('{{ asset('css/foo.css') }}'))"></div>
```
## [Laravel Filament](https://filamentphp.com/)
### Filament v3
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.
```php
$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
});
```
### Filament v2
Add the following code to any service providers `boot()` method.
```php
Filament::registerScripts([
'https://unpkg.com/alpine-lazy-load-assets@latest/dist/alpine-lazy-load-assets.cdn.js',
], true);
```
### Contributing
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.
### License
This project is licensed under the MIT License.