6 ms·
Tetra – Full stack reactive component framework for Django using Alpine.js
- dagw 4y agoLooks great. Just a heads up that there a bug in the example at https://www.tetraframework.com/docs/introduction https://www.tetraframework.com/docs/introduction As it stands you'll get TypeError: ToDoItem.save() takes 3 positional arguments but 4 were given when trying to add a ToDo.
- samwillis 4y agoThanks, there was an error in the docs, public methods that are watching an attribute should be `def name(self, value, old_value, attr)`. "attr" is the name of the attribute that has changed. Fixed!
- dagw 4y agoWhile I'm suggesting changes, you should probably make it clear that you have to link in bootstrap and font-awesome explicitly in your template to make all the styling work. I initially assumed that it was somehow included in tetra and it took me a second to work out why all the styling was missing.
- samwillis 4y agoOh that’s just for the docs and demo site, no need for bootstrap or font-awesome at all. You can use whatever you want.
- dagw 4y agoYea, I got that. But if someone is just following along the demo in the docs they won't get the results they'll be expecting unless they add bootstrap and font-awesome. It's probably worth mentioning that they should add the relevant imports to the template index.html for the demo.
- bluewalt 4y agoI love these kinds of projects. I hope you'll have the time you need and enough attention/traction to make it work. 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)
- nicogg88 4y agoAs someone who always throw away web side projects when it's time to do frontend, this looks perfect lol Thanks for sharing !
- samwillis 4y agoThanks, I have big plans for it!
- zeusbeard 4y agoReally interesting, are you using it in production now? I would love too just not sure if its stable enough yet?
- samwillis 4y agoNot yet, but soon. I would call it an Alpha right now, but plan to release V1 this summer at which point the API will have stabilised and be well tested.
- zeusbeard 4y agoAh cool, maybe i'll give it a go on a dummy project but it seems really useful. Is there a roadmap for features or timeline?
- samwillis 4y agoBottom of the homepage has a list of what's planed. No specific timeline other than a V1 release this summer. 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.
- ahmedfromtunis 4y ago> It also encapsulates your Python, HTML, JavaScript and CSS into one file. 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?
- samwillis 4y agoI have a blog post in the works to go into depth the thoughts about this. 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/ https://htmx.org/essays/locality-of-behaviour/)
- nisegami 4y agoIf you take a "concern" to be domain-defined rather than architecture-defined, then this approach separates concerns effectively.
- upupandup 4y ago> After years and years of hearing people much more knowledgeable than recommend seperation of concerns 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.
- acjohnson55 4y ago
- marban 4y agoThat 5-line description alone freezes my brain.
- samwillis 4y agoHa, yes, still working out the best way to describe it.
- deathtrader666 4y agoLike the LiveView for Phoenix
- earthboundkid 4y agoSomeone should make a family tree of frameworks. Tetra is the child of LiveWire, is the grandchild of LiveView, is the cousin of …
- WesleyJohnson 4y agoI agree with some of the other early sentiments, this is interesting. We just recently started integrating React into our Django projects. Are there any plans to allow for different JS frameworks, or does the approach tightly couple with Alpine.js? I may have to play around with this regardless; very cool.
- samwillis 4y agoCurrently yes, it is tightly coupled with Alpine.js for the server<->browser coms. However Alpine is so lightweight it's easy to throw in an `x-ignore` [0] and then mount any other framework for a component and still take advantage of the coms and bundling. 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. 0: https://alpinejs.dev/directives/ignore https://alpinejs.dev/directives/ignore 1: https://www.reactivated.io https://www.reactivated.io
- canadiantim 4y agoThis looks incredible. Great choice for using alpine. This matches my stack perfectly, will definitely give it a whirl. I expect I’ll end up using tetra for a long while yet. Congrats and thank you for such a great contribution to the community!
- rsyring 4y agosamwillis: since I see you are here answering questions, any reason you choose Alpine over HTMX? I've been thinking about building something like Tetra for Flask, but was planning on using HTMX.
- samwillis 4y agoFirstly HTMX is awesome, its a really cool project. There is also a Django project implementing helpers for it: https://django-htmx.readthedocs.io/en/latest/ https://django-htmx.readthedocs.io/en/latest/ 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.
- rsyring 4y agoThanks for the detailed reply. It's helpful to understand the difference between the two approaches at a high level. 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/ 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.
- upupandup 4y agoseems a bit slow, like that movie search example. Using normal frontend framework the response is instant as I type. This seems to be half a second delay on each keystroke.
- XzAeRosho 4y agoThe code seems to suggest they have a 200ms throttle between each keystroke, which should explain the delay.
- upupandup 4y agoi makes sense!
- samwillis 4y agoThere is a 200ms debounce on that example, it's also on a tiny DigitalOcean droplet. (I will reduce that debounce) The approach is similar to Laravel Livewire, and so it's possible to have the same level of responsiveness.
- sirsinsalot 4y agoI was hacking together a Django component system (non reactive) and this looks really cool. I love the approach and think Django should come with this kind of thing out of the box in 2022. I'll be using it for sure.
- hkhanna 4y agoLooks cool! My company uses Django & Alpine.js so I will be keeping my eye on this. Would Tetra replace something like HTMX (htmx.org) or would it be used in conjunction with it?
- samwillis 4y agoYes, you wouldn't need HTMX (which is awesome!) with Tetra. The idea is that Tetra is an opinionated framework (with escape hatches), it will come with everything you need.
- IceWreck 4y agoHTML & CSS in Python is ugly. Is there a way to split those from python ?
- samwillis 4y agoYes, you can just set your template to '{% extend "template.html" %}', your styles to '@import "styles.css";", and your script to 'export default from "script.js"'. 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.
- hoistbypetard 4y agoI've been using django/alpine/tailwind/htmx together lately, and I really like it. Can you give a quick rundown of when it might make more sense to use Tetra?
- NoGravitas 4y agoJust curious, why would you use both alpine and htmx? Do you use htmx for simple stuff, and alpine for more complex things?
- dinkleberg 4y agoHtmx isn’t built for interactivity like opening a menu. That is where alpine comes in.
- samwillis 4y agoSo in that stack Tetra would replace htmx (which is an awesome tool!) and takes control of your Alpine components. 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.
- infamia 4y agoThis looks really great! Can you mention some of the differences between Tetra and Unpoly? The full page diff approach Unpoly uses matches my mental model (and follows Django's natural request/response cycle). It sounds like Tetra does something similar? 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?
- 4y ago
- ssalka 4y agoReact may have convinced the community to put HTML in their JavaScript, but I'm extremely reluctant to put JavaScript in my Python.
- samwillis 4y agoI completely understand the hesitation, it appears to be going against 30 years of separation of concerns. However, there is a big difference between the HTML/JS mix in React, there you are using JS as a template language, mixing it with your html. Personally I prefer a domain specific template language (like Django or Vue.js) as it enforces separation of concerns. With Tetra you aren't mixing your js/html/css/python, they are just conveniently located next to each other. It's much closer to the idea of Vue.js single file components, where you have your JS, CSS, and HTML for a component all in the same file. 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/ 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"'.
- sirsinsalot 4y agoI did something similar in Django (ish) where I defined CSS, JS and Django templates in one file using special blocks then pre-processed them into vanilla templates, own JS and CSS. It worked well but was a sketch of what Tetra is doing. I certainly think there's a need for full stack the Django way (tm)
- canadiantim 4y agoHow does graceful degradation work for Tetra? Eg how would a non-js user experience the presentation of tetra components?