Tetra – Full stack reactive component framework for Django using Alpine.js
tetraframework.com
tetraframework.com
Can you give a quick rundown of when it might make more sense to use Tetra?
Tetra provides the "glue" between Django and Alpine, but also encapsulates your components so all html/css/python/js thats related is next to each other. You wouldn't need to be writing views that return html fragments for htmx.
One of its big features though is that your server rendered views can be reactive, re-rendering on the server and updating in the browser based on user interactions a client side state changes. You have to write less glue code to make everything work with Tetra.
In my tests, HTMX takes about half the time to render vs Unpoly. I assume HTMX is a lot faster than Unpoly because it's only processing fragments versus a full-page diff. How does the rendering speed with HTMX vs. Tetra's stack up if you've done any testing?
Tetra on the other hand is very "component" focused, everything is built up out of nested components. These are rendered on the server and a diff/merge is performed by the Alpine.js Morph plugin to update the dom. So Tetra doesn't re-render the whole page, only the component that changes, therefore it probably sits somewhere between Unpoly and HTMX, but I have done no benchmarking.
Tetra is also tightly linked to Python, each components server state is "frozen" and sent to the browser when it first renders (encrypted and signed). If you then call any public methods on the component the state is sent back to the server and "resumed". This makes the component fully statefull between server public method calls. Neither HTMX or Unpoly have this, you have to manually implement the end points for all updates. Tetra does that all for you.
Compared with HTMX and Unpoly you should be writing less code with Tetra.
That's fascinating, thanks for sharing. I will have to play around with Tetra. Based on your description, it certainly feels like, "Greetings. We are from the future." :-)
My experience with HTMX and Unpoly is limited to building three prototypes (once each in HTMX and Unpoly). Based on that:
* For Unpoly, you mark HTML elements that you want Unpoly to monitor/manipulate. Then some event happens (e.g. the user submits a form, clicks a link, etc.).
* Then Django returns the entire page, just like an old school, web 1.0 app.
* Finally, Unpoly looks at the entire page and finds the elements it's told to monitor/change. Then it swaps those elements in the DOM (if needed), which prevents a page reload.
You should look at Unpoly to see if it sparks any ideas. Its layers feature [0] in particular is really awesome. In the link below, it shows how to (from a high level) use layers to build something pretty complicated like Gmail, while keeping the back end code relatively simple using any SSR framework (Django, Rails, etc.).
I have been calling what Tetra does "close proximity of related concerns", the creator of HTMX called it "locality of behaviour" (https://htmx.org/essays/locality-of-behaviour/).
The original idea with Tetra was to use Python import hooks to create something akin to Vue.js single file components, and I did in fact built an early prototype doing that. However then the idea came to use Python type annotations to enable you to indicate to your editor to syntax highlight inline strings (the Vue.js like single file components would have needed an even more complex editor plugin and setup).
So, it's not going to be to everyone's taste, it it shouldn't be. There are a million ways to build a website, this is just another. However, I believe its good way to do it.
It's worth noting that it's possible to split the html/css/js out into other files if you set your template to '{% extend "template.html" %}', your styles to '@import "styles.css";", and your script to 'export default from "script.js"'.
After years and years of hearing people much more knowledgeable than recommend seperation of concerns and me actually following it, I find this "feature" horrifying.
So my honest question to you, people who used similar frameworks, is this really helpful? How is this not confusing and not a source of undebuggable code?
The gist though (copied from the introduction):
--
Proximity of related concerns is as important as separation of concerns. Whilst it is important to keep your backend logic, front end JavaScript, HTML, and styles separate, it is also incredibly useful to have related code in close proximity.
Front end toolkits such as Vue.js, with its single file components and newer "utility class" based CSS frameworks such as Tailwind, have shown that keeping related aspects of a component in the same file helps to reduce code rot, and to improve the speed at which developers gain an understanding of the component.
--
Really the intention is that you can keep small parts of CSS/JS close to where it is being used. Larger functionality, particularly anything reused, you would still break out into separate files.
The creator of htmx refers to this as "Locality of Behaviour", they wrote a good post on it (https://htmx.org/essays/locality-of-behaviour/)
You should never ever just trust experts or popular advice at face value. You have to test it out.
If you are not doing a large project with many people, you certainly do not need to have files all over the place.
The real question is where are the inherent couplings within a system? In places where they exist, collocation is a very good thing. Separation of concerns is best applied parts of the system with low inherent coupling.
In the case of web UI, the controller logic, document structure (HTML), presentation (CSS), and client-side interaction logic (JS) often have very tight inherent coupling, to the point of needing to relate to each other through shared identifiers (e.g. DOM classes, variables). Collocation generally allows you to scrap boilerplate declarations and work on an entire UI component in one screen of source code, rather than bouncing between tightly coupled files. In my experience, this is a huge productivity boost and aid in understanding code other people wrote.
Thanks for sharing !
As it stands you'll get
TypeError: ToDoItem.save() takes 3 positional arguments but 4 were given
when trying to add a ToDo.I'm not sure it's possible, but it could be great to make this a team project officially supported by Django (like DRF or channels). This would bring trust and support, compared to solo-dev projects that can die instantely if the developer can't support it anymore. Anyway, I'd be glad to sponsor your project on Github.
From this new perspective, here are the tools I'd use in my front-end Django: - Level 0: no dynamic UI needs -> no additional tool (pure HTML/CSS templates) - Level 1: simple dynamic needs -> HTMX + Hyperscript - Level 2: SPA-like needs -> Tetra (instead of Alpine itself)
I may have to play around with this regardless; very cool.
There is a "BasicComponent" that currently has no JS, one idea is expand this with very basic js support (when it mounts on the page your js would receive the element) so that other frameworks can be used with Tetra, probably implemented as extensions.
For react you should take a look at Reactivated[1] though! they are doing interesting things with Django and React.
I've been thinking about building something like Tetra for Flask, but was planning on using HTMX.
HTMX and Alpine take quite different approaches, HTMX is more about calling remote endpoints, returning html fragments and replacing parts of the DOM. It's really nicely done.
Alpine on the other hand is more about decorating your elements with directives and having a "reactive" client side state, very much like a mini Vue.js (it actually uses the reactive core from Vue). It also has a "morph" plugin, which Tetra uses, that rather than replacing the dom with html retuned from the server it makes all the necessary changes to make the existing dom match, keeping all user state (cursers in text boxes etc.). This is a lot like how Vue and React work.
Tetra components are sort of inspired by Vue and so more closely align with the Alpine approach.
You probably know this but for others who might read, HTMX has an alpine plugin which uses morph and persists client side state, including Alpine competent state: https://htmx.org/extensions/alpine-morph/
I also thought HTMX persisted some state on swapped elements, but it's possible that's only the html attributes. Can't seem to find details in the docs at the moment.
The approach is similar to Laravel Livewire, and so it's possible to have the same level of responsiveness.
Keen to get any feedback, I think there is gap in the Django ecosystem that this fills and want to build something thats super useful to the community.
However I do think for the small sort of sprinkling of CSS/JS that is common for components you will find that actually having them embedded within the component file an advantage.