6 ms·
</> Htmx – The Fetch()ening
- gr4vityWall 1y ago> htmx 2.0 (like htmx 1.0 & intercooler.js 1.0) will be supported in perpetuity, so there is absolutely no pressure to upgrade your application: if htmx 2.0 is satisfying your hypermedia needs, you can stick with it This is commendable, specially during times when libraries and programs aren't afraid of breaking changes and API churn.
- ranger_danger 1y agoThe only big gripe I have about htmx is that the hx-on::after-request response it provides to your callback function does not automatically parse JSON content types like with e.g. jQuery.ajax(). Last time I brought that up, people simply questioned why I would ever want to do that in the first place.
- edoceo 1y agoThat sounds like use-case exploration? Did you answer?
- ranger_danger 1y agoOne of the actual responses was "Htmx isn’t designed to work with JSON APIs at all. It needs HTML back from the server." It sounds like they are referring to hx-swap and not arbitrary javascript callbacks though, and in that case, I don't see why calling JSON.parse() inside htmx (when the content-type is json) is that big of a deal.
- johannes1234321 1y agoThey don't want to become a general purpose dynamic web library, but focus on swapping server generated HTML blocks. It's a conscious decision in what they are and what not.
- isleyaardvark 1y agoIt's a pretty core part of their design philosophy, possible the core. https://htmx.org/essays/rest-explained/ https://htmx.org/essays/rest-explained/
- sudodevnull 1y agoSo you can support JSON while still being REST. For example, Datastar supports merging in HTML, JS, JSON into the current view of a resource. They work together to keep the resource state unified versus polling. In general the Datastar way is... 1. make an MPA 2. each page is a resource 3. keep a stream open on the current state of that resource 4. ship, touch grass, repeat
- bananapub 1y ago> One of the actual responses was "Htmx isn’t designed to work with JSON APIs at all. It needs HTML back from the server." Uh, yes? They wrote a literal book about why they think this is important: https://hypermedia.systems/ https://hypermedia.systems/
- recursivedoubts 1y agoin 4.0 we are opening up the entire request/response/swap mechanism so you can replace any component of it per-trigger you can replace the fetch() function used w/ an event callback, etc should allow you to do pretty much anything w/o any hacks
- booi 1y ago> So, eventually & reluctantly, I have changed my mind: there will be another major version of htmx. > However, in order to keep my word that there will not be a htmx 3.0, the next release will instead be htmx 4.0. technically correct.. the best kind of correct
- jraph 1y agoThe author is lucky the phrasing wasn't "there won't be another major version of htmx", or even "a third version".
- scuff3d 1y agoFrom what I know of Carson from his writing and presentations, he probably worded it that way on purpose knowing he'd eventually do a new version, and he didn't want to miss an opportunity to troll everyone a bit.
- SquareWheel 1y agoIt's an amusing solution, but if this ends up being anything like the missing PHP 6, it's also going to cause confusion for users. It might've been better to just mea culpa and release 3.0 anyway. I can't imagine anybody would really hold it against the author.
- johannes1234321 1y agoWhat's the confusion around PHP 6? - There would have been a lot more confusion due to articles, talk slides, even printed books, .. talking about PHP 6's Unicode support would have been truly confusing.
- pavon 1y agoAs long as they commit to making the next version after this htmx 8, I will be content with this versioning scheme.
- recursivedoubts 1y ago
- nchmy 1y agoGreat to see this evolution! Realtime ssr hypermedia is definitely the future. But, my thoughts immediately go to Datastar, which has Fetch, SSE, declarative signals and js expressions, dom morphing, and much more - in a tiny package. I find it to have a more flexible, expressive and standards-compliant API as well. And it'll soon have a simple reactive web components and css framework as well. At this point, why use HTMX when it really seems like (a heavier) Datastar-lite?
- andersmurphy 1y agoThe irony that the Datastar author originally tried to have those features added to HTMX a few years ago.
- nchmy 1y agoBetter late than never. Everyone benefits with HTMX evolving and bringing more attention and capabilities to hypermedia-first approaches.
- arcanemachiner 1y agoBecause Datastar Pro isn't FOSS, and speaking from a purely probabilistic and historical standpoint, your odds of getting rugpulled (in some form or another) might as well be 100%.
- nchmy 1y agoI can appreciate why people would have this perspective - I have been rugpulled a few times recently by thoroughly unscrupulous companies (Augment Code are trash humans). But Datastar is different. The project is literally owned by a 501c3 non-profit. The devs have dayjobs and donate their spare time to this. Funds are for going to conferences or hosting their own And 99% of the features/value that I mentioned is MIT licensed, and the "rugpulled" code is still available to easily port via the plugin API.
- epolanski 1y ago
- amanzi 1y agoThis looks great, although the version 4 alpha doesn't appear to be available at the suggested URL: https://cdn.jsdelivr.net/npm/htmx.org@4.0.0-alpha/dist/htmx.min.js https://cdn.jsdelivr.net/npm/htmx.org@4.0.0-alpha/dist/htmx.... "Couldn't find the requested release version 4.0.0-alpha."
- deepsun 1y ago> hx-target attribute is explicitly declared as inherited on the enclosing div and, if it wasn’t, the button elements would not inherit the target from it. So confusing. I'm pretty sure it should be "inheritable", because "inherited" on an attribute means the attribute is inherited, not the element's children will inherit the attribute. UPDATE: or "inherit", sounds like a command, little less confusing.
- SoftTalker 1y agoI was going to make the same comment. "inherited" is the wrong word. I like "inherit" too. And it's a bit shorter which is always nice. I guess "bequeath" might work also?
- mrj 1y agoMaybe `heritable`?
- recursivedoubts 1y agoyeah, i'm struggling w/it, willing to consider options
- deleted 1y ago[deleted]
- lazypenguin 1y ago> By switching to fetch(), we can take advantage of its support for readable streams, which allow for a stream of content to be swapped into the DOM, rather than a single response. Based on this section, it will be interesting to see how this evolves. I've used HTMX a bunch but after stumbling on Datastar I've come to prefer it. Partially because I don't need something like alpine.js to get some frontend goodies but also because I've come to appreciate the power of SSE streaming morphable targets to the browser
- simonw 1y agoI really enjoyed reading this - very clear technical writing and I learned quite a bit about htmx and their approach to API design generally from it.
- andersmurphy 1y agoLooking forward to porting my demos [1] from Datastar to HTMX once V4 is stable enough. Exciting stuff. Nice to see HTMX innovating again. - [1] https://checkboxes.andersmurphy.com/ https://checkboxes.andersmurphy.com/
- jakubmazanec 1y ago[flagged]
- atomicnumber3 1y agoit's truly wonderful how much can be done and still be better than writing javascript
- blovescoffee 1y agoDo you actually feel like this is better (and not just at par or worse)?
- jabbywocker 1y agoI find it much better for my use cases to use this than to use a JavaScript framework the necessitates the use of a JavaScript server
- scuff3d 1y agoAlmost anything is better than writing JavaScript
- patates 1y agoyes, you write this weird custom syntax that's interpreted in js, without writing any single line of js! well, except when you want to do drag and drop sorting and this other thing. yeah you get to communicate intent with html, but ignoring the security concerns for arguments sake, an inline script tag or your good old onclick event handler can do that too.
- SoftTalker 1y agoDeclarative style is almost always a win, IMO.
- recursivedoubts 1y agothis one is really, truly the last version for sure
- logankeenan 1y agoThis is great! I had to create an xhr-fetch-proxy to use fetch and htmx. This change should open up a lot of fun possibilities. https://github.com/logankeenan/xhr-fetch-proxy https://github.com/logankeenan/xhr-fetch-proxy
- recursivedoubts 1y agoin 4.0 the request cycle is totally open: you can replace the fetch() implementation on a per-request basis learned that trick from fixi.js
- logankeenan 1y agoYep, it's super nice. The Service Workers API also makes this really easy too. I experimented with compiling a Rust Axum server to WASM and then ran it in my service worker. Also, thanks for incorporating fetch into htmx! I thought I'd include an example of replacing fetch for anyone that come across this. const originalFetch = window.fetch; window.fetch = function(url, options) { if (url.includes('/api/user')) { const mockUser = {id: 1, name: 'John Doe', email: 'john@example.com'}; return Promise.resolve(new Response(JSON.stringify(mockUser))); } return originalFetch(url, options); }; https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/fetch_event https://developer.mozilla.org/en-US/docs/Web/API/ServiceWork...
- recursivedoubts 1y agoin htmx 4 you are able to swap it on a per-trigger basis, so need to muck w/the global fetch function: <button hx-get="/foo" hx-on:htmx:config:request="ctx.fetch = myCustomFetch"> Do It </button>
- logankeenan 1y agoOh that’ll be much nicer. Would myCustomFetch then need to return a Response? https://developer.mozilla.org/en-US/docs/Web/API/Response https://developer.mozilla.org/en-US/docs/Web/API/Response
- adamzwasserman 1y agoInteresting timing - I'm building genx.software which leans hard into implicit inheritance for the exact reason he is abandoning it. In my finance app, when the product owner changes their mind about decimal places for the 47th time (and it's always 47), the last thing I want is to hunt down every cell and add :inherited modifiers. We treat everything as integers server-side (because floating point is the devil) and defer all formatting to the client. Implicit cascade means I can change fmt-x="currency:USD:decimals:2" in one place and watch it ripple down the entire table. It's 'maddening' the way CSS is maddening - which is to say, it becomes second nature after you stop fighting it. That said, I fully understand the support ticket burden. Maybe the real lesson is: implicit inheritance is great when you control the domain (like 'format all money the same way'), but terrible when people want to do arbitrary things at arbitrary levels. I will bear that in mind as I complete genx.software
- causal 1y agoNeato. Sensible updates, no loss of support for previous versions? The software dream.
- epolanski 1y agoThe image breaks the website on mobile for me.
- prokopton 1y agohtmx hasn’t had the piss taken out of it enough.
- recursivedoubts 1y ago100%
- fud101 1y agoI was just about to use this for a feature but i won't bother now, it won't pass the stability test. Thanks I guess.
- rtpg 1y agoI feel like people who crave stability pull all the wrong lessons from how to get to stability when doing this sort of "ok we'll make _one_ major version with all the breaking changes we've built up over time". This feels like a repeat of the Python 3.0 strategy, though obviously at a much smaller scale. Some stuff is of course hard to roll out but to me it feels "obvious" that having a 4.0 with the inheritence change (or even better, a 2.1 with a toggle on that change!), then a 5.0 with some other changes, then a 6.0 with other changes... all feels way easier to manage than a 4.0 with all the changes at once. We have version pinning! People who want 2.0 can have 2.0 "forever", so version numbers that go up very high are not actually a problem. Many releases can of course be a bit of a frustration from a release maker's perspective, but given that htmx is the way it is (ain't even getting type checking helping you out on any of this like you would with React!), having the gradual path seems way better. "I think I've handled the 10 changes in between 2.0 and 4.0... but forgot the 11th change" is a constant annoyance with these huge major version bumps. I will once again point to the Django strategy of having breaking changes be rolled out over several releases, including in between releases where "both" models exist. It is a very nice way to do release management when rolling things out, gives good checkpoints for pushing things out, and overall means users are seeing less bugs. Going from `XMLHttpRequest` to `fetch` really might not be a feasable thing to toggle, but a lot of the other stuff in that list feels like it.
- imtringued 1y ago>I feel like people who crave stability pull all the wrong lessons from how to get to stability when doing this sort of "ok we'll make _one_ major version with all the breaking changes we've built up over time". Yeah this is a huge fallacy. If you do a breaking change, you want to do as few breaking changes at once as possible, with as little impact as possible and in the best case scenario you're in contact with every single person that is affected by the breaking change, so that it can be handled without anyone noticing anything other than having to bump a library version, which they were doing anyway since they're running a new Python version in the first place. The dumbest change in python 3 was removing the print statement [0]. Maximum breakage, minimum gain. They could have introduced the new function as println() and deprecated the print statement in Python 3. [0] https://news.ycombinator.com/item?id=13260563 https://news.ycombinator.com/item?id=13260563
- JSR_FDED 1y agoI think the ideas behind HTMX are cool, and Carson’s advocacy around Hypermedia is great. I came from SPA-land and was tired of the fundamental architectural issue of having to keep the front-end and back-end state in sync. I’ve compared Datastar and HTMX and decided on Datastar. There’s overlap between the two libraries in that they both support the request/response model, but with Datastar my learning investment takes me further and opens up new possibilities. In one project I was able to remove a bunch of polling code and simply push a signal from the server to the browser when an external event occurred. The reduction in complexity was crazy. On an internal tool I noticed I didn’t need Alpine.js anymore, and while anytime I can remove a dependency is a good time, the conceptual simplicity is what really makes me happy. Now I’m doing a small app where I decided to make a streaming connection between browser and server and simply regenerate and send the entire view over that connection anytime something changes. Intuitively this felt wasteful but it turned out that with compression this works beautifully. There’s just less code in my app, and the code that’s there is less “fiddly” not having to deal with partial updates of the page. If you’re coming from the world of SPAs, definitely check out both.
- nprateem 1y agoDatastar looks interesting, but their guide on how to redirect a user is a joke. async def redirect_from_backend(): yield SSE.patch_elements('<div id="indicator">Redirecting in 3 seconds...</div>') await asyncio.sleep(3) yield SSE.execute_script('window.location = "/guide"') LOL, they really think it's a good use of server resources to sleep so the client doesn't have to. [1] https://data-star.dev/how_tos/redirect_the_page_from_the_backend https://data-star.dev/how_tos/redirect_the_page_from_the_bac...
- JSR_FDED 1y agoOne of the things I had to wrap my head around was the whole async server style of programming. I learned that doing a sleep on the server consumes essentially zero resources. The thread goes to sleep and wakes up when the timer expires. In the meantime the server can handle other requests unhindered. You can have hundreds or thousands of these threads at the same time - serving requests, waiting for IO, etc. It’s not like synchronous servers e.g. Flask with Gunicorn (in the Python world) where you have a few pre-forked server processes. In that case it would be a waste to prevent one of those processes from serving other requests while sleeping, I agree. Ultimately it’s cool though to be able to control the client from the backend asynchronously, updating signals (think of them as a kind of special front-end variable with superpowers) when something on the backend happens, or updating the client’s DOM, or running scripts.
- huntercaron 1y ago> In 4.0, with the complexity savings we achieved by moving to fetch(), we can now comfortably fit a morphInner and morphOuter swap into core It seems odd to me to treat these as different properties on their own? might as well keep it as an extension if it is not going to be more deeply integrated and let htmx 4.0 be smaller? Possible I may not be understanding the use case though
- masfoobar 1y agoComputer works in binary htmx 1 htmx 2 htmx 4 I look forward to version 8 in 2030. (Meaning there always was a version 3! Just include both htmx1 and htmx2 onto your webpage!)
- rbjorklin 1y agoAny chance we could get a poll on changing the default swap strategy as documented in the quirks page? https://htmx.org/quirks/#the-default-swap-strategy-is-innerhtml https://htmx.org/quirks/#the-default-swap-strategy-is-innerh...
- ksec 1y agoHopefully one day we will see htmx 4.0 being merged into HTML Spec.