Hacker Newsnew | past | comments | ask | show | jobs | submit | volfpeter's commentslogin

Well, the thing is, FastHX, htmy, and holm should be powerful an unopinionated. Think of them like ReactDOM, React, and Next.js.

On the other hand, I already thought about building a component library for htmy. I'd prefer to do it with TailwindCSS and DaisyUI, or I could use for example BasecoatUI https://basecoatui.com/ as a template, because it already offers Jinja-like component snippets.

Now that I have holm as well, I may eventually do it. It's a lot of work though, finding so much spare time is hard.

FastUI is now Reflex. They essentially build a FastAPI + NextJS app combo from your code (maybe they already swapped NextJS for something else). NiceGUI is similar as well.

For my projects, I really want to avoid a big JavaScript companion app, so interactivity will remain HTMX, pure JS where needed, or AlpineJS for example. I'm also thinking about a server-component concept for HTMX with holm, but I don't have a clear plan just yet. I can think about these more now that I have holm.


Thanks for mentioning Basecoat.

Funny enough, I've used a very similar stack (HTMX + FastAPI) for /dev/push [1]. Code is available there: https://github.com/hunvreus/devpush

Planning on checking out holm soon.

[1]: https://devpu.sh


It's a shame you did all the rendering manually :) FastHX would have simplified your life a bit.

devpush seems really interesting! I wasn't aware of it, but I'll check it out! It also looks great (no surprise there, it's Basecoat).

Although I usually go with DaisyUI, Basecoat is a vey good source for ideas and more complex component patterns. This is why I feel translating Basecoat snippets to htmy wouldn't be that much trouble, and I'm seriously considering starting it.


I believe I checked FastHX while building it, but wasn't clear what the main advantage was. Can you help me understand what problems I'd solve with it?


It's just sugar.

It hides the manual template selection, context creation, and rendering logic behind a simple decorator. This way you always write standard FastAPI routes (or you add HTML rendering to existing JSON APIs without changing the route or breaking the existing functionality).

With htmy, it does a bit more, like adding some utilities to the rendering context, adding context processor support, simplify rendering, letting you statically check whether your components receive the correct properties.


With the current renderer (which is super basic because simplicity and features were the main priority over optimization for now), if a component has multiple async children, they will be resolved concurrently. I assume that's what you meant by "parallel". Not sure why that would need an example, but you can simply create a component that calls asyncio.sleep(1), then create a bunch of instances and render them to test it.

I want to have at least the same level of concurrency when the new, better optimized renderer lands.


I did some testing in the meantime. Depending on what you render, it's about an order of magnitude slower currently.

The renderer is as simple/minimal as possible at this point (the focus was on the core feature set I needed until now), so it's performance is as bad as it can be :) There's plenty of room for improvement. I'll work on a few optimizations as I have time, but contributions are more than welcome.


That's a pretty complex question.

Reflex is a great project with a great feature set, it does everything (client rendering, state sync, API) and you can even write your callbacks in Python. It seems like the best option from this family of frameworks (alternative is NiceGUI for example, but having worked quite a bit with that, I probably wouldn't recommend it). Doing everything has some downsides though: there's a ton of "magic" under the hood, the lib is obviously very opinionated (it couldn't exist otherwise) and you may have a hard time if you need something that's not built in to the framework.

htmy is pretty much the opposite, it only does HTML rendering and comes with a set of utilities for advanced uses, e.g. async support, context usage, styled markdown, etc.. With FastHX, you also get a pretty convenient, declarative integration with FastAPI and HTMX. The tool is ergonomic, but you do need to put in more work compared to Reflex (create APIs, use HTMX, maybe AlpineJS or similar client-side tools). In exchange for simplicity (and lack of magic), you get full control over everything: you can convert your business objects to components, use any CSS/UI lib, any backend tooling. Extra benefit is you can migrate to (and from) it relatively easily from tools like Jinja.


I haven't done benchmarking yet. To be fair, I had limited time and I focused on developer comfort and the features I needed for projects I work on. Simplicity and flexibility was another goal: the rendering engine itself is as minimal as possible, but can be replaced or optimized in the future.

I'll probably do a simple comparison with Jinja (using FastAPI) this week. Given that I can put an htmy() method on my business objects (it was an important design consideration, no conflict with other tools), I expect an okay results, but we'll see.


The most important difference is that htmy does not bring its own web framework, you can use it your preferred one (preferably one with async support, but you can always delegate the rendering if you use a sync one).


Funny, I went through the exact same process before I started creating this project :)


I've seen htpy before starting this project. While creative, I'm not too happy with the interface if I'm honest and it feels quite a bit more limited.

There are no magic methods really, you can even write function components. Using dataclasses in examples is also an irrelevant technical details.

The actual reason for requiring an `htmy()` method is that this way you can turn any of your business objects (be it Pydantic or SQLModel classes for example) into components without the fear of a method name conflict with your business stuff. Actually, I expect/planned this to be a very frequent use-case, and then there'll be zero unnecessary nesting.


Ah OK, that makes sense. I hadn't really thought there was much room to do things differently than what htpy does, but I probably just haven't thought about it enough. I'll definitely give this a go as well. I think the idea in general is a good one.


That's a fair point, although my feeling after working quite a bit with Jinja recently is the opposite (primarily for lack of static analysis and IDE support).

You're right, for example the documentation should be improved quite a bit. Keep in mind that this project is pretty new, I simply had no time to add more docs or further improve the existing one.

Ps.: with the Snippet utility and markdown support, you can actually write quite a bit of your HTML in a html files rather than Python. You could even use Jinja templates as the backend for some of your components. This part will see more work as I have spare time to work more on the project.


Components don't really need to fetch anything, they don't need to be smart. It's up to you where data fetching happens. If you look at fasthx for example, you'll see that routes/views normally handle your business logic and fasthx does the rendering (now with Jinja or htmy). With Jinja for example, it can only work like this. With htmy, you have more flexibility (which can be an advantage but of course it can also be misused).

Async components can be handy for example when you need to load files. See the Snippet utility and the markdown support in the lib. https://volfpeter.github.io/htmy/examples/markdown/


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: