bigskysoftware / bigskysoftware/htmx
Scripts which depend on other scripts to be loaded first in a HTMLX fragment can cause issue.
- Dominant language
- JavaScript
- Stars
- 49.4k
- Forks
- 1.7k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 30
Description
This is a problem I've been having when using HTMX with Django + Wagtail CMS. Basically one of the forms for Django first uses a `` tag to fetch a library using the `src` attribute. An inline script which is then added afterwards, inits the library.
When opening this page directly it works because the browser will block rendering the page whilst it fetches the script and then executes the code which starts that library. However when fetching this response using HTMX this code breaks because `<script/>` tags no-longer load synchronously and so the inline script tries to call the library before it's ready.
In this case it's not easy to modify this code on the server side so that it waits, the library has no event I can listen to do determine if it's ready and there is no way in HTMX to trigger event when script has loaded (and I'm not ready for Hyperscript).
However with the help of GPT I was able to write a small script which iterates through the nodes HTMX swapped out, finds the script tags and injects them into the browser with the async set to false which forces the behaviour usually experienced when loading the page from scratch.
```
/*
This event listener is added to handle a specific issue when fetching scripts with HTMX.
In some cases, inline scripts may depend on functions defined in other scripts.
However, when these scripts are injected into the DOM via HTMX, they don't get loaded one by one by default.
This can cause issues if an inline script that depends on another script is executed before the other script has loaded.
To solve this issue, we manually control the loading of the scripts.
Scripts with a `src` attribute are loaded first, and their `async` attribute is set to `false` to ensure they are loaded synchronously.
Once a script with a `src` attribute has loaded, the inline scripts are then inserted into the DOM.
This ensures that all functions that the inline scripts depend on are defined before the inline scripts are executed.
*/
document.body.addEventListener('htmx:afterSwap', function(event) {
var scripts = event.detail.elt.querySelectorAll('script');
var inlineScripts = [];
scripts.forEach(function(script) {
var newScript = document.createElement('script');
if (script.src) {
newScript.src = script.src;
newScript.async = false;
newScript.onload = function() {
inlineScripts.forEach(function(inlineScript) {
script.parentNode.insertBefore(inlineScript, script.nextSibling);
});
};
script.parentNode.replaceChild(newScript, script);
} else {
newScript.textContent = script.textContent;
inlineScripts.push(newScript);
}
});
});
```
Any inline scripts are only injected once all remote script have been loaded.
I was wondering if it would either be possible to:
- Make this default/optional behaviour in HTMX either with tag i.e `hx-async-scripts="false" or just setting "async" to false for any script tag returned from server without an explicit "async" or "defer"
- Or make this an official plugin
Contributor guide
Assessment
This issue has not been assessed yet.