htmx
htmx copied to clipboard
Order of `hx-boost` checking and history pushing causes issues with relative links
Found this bug after some strange behavior with my application.
I noticed that my hx-boost links weren't actually making a request to the correct URL. These links are relative, so they depend on the current browser location to resolve properly.
I noticed that by the time the function boostElement (https://github.com/bigskysoftware/htmx/blob/6180ad2b25c9b40419ab1d10b124ba67c33c21a8/src/htmx.js#L1319) is called after an HTTP 303 redirect, the value of window.location is still the old location - so the swapping takes place before the location has been updated. Since my URLs are relative, when I click on them HTMX sends a GET request to how they would have resolved with the previous location in the address bar.
It seems like the correct behavior would be to push the URL state as soon as we can, before running any other swapping logic. Unsure if that's a safe change however, as https://github.com/bigskysoftware/htmx/blob/6180ad2b25c9b40419ab1d10b124ba67c33c21a8/src/htmx.js#L3331 seems to be called in doSettle - is there a reason why the URL is updated during settling?
An alternative solution (and probably the easier fix) would be to move the path calculation code in boostElement to when the eventListener is actually fired, rather than doing it the moment everything is swapped in.
Was scanning through the list of PRs and #1451 would fix this issue as a side effect of building the link when it is actually clicked on.
Current workaround is to put hx-boost="false" on the links.
+1 on getting this fixed though. I discovered that when the document byte size is too large, it will prematurely resolve the links. Probably due to the time serialization takes from localStorage.
Here's a reproduction:
- Install asdf
- enable elixir/erlang:
asdf plugin add erlang
asdf plugin add elixir
git clone https://github.com/100phlecs/htmx_1476
cd htmx_1476
asdf install
elixir server.exs
- Visit
localhost:4000 - Click
go page two, then clickto go home page. - Observe the relative links now resolve to
localhost:4000/2#aandlocalhost:4000/2#b
Hey, I just hit this and have a trivial reproduction:
<!-- index.html -->
<html>
<body class="hx-boost">
<a href="sub/page1.html">Go to page</a>
</body>
<html>
<!-- sub/page1.html -->
<html>
<body class="hx-boost">
<img src="img.png">
</body>
<html>
Requires an image at sub/img.png.
Following the boosted link from /index.html will result in a 404 of /img.png, where the request should have been to /sub/img.png.
My assumption is that anything in the content of the navigation target will be swapped in at the wrong time and the browser will make the correct requests based on the order of operations, but not the requests the user is expecting.
Note that this also affects lazy-loading after following a boosted link. e.g. I have <ul hx-get="list" hx-trigger="load"> on /users/ and it correctly loads /users/list when going directly to the page, but tries to load /list when boosting into the page.
This also seems to cause relatively referenced js and css assets to fail to load on the target page.