Remix.run Logo
JSR_FDED 3 days ago

I 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 3 days ago | parent [-]

Datastar 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_bac...

JSR_FDED 3 days ago | parent | next [-]

One 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.

nprateem 3 days ago | parent | next [-]

To a point, but sleeping before redirecting on the server is insanity. It's pointlessly brittle when the client is perfectly capable of managing its own timer.

This approach completely breaks sensible reasoning about what clients are responsible for. What's next, sending every keystroke to the server so it can tell the client to update a text input?!?

It still takes resources to keep SSEs open, load balance, reopen lost connections, etc. But worst of all is shifting fundamental logic back to the server for literally no benefit.

sudodevnull 2 days ago | parent [-]

It's a toy example, it's suppose to show that you can be doing N things and then redirect. If you have a normal redirect immediately, just do a 307 or whatever.

nasretdinov 2 days ago | parent | prev [-]

Sleeping on the server still consumes resources like memory, open sockets, etc, which may in turn cause some unnecessary CPU usage because of e.g. GC costs, scheduling costs, etc.

gazpachoking 2 days ago | parent | prev [-]

That's a contrived example to show how you can redirect from the backend (and the sleep is to make it easy to see it working.) It isn't a recommendation that you should do it exactly that way.