htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Order of `hx-boost` checking and history pushing causes issues with relative links

Open ajusa opened this issue 2 years ago • 5 comments

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.

ajusa avatar Jun 04 '23 04:06 ajusa

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.

ajusa avatar Jun 04 '23 18:06 ajusa

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:

  1. Install asdf
  2. enable elixir/erlang:
asdf plugin add erlang
asdf plugin add elixir
  1. git clone https://github.com/100phlecs/htmx_1476
cd htmx_1476
asdf install
elixir server.exs
  1. Visit localhost:4000
  2. Click go page two, then click to go home page.
  3. Observe the relative links now resolve to localhost:4000/2#a and localhost:4000/2#b

100phlecs avatar Jun 28 '23 18:06 100phlecs

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.

danpalmer avatar Nov 05 '23 15:11 danpalmer

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.

DavidS-ovm avatar Nov 14 '23 13:11 DavidS-ovm

This also seems to cause relatively referenced js and css assets to fail to load on the target page.

bcomnes avatar Nov 20 '23 17:11 bcomnes