htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Websocket extension not working when HTMX loaded with "defer"?

Open nerdoc opened this issue 2 years ago • 4 comments

I am struggling with the WS extension on HTMX 1.7.0. Maybe This is not a bug, but I couldn't find any information across the internet, and at least, the the documentation is a bit sparse about extensions usage... When I use the old-style hs-ws="connect:/chatroom/, I get a connection to my Django (4,0)/Channels(3,0,5) setup, but if I change that attr to `hs-ext="ws" ws-connect="/chatroom/" - nothing happens, a connection is never established.

HTMX and the ws extension is loaded correctly (tried with CDN too):

  <script src="{% static 'common/js/htmx/htmx.min.js' %}" defer></script>
  <script src="{% static 'common/js/htmx/ext/ws.js' %}" defer></script>
<div
    hx-ws="connect:/ws/messages/"
{#            hx-ext="ws" ws-connect="/ws/messages/"  #} <!-- does not work! -->
    id="messages-container"
>
  ...
  <div id="message"></div>
</div>

The Extension usage docs say how to use them - as small hint - you should add a link to each Extension at the beginning of the section to this usage section, it's not as easy to find as you think, from a newcomer's perspective, or at least change the line mentioning the extension docs, to point newcomers to the correct place:

In the docs, click on extensions, there is no hint how to install them, just

If you are interested in adding your own extension to htmx, please see the extension docs.

Just change that to

If you are want to know how to install an extension or add your own extension to htmx, please see the extension docs.

That would help find the install section.

But nothing helped bringing the WS extension to life.

nerdoc avatar Jul 05 '22 06:07 nerdoc

Oh, some additional info: The problem is that when you use "defer" in the script tag, the extension does not work. I removed the "defer" attr (from the main htmx.js file) - and the connection worked immediately. How can that be?

nerdoc avatar Jul 11 '22 08:07 nerdoc

The reason is this fragment of code https://github.com/bigskysoftware/htmx/blob/master/src/htmx.js#L3224-L3230

Basically, here is what happens when you load htmx without defer

  1. Browser starts loading the page
  2. Browser loads and executes htmx
  3. htmx sets up DOMContentLoaded handler
  4. Browser loads and executes WS extension
  5. ws extension hooks up to htmx lifecycle events
  6. Browser loads the rest of the page
  7. Handler from step 3 fires and initializes htmx
  8. Lifecycle events are triggered
  9. ws extension is initialized

And here is what happens when script is deferred

  1. Browser starts loading the page
  2. Browser starts loading of htmx script
  3. Browser starts loading of WS extension
  4. Browser loads the rest of the page
  5. Browser executes htmx
  6. htmx initialized immediately
  7. Lifecycle events are triggered, but there are no handlers listening
  8. Browser executes WS extension
  9. ws extension hooks up to htmx lifecycle events, but the events have already been triggered, so it is never initialized (this https://github.com/bigskysoftware/htmx/blob/master/src/ext/ws.js#L40-L65 never runs)

Renerick avatar Aug 18 '22 08:08 Renerick

We were bitten by this bug too. As a temporary measure, we're using the hx-ws attribute instead of the extension.

@Renerick That sounds fairly easy to fix (I haven't worked on JS stuff before, though). Should I give it a shot? My plan would be to simply store a boolean variable (something like htmxWSInitializerExecuted) and if it's true, run the extension's initialization manually instead of hooking up to htmx events.

Maybe this should be done for other extensions as well, though, like the sse one (see #915)

VichoReyes avatar Jun 30 '23 00:06 VichoReyes