I've been working on a lightweight framework called Ludic that focuses on web development using Python, htmx.org, and a somewhat React-like component approach. It leverages Starlette for performance and the latest Python 3.12 typing features.
I think it is somewhat similar to React, for example, you can create a Link component like you can see in the README.md
Now you can use it in f-strings, and well, other components.
The idea from the beginning was to integrate it with htmx.org, so to me, it feels kind of similar when you are writing endpoints using these "components".
But I understand why you are raising this question, I also didn't know how to name it, and React is a completely different framework. I didn't know how to describe the framework in just a few sentences but wanted to somehow. I might change the description at some point.
I still don't know how useful the framework is, I am playing around with it and I like it. Who knows what other people think, though.
Nice release! This looks good, docs look really nice too. I'd use HTMX anywhere I can to improve a basic HTML site.
One word of warning for people considering HTMX though – it's not a framework, it's an appliance.
In my experience with it, I ran into problems integrating with HTMX very quickly. Drop it into your project, use the HTML attributes, and it'll be great. However if you need custom Javascript, HTMX provides little in the way of an integration path (the lifecycle events are basic), and nothing in the way of structure, and can even get in the way in places where its lifecycle causes issues in the lifecycle of whatever you're adding. To add your own Javascript you'll almost certainly want Jquery or React/Svelte/etc, and with the latter you'll get interactions between their lifecycles.
If you're using it entirely via the HTML API, and you're happy to accept that sometimes it won't do something, you'll be fine. If you're looking to add units of more complex client-side functionality in places, try prototyping with it to make sure it works well, it didn't for me.
I think those are all good points, but do cringe a little at the idea that "to add your own JavaScript you'll want React". Seems like a lot to bring in if you're really just wanting to add some JavaScript.
Ha, fair point. I don't mean so much that for any JS you'd want to bring in React, but more that something like that will likely be needed to manage a codebase of any scale.
My context here is a mostly server-side application using HTMX, where I wanted to add a few small bits of additional client-side code. I tried to do it without any libraries but rapidly realised that Jquery would simplify things a lot, and managed to do ok with that, but was still fighting HTMX throughout, and I ended up with a lot of poorly managed local state quite quickly. It doesn't take much complexity to need some better form of state management, and something like React provides some direction there, but of course there are other options, my point was only really to say that HTMX will not do any of this for you, and may get in the way depending on what you need to do.
React can be added by rendering into a dom node that's not necessarily the root of your app.
Yes, it can be used to render the entire UI app with rich state management across all pages, routing, etc.
However it can just as simply be used to render 1 complex part of an app that has an isolated but possibly complex state. In this scenario I think sprinkling react is reasonable.
True, I can recommend hotwire turbo as an alternate similar to htmx, it has a js framework called Stimulus that integrates nicely for those instances where you need some custom interactivity.
Wish GVR updates pyxl4(used by Mixt) and includes it into Python. It could be used for html, xml, yaml and its config language friends and declarative UIs like React. IMO if and for are better implemented in Jinja or JSX better than Python's ternary and list comprehension. Comparison at bottom.
Most of the frameworks here are calling side effects upon shared objects in the guise of `with` statements. Not to mention the extreme verbosity.
I second this. kotlinx-html is poorly documented and has a couple quirks, but is fantastic. As I've been building one of my current projects, I've also been building a framework based on jooq + kotlinx.html + javalin + htmx + flowbite (+kotlinjs for a few fancy bits, e.g. the charting library). Aside from tailwind, you end up with a fully typed and compiler-checked application end to end, i.e. no magic strings to be seen. I'm exclusively using HX-Retarget, so the backend is in charge of where things land, meaning that the frontend can do things like:
div {
onClick(loadItems)
}
I don't know whether I'll ever actually get it in good enough shape to release, but I do plan to blog about how some of the tricks I've found it fitting it together. One thing I definitely need to do before anybody looks at it is clean up how routes and targets are managed.
Call me traumatized by the Web framework wars, but this seems like the path back to some of the issues that HTMX is trying to solve.
There is a strong developer instinct to "simplify through complexity". That is, to stuff down so much functionality and saw off all edges in an effort to hide complexity. "Let's expose a simple interface that will allow devs to do everything they want to do."
It starts with good intentions and initially provides some improvements in productivity. But it continues to evolve to the point of untenability: the complexity starts to ooze out and become a thing to manage, but with abstractions that make it more difficult; the framework becomes so opinionated that it begins to stifle; performance issues are introduced as we drift farther from the metal.
We continue to try to solve with newer constructs and abstractions, frequently introducing more issues. Eventually, it comes full circle ("hey, let's add SSR!"), and we're again looking for another solution. One that's simpler.
Then the cycle starts over again.
I think there is an inflection point with all of these things, wherein whatever perceived productivity gains are had by pushing more functionality into the framework quietly begins the path to regression. I don't exactly know where it is, but I would bet that it happens far sooner than we suspect.
So, I kind of like HTMX where it is, in spirit and implementation. Whatever additional productivity I can pick up via helper functionality and reuse is something I believe there is value in devs doing on their own, for their individual use cases and preferences. There's a tendency to think "well why reinvent the wheel? Let's make it a framework". I've come to believe that impulse is somewhat pernicious in its effect. Ultimately we're going to have to write our own code at some point. I'd suggest that we're better off doing it much sooner than frameworks encourage.
Spot on, in my opinion we need at least a 10 years ban on the creation of any new web framework of any kind. Hope that AI coders will make frameworks obsolete, but maybe i'm crazy :-).
- Type safe HTML: you get an exception instead of malformed HTML
- Truly reusable components: any Python web framework, component packages are truly reusable in any other projects. I never seen this with template engines.
- Huge productivity boost: not even close! No hunting for templates, no jumping between files, everything is in Python functions.
- Composable elements: you can nest things as much as you want, refactor very easily. Doing this with templates is not even possible, or such a pain I never did it.
- Storybook: There are a couple ones for Django, but they are clunky and not reusable at all.
I felt the same for a long time, but started thinking about a nice API. It took me months, but I finally got it: https://github.com/kissgyorgy/compone
Yes, I quite like the idea of being able to run pyflakes/flake8/black/pytest/mypy over my "html templates", and benefiting from all the power that entails.
It may hurt your eyes at first sight, for sure... But similarly to technologies like Tailwind CSS, it's mostly a matter of getting used to it - and after a while it end ups feeling very natural to use :-)
I imagine a lot of this comes down to personal preference. In the early days of Mountaineer [^1] (gee, almost two months ago at this point), I played around with the idea of embedding html into python instead of needing a JS layer. Eventually my consensus was:
- The most flexible shim approaches typically end up wrapping JS/React components anyway (like Reflex/Pinecone)
- We really need better IDE support for html strings that are within python strings. The editing problem is a big setback.
The ergonomics of Python + JS in separate code files won out and the user experience has been better than forcing them both into a common language would be.
This has the benefit of leveraging whatever the two languages are best at, in native code, so you have access to all the native APIs without having to learn a shim on top of it. Way more longevity to that approach too. Context switching between two languages isn't that bad if you minimize the glue layer that you have to write between them.
I agree and I don't fully understand the why of it.
I remember coding PL/SQL to emmit HTML in Oracle around 1999 or 2000 and using functions to code the various elements.
That got old and repetitive very quickly - for instance, everytime I had to correct a spelling error, I had to recompile the code.
To get around it I used one or two tables to hold html snippets to decouple the business/backend logic from the frontend, and stopped using the PL/SQL functions completely.
My speed of developmet skyrocketed, and separating and abstracting the frontend from the backend made so much sense.
A few years later, I was doing web developemt with Python using the Zope framework (not many people know about it tiday, I think).
It uses a specialised serverside templating language called TAL (Template Attribute Language)[1] that basically builds the front end dynamically, and then you feed it data from the backend.
Very neat and allowed me to build reusable compoments as well as collections of a schema definition (basically a dict), html template(s) and the code to validate that the input matched the schema and could be rendered.
Or something like that - its been 2 employers and almost 20 years since I worked with that :)
I did build a small extension for Wordpress using a PHP implementation[2] of TAL a few years ago, and TAL still works like a charm :)
My point is that I still believe there is value in keeping python out of the html-templating, and in keeping the front end logic apart from the backend logic.
There is something I am not understanding about the renewal of mixing HTML/GUI template with code, but I haven't fully found it yet.
Yeah, I understand that. Now that Python 3.12 has better support for f-strings, I thought there might be a way to make it possible. But I am still not sure it will work. There is a pretty weird hack to make f-strings work while avoiding the possibility of rendering unsafe user input.
It's nice for small hacks, but for anything longer than a couple dozen characters you're probably still better off making jinja2 (or similar) templates as painless as possible.
In general, this usually results in front-end logic being very tightly coupled with back-end logic. In some of the examples given, you even have database access in the same line that is generating the HTML document.
I also started working on a Python Component library, but it's fully independent of any web framework, and you can generate XML/RSS with it too. I'm using it for months now, I will release the first version soon: https://github.com/kissgyorgy/compone
Interested in feedback!
* Docs: https://ludic.readthedocs.io/ * Code: https://github.com/paveldedik/ludic/ * Examples: https://github.com/paveldedik/ludic/tree/main/examples
Now you can use it in f-strings, and well, other components.
The idea from the beginning was to integrate it with htmx.org, so to me, it feels kind of similar when you are writing endpoints using these "components".
But I understand why you are raising this question, I also didn't know how to name it, and React is a completely different framework. I didn't know how to describe the framework in just a few sentences but wanted to somehow. I might change the description at some point.
I still don't know how useful the framework is, I am playing around with it and I like it. Who knows what other people think, though.
// edit - code block don't work here, removed code sample.
One word of warning for people considering HTMX though – it's not a framework, it's an appliance.
In my experience with it, I ran into problems integrating with HTMX very quickly. Drop it into your project, use the HTML attributes, and it'll be great. However if you need custom Javascript, HTMX provides little in the way of an integration path (the lifecycle events are basic), and nothing in the way of structure, and can even get in the way in places where its lifecycle causes issues in the lifecycle of whatever you're adding. To add your own Javascript you'll almost certainly want Jquery or React/Svelte/etc, and with the latter you'll get interactions between their lifecycles.
If you're using it entirely via the HTML API, and you're happy to accept that sometimes it won't do something, you'll be fine. If you're looking to add units of more complex client-side functionality in places, try prototyping with it to make sure it works well, it didn't for me.
My context here is a mostly server-side application using HTMX, where I wanted to add a few small bits of additional client-side code. I tried to do it without any libraries but rapidly realised that Jquery would simplify things a lot, and managed to do ok with that, but was still fighting HTMX throughout, and I ended up with a lot of poorly managed local state quite quickly. It doesn't take much complexity to need some better form of state management, and something like React provides some direction there, but of course there are other options, my point was only really to say that HTMX will not do any of this for you, and may get in the way depending on what you need to do.
Yes, it can be used to render the entire UI app with rich state management across all pages, routing, etc.
However it can just as simply be used to render 1 complex part of an app that has an isolated but possibly complex state. In this scenario I think sprinkling react is reasonable.
If most of your logic is server-side and client JS is kept small, custom elements let you lean on lifecycle events built right into the browser specs.
- <https://github.com/abilian/webbits>
Inspirations for the idea of generating HTML code from Python:
- <https://www.yattag.org/>
- <https://tylerbakke.github.io/MarkupPy/>
- <https://github.com/michaeljones/packed>
- <https://github.com/twidi/mixt/>
- <https://github.com/byteface/domonic>
- <https://pypi.org/project/hyperpython/>
- <https://pypi.org/project/PyHTML/>
- <https://github.com/jviide/htm.py>
- <https://viewdom.readthedocs.io/>
- <https://github.com/pcarbonn/fast_html>
- <https://github.com/sanic-org/html5tagger>
- <https://github.com/j4mie/hotmetal/>
Most of the frameworks here are calling side effects upon shared objects in the guise of `with` statements. Not to mention the extreme verbosity.
> <if cond>
> <long code 1>
> <else>
> <long code 2>
>
> [longcode1() if cond else longcode2()]
>
> <for i in ls>
> <long code 1>
>
>[longcode() for i in ls]
I started using it for some documentation generation purposes. I'm not a web-dev.
Disclaimer: Not my code, just an example I found.
There is a strong developer instinct to "simplify through complexity". That is, to stuff down so much functionality and saw off all edges in an effort to hide complexity. "Let's expose a simple interface that will allow devs to do everything they want to do."
It starts with good intentions and initially provides some improvements in productivity. But it continues to evolve to the point of untenability: the complexity starts to ooze out and become a thing to manage, but with abstractions that make it more difficult; the framework becomes so opinionated that it begins to stifle; performance issues are introduced as we drift farther from the metal.
We continue to try to solve with newer constructs and abstractions, frequently introducing more issues. Eventually, it comes full circle ("hey, let's add SSR!"), and we're again looking for another solution. One that's simpler.
Then the cycle starts over again.
I think there is an inflection point with all of these things, wherein whatever perceived productivity gains are had by pushing more functionality into the framework quietly begins the path to regression. I don't exactly know where it is, but I would bet that it happens far sooner than we suspect.
So, I kind of like HTMX where it is, in spirit and implementation. Whatever additional productivity I can pick up via helper functionality and reuse is something I believe there is value in devs doing on their own, for their individual use cases and preferences. There's a tendency to think "well why reinvent the wheel? Let's make it a framework". I've come to believe that impulse is somewhat pernicious in its effect. Ultimately we're going to have to write our own code at some point. I'd suggest that we're better off doing it much sooner than frameworks encourage.
- Type safe HTML: you get an exception instead of malformed HTML
- Truly reusable components: any Python web framework, component packages are truly reusable in any other projects. I never seen this with template engines.
- Huge productivity boost: not even close! No hunting for templates, no jumping between files, everything is in Python functions.
- Composable elements: you can nest things as much as you want, refactor very easily. Doing this with templates is not even possible, or such a pain I never did it.
- Storybook: There are a couple ones for Django, but they are clunky and not reusable at all.
I felt the same for a long time, but started thinking about a nice API. It took me months, but I finally got it: https://github.com/kissgyorgy/compone
Here is an example of a HTML page layout written with the DOMinate [1] library for example, in a "JSX-like" way:
https://github.com/olivierphi/zakuchess/blob/main/src/apps/w...
It may hurt your eyes at first sight, for sure... But similarly to technologies like Tailwind CSS, it's mostly a matter of getting used to it - and after a while it end ups feeling very natural to use :-)
1: https://github.com/Knio/dominate#readme
- The most flexible shim approaches typically end up wrapping JS/React components anyway (like Reflex/Pinecone)
- We really need better IDE support for html strings that are within python strings. The editing problem is a big setback.
The ergonomics of Python + JS in separate code files won out and the user experience has been better than forcing them both into a common language would be.
This has the benefit of leveraging whatever the two languages are best at, in native code, so you have access to all the native APIs without having to learn a shim on top of it. Way more longevity to that approach too. Context switching between two languages isn't that bad if you minimize the glue layer that you have to write between them.
[^1]: https://github.com/piercefreeman/mountaineer
I remember coding PL/SQL to emmit HTML in Oracle around 1999 or 2000 and using functions to code the various elements.
That got old and repetitive very quickly - for instance, everytime I had to correct a spelling error, I had to recompile the code.
To get around it I used one or two tables to hold html snippets to decouple the business/backend logic from the frontend, and stopped using the PL/SQL functions completely.
My speed of developmet skyrocketed, and separating and abstracting the frontend from the backend made so much sense.
A few years later, I was doing web developemt with Python using the Zope framework (not many people know about it tiday, I think).
It uses a specialised serverside templating language called TAL (Template Attribute Language)[1] that basically builds the front end dynamically, and then you feed it data from the backend.
Very neat and allowed me to build reusable compoments as well as collections of a schema definition (basically a dict), html template(s) and the code to validate that the input matched the schema and could be rendered.
Or something like that - its been 2 employers and almost 20 years since I worked with that :)
I did build a small extension for Wordpress using a PHP implementation[2] of TAL a few years ago, and TAL still works like a charm :)
My point is that I still believe there is value in keeping python out of the html-templating, and in keeping the front end logic apart from the backend logic.
There is something I am not understanding about the renewal of mixing HTML/GUI template with code, but I haven't fully found it yet.
[1] https://en.m.wikipedia.org/wiki/Template_Attribute_Language
[2] I believe it was this one https://phptal.org/
https://github.com/paveldedik/ludic/blob/main/examples/click...
It's the kind of thing that looks very cool and concise in small examples, but tends to become a nightmare when you are working on larger projects.